Salome HOME
0d8052d19ee042b42b737ad9d0eb794f60740029
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
1 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 //
4 //  This library is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU Lesser General Public
6 //  License as published by the Free Software Foundation; either
7 //  version 2.1 of the License.
8 //
9 //  This library is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 //  Lesser General Public License for more details.
13 //
14 //  You should have received a copy of the GNU Lesser General Public
15 //  License along with this library; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19
20 #include "SMESH_ControlsDef.hxx"
21
22 #include <set>
23
24 #include <BRep_Tool.hxx>
25 #include <gp_Ax3.hxx>
26 #include <gp_Cylinder.hxx>
27 #include <gp_Dir.hxx>
28 #include <gp_Pnt.hxx>
29 #include <gp_Pln.hxx>
30 #include <gp_Vec.hxx>
31 #include <gp_XYZ.hxx>
32 #include <Geom_Plane.hxx>
33 #include <Geom_CylindricalSurface.hxx>
34 #include <Precision.hxx>
35 #include <TColgp_Array1OfXYZ.hxx>
36 #include <TColStd_MapOfInteger.hxx>
37 #include <TColStd_SequenceOfAsciiString.hxx>
38 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
39 #include <TopAbs.hxx>
40 #include <TopoDS.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Shape.hxx>
43
44 #include "SMDS_Mesh.hxx"
45 #include "SMDS_Iterator.hxx"
46 #include "SMDS_MeshElement.hxx"
47 #include "SMDS_MeshNode.hxx"
48 #include "SMDS_VolumeTool.hxx"
49 #include "SMDS_QuadraticFaceOfNodes.hxx"
50 #include "SMDS_QuadraticEdge.hxx"
51
52
53 /*
54                             AUXILIARY METHODS
55 */
56
57 namespace{
58   inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
59   {
60     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
61
62     return v1.Magnitude() < gp::Resolution() ||
63       v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
64   }
65
66   inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
67   {
68     gp_Vec aVec1( P2 - P1 );
69     gp_Vec aVec2( P3 - P1 );
70     return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
71   }
72
73   inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
74   {
75     return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
76   }
77
78
79
80   inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
81   {
82     double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
83     return aDist;
84   }
85
86   int getNbMultiConnection( const SMDS_Mesh* theMesh, const int theId )
87   {
88     if ( theMesh == 0 )
89       return 0;
90
91     const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
92     if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */)
93       return 0;
94
95     // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge)
96     // count elements containing both nodes of the pair.
97     // Note that there may be such cases for a quadratic edge (a horizontal line):
98     //
99     //  Case 1          Case 2
100     //  |     |      |        |      |
101     //  |     |      |        |      |
102     //  +-----+------+  +-----+------+ 
103     //  |            |  |            |
104     //  |            |  |            |
105     // result sould be 2 in both cases
106     //
107     int aResult0 = 0, aResult1 = 0;
108      // last node, it is a medium one in a quadratic edge
109     const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 );
110     const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 );
111     const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 );
112     if ( aNode1 == aLastNode ) aNode1 = 0;
113
114     SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator();
115     while( anElemIter->more() ) {
116       const SMDS_MeshElement* anElem = anElemIter->next();
117       if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
118         SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
119         while ( anIter->more() ) {
120           if ( const SMDS_MeshElement* anElemNode = anIter->next() ) {
121             if ( anElemNode == aNode0 ) {
122               aResult0++;
123               if ( !aNode1 ) break; // not a quadratic edge
124             }
125             else if ( anElemNode == aNode1 )
126               aResult1++;
127           }
128         }
129       }
130     }
131     int aResult = max ( aResult0, aResult1 );
132
133 //     TColStd_MapOfInteger aMap;
134
135 //     SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator();
136 //     if ( anIter != 0 ) {
137 //       while( anIter->more() ) {
138 //      const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
139 //      if ( aNode == 0 )
140 //        return 0;
141 //      SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
142 //      while( anElemIter->more() ) {
143 //        const SMDS_MeshElement* anElem = anElemIter->next();
144 //        if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
145 //          int anId = anElem->GetID();
146
147 //          if ( anIter->more() )              // i.e. first node
148 //            aMap.Add( anId );
149 //          else if ( aMap.Contains( anId ) )
150 //            aResult++;
151 //        }
152 //      }
153 //       }
154 //     }
155
156     return aResult;
157   }
158
159 }
160
161
162
163 using namespace SMESH::Controls;
164
165 /*
166                                 FUNCTORS
167 */
168
169 /*
170   Class       : NumericalFunctor
171   Description : Base class for numerical functors
172 */
173 NumericalFunctor::NumericalFunctor():
174   myMesh(NULL)
175 {
176   myPrecision = -1;
177 }
178
179 void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh )
180 {
181   myMesh = theMesh;
182 }
183
184 bool NumericalFunctor::GetPoints(const int theId,
185                                  TSequenceOfXYZ& theRes ) const
186 {
187   theRes.clear();
188
189   if ( myMesh == 0 )
190     return false;
191
192   return GetPoints( myMesh->FindElement( theId ), theRes );
193 }
194
195 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
196                                  TSequenceOfXYZ&         theRes )
197 {
198   theRes.clear();
199
200   if ( anElem == 0)
201     return false;
202
203   theRes.reserve( anElem->NbNodes() );
204
205   // Get nodes of the element
206   SMDS_ElemIteratorPtr anIter;
207
208   if ( anElem->IsQuadratic() ) {
209     switch ( anElem->GetType() ) {
210     case SMDSAbs_Edge:
211       anIter = static_cast<const SMDS_QuadraticEdge*>
212         (anElem)->interlacedNodesElemIterator();
213       break;
214     case SMDSAbs_Face:
215       anIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
216         (anElem)->interlacedNodesElemIterator();
217       break;
218     default:
219       anIter = anElem->nodesIterator();
220       //return false;
221     }
222   }
223   else {
224     anIter = anElem->nodesIterator();
225   }
226
227   if ( anIter ) {
228     while( anIter->more() ) {
229       if ( const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( anIter->next() ))
230         theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
231     }
232   }
233
234   return true;
235 }
236
237 long  NumericalFunctor::GetPrecision() const
238 {
239   return myPrecision;
240 }
241
242 void  NumericalFunctor::SetPrecision( const long thePrecision )
243 {
244   myPrecision = thePrecision;
245 }
246
247 double NumericalFunctor::GetValue( long theId )
248 {
249   myCurrElement = myMesh->FindElement( theId );
250   TSequenceOfXYZ P;
251   if ( GetPoints( theId, P ))
252   {
253     double aVal = GetValue( P );
254     if ( myPrecision >= 0 )
255     {
256       double prec = pow( 10., (double)( myPrecision ) );
257       aVal = floor( aVal * prec + 0.5 ) / prec;
258     }
259     return aVal;
260   }
261
262   return 0.;
263 }
264
265 //=======================================================================
266 //function : GetValue
267 //purpose  : 
268 //=======================================================================
269
270 double Volume::GetValue( long theElementId )
271 {
272   if ( theElementId && myMesh ) {
273     SMDS_VolumeTool aVolumeTool;
274     if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
275       return aVolumeTool.GetSize();
276   }
277   return 0;
278 }
279
280 //=======================================================================
281 //function : GetBadRate
282 //purpose  : meaningless as it is not quality control functor
283 //=======================================================================
284
285 double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const
286 {
287   return Value;
288 }
289
290 //=======================================================================
291 //function : GetType
292 //purpose  : 
293 //=======================================================================
294
295 SMDSAbs_ElementType Volume::GetType() const
296 {
297   return SMDSAbs_Volume;
298 }
299
300
301 /*
302   Class       : MinimumAngle
303   Description : Functor for calculation of minimum angle
304 */
305
306 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
307 {
308   double aMin;
309
310   if (P.size() <3)
311     return 0.;
312
313   aMin = getAngle(P( P.size() ), P( 1 ), P( 2 ));
314   aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 )));
315
316   for (int i=2; i<P.size();i++){
317       double A0 = getAngle( P( i-1 ), P( i ), P( i+1 ) );
318     aMin = Min(aMin,A0);
319   }
320
321   return aMin * 180.0 / PI;
322 }
323
324 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
325 {
326   //const double aBestAngle = PI / nbNodes;
327   const double aBestAngle = 180.0 - ( 360.0 / double(nbNodes) );
328   return ( fabs( aBestAngle - Value ));
329 }
330
331 SMDSAbs_ElementType MinimumAngle::GetType() const
332 {
333   return SMDSAbs_Face;
334 }
335
336
337 /*
338   Class       : AspectRatio
339   Description : Functor for calculating aspect ratio
340 */
341 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
342 {
343   // According to "Mesh quality control" by Nadir Bouhamau referring to
344   // Pascal Jean Frey and Paul-Louis George. Maillages, applications aux elements finis.
345   // Hermes Science publications, Paris 1999 ISBN 2-7462-0024-4
346   // PAL10872
347
348   int nbNodes = P.size();
349
350   if ( nbNodes < 3 )
351     return 0;
352
353   // Compute aspect ratio
354
355   if ( nbNodes == 3 ) {
356     // Compute lengths of the sides
357     vector< double > aLen (nbNodes);
358     for ( int i = 0; i < nbNodes - 1; i++ )
359       aLen[ i ] = getDistance( P( i + 1 ), P( i + 2 ) );
360     aLen[ nbNodes - 1 ] = getDistance( P( 1 ), P( nbNodes ) );
361     // Q = alfa * h * p / S, where
362     //
363     // alfa = sqrt( 3 ) / 6
364     // h - length of the longest edge
365     // p - half perimeter
366     // S - triangle surface
367     const double alfa = sqrt( 3. ) / 6.;
368     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
369     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
370     double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) );
371     if ( anArea <= Precision::Confusion() )
372       return 0.;
373     return alfa * maxLen * half_perimeter / anArea;
374   }
375   else if ( nbNodes == 6 ) { // quadratic triangles
376     // Compute lengths of the sides
377     vector< double > aLen (3);
378     aLen[0] = getDistance( P(1), P(3) );
379     aLen[1] = getDistance( P(3), P(5) );
380     aLen[2] = getDistance( P(5), P(1) );
381     // Q = alfa * h * p / S, where
382     //
383     // alfa = sqrt( 3 ) / 6
384     // h - length of the longest edge
385     // p - half perimeter
386     // S - triangle surface
387     const double alfa = sqrt( 3. ) / 6.;
388     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
389     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
390     double anArea = getArea( P(1), P(3), P(5) );
391     if ( anArea <= Precision::Confusion() )
392       return 0.;
393     return alfa * maxLen * half_perimeter / anArea;
394   }
395   else if( nbNodes == 4 ) { // quadrangle
396     // return aspect ratio of the worst triange which can be built
397     // taking three nodes of the quadrangle
398     TSequenceOfXYZ triaPnts(3);
399     // triangle on nodes 1 3 2
400     triaPnts(1) = P(1);
401     triaPnts(2) = P(3);
402     triaPnts(3) = P(2);
403     double ar = GetValue( triaPnts );
404     // triangle on nodes 1 3 4
405     triaPnts(3) = P(4);
406     ar = Max ( ar, GetValue( triaPnts ));
407     // triangle on nodes 1 2 4
408     triaPnts(2) = P(2);
409     ar = Max ( ar, GetValue( triaPnts ));
410     // triangle on nodes 3 2 4
411     triaPnts(1) = P(3);
412     ar = Max ( ar, GetValue( triaPnts ));
413
414     return ar;
415   }
416   else { // nbNodes==8 - quadratic quadrangle
417     // return aspect ratio of the worst triange which can be built
418     // taking three nodes of the quadrangle
419     TSequenceOfXYZ triaPnts(3);
420     // triangle on nodes 1 3 2
421     triaPnts(1) = P(1);
422     triaPnts(2) = P(5);
423     triaPnts(3) = P(3);
424     double ar = GetValue( triaPnts );
425     // triangle on nodes 1 3 4
426     triaPnts(3) = P(7);
427     ar = Max ( ar, GetValue( triaPnts ));
428     // triangle on nodes 1 2 4
429     triaPnts(2) = P(3);
430     ar = Max ( ar, GetValue( triaPnts ));
431     // triangle on nodes 3 2 4
432     triaPnts(1) = P(5);
433     ar = Max ( ar, GetValue( triaPnts ));
434
435     return ar;
436   }
437 }
438
439 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
440 {
441   // the aspect ratio is in the range [1.0,infinity]
442   // 1.0 = good
443   // infinity = bad
444   return Value / 1000.;
445 }
446
447 SMDSAbs_ElementType AspectRatio::GetType() const
448 {
449   return SMDSAbs_Face;
450 }
451
452
453 /*
454   Class       : AspectRatio3D
455   Description : Functor for calculating aspect ratio
456 */
457 namespace{
458
459   inline double getHalfPerimeter(double theTria[3]){
460     return (theTria[0] + theTria[1] + theTria[2])/2.0;
461   }
462
463   inline double getArea(double theHalfPerim, double theTria[3]){
464     return sqrt(theHalfPerim*
465                 (theHalfPerim-theTria[0])*
466                 (theHalfPerim-theTria[1])*
467                 (theHalfPerim-theTria[2]));
468   }
469
470   inline double getVolume(double theLen[6]){
471     double a2 = theLen[0]*theLen[0];
472     double b2 = theLen[1]*theLen[1];
473     double c2 = theLen[2]*theLen[2];
474     double d2 = theLen[3]*theLen[3];
475     double e2 = theLen[4]*theLen[4];
476     double f2 = theLen[5]*theLen[5];
477     double P = 4.0*a2*b2*d2;
478     double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
479     double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
480     return sqrt(P-Q+R)/12.0;
481   }
482
483   inline double getVolume2(double theLen[6]){
484     double a2 = theLen[0]*theLen[0];
485     double b2 = theLen[1]*theLen[1];
486     double c2 = theLen[2]*theLen[2];
487     double d2 = theLen[3]*theLen[3];
488     double e2 = theLen[4]*theLen[4];
489     double f2 = theLen[5]*theLen[5];
490
491     double P = a2*e2*(b2+c2+d2+f2-a2-e2);
492     double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
493     double R = c2*d2*(a2+b2+e2+f2-c2-d2);
494     double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
495
496     return sqrt(P+Q+R-S)/12.0;
497   }
498
499   inline double getVolume(const TSequenceOfXYZ& P){
500     gp_Vec aVec1( P( 2 ) - P( 1 ) );
501     gp_Vec aVec2( P( 3 ) - P( 1 ) );
502     gp_Vec aVec3( P( 4 ) - P( 1 ) );
503     gp_Vec anAreaVec( aVec1 ^ aVec2 );
504     return fabs(aVec3 * anAreaVec) / 6.0;
505   }
506
507   inline double getMaxHeight(double theLen[6])
508   {
509     double aHeight = max(theLen[0],theLen[1]);
510     aHeight = max(aHeight,theLen[2]);
511     aHeight = max(aHeight,theLen[3]);
512     aHeight = max(aHeight,theLen[4]);
513     aHeight = max(aHeight,theLen[5]);
514     return aHeight;
515   }
516
517 }
518
519 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
520 {
521   double aQuality = 0.0;
522   if(myCurrElement->IsPoly()) return aQuality;
523
524   int nbNodes = P.size();
525
526   if(myCurrElement->IsQuadratic()) {
527     if(nbNodes==10) nbNodes=4; // quadratic tetrahedron
528     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
529     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
530     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
531     else return aQuality;
532   }
533
534   switch(nbNodes){
535   case 4:{
536     double aLen[6] = {
537       getDistance(P( 1 ),P( 2 )), // a
538       getDistance(P( 2 ),P( 3 )), // b
539       getDistance(P( 3 ),P( 1 )), // c
540       getDistance(P( 2 ),P( 4 )), // d
541       getDistance(P( 3 ),P( 4 )), // e
542       getDistance(P( 1 ),P( 4 ))  // f
543     };
544     double aTria[4][3] = {
545       {aLen[0],aLen[1],aLen[2]}, // abc
546       {aLen[0],aLen[3],aLen[5]}, // adf
547       {aLen[1],aLen[3],aLen[4]}, // bde
548       {aLen[2],aLen[4],aLen[5]}  // cef
549     };
550     double aSumArea = 0.0;
551     double aHalfPerimeter = getHalfPerimeter(aTria[0]);
552     double anArea = getArea(aHalfPerimeter,aTria[0]);
553     aSumArea += anArea;
554     aHalfPerimeter = getHalfPerimeter(aTria[1]);
555     anArea = getArea(aHalfPerimeter,aTria[1]);
556     aSumArea += anArea;
557     aHalfPerimeter = getHalfPerimeter(aTria[2]);
558     anArea = getArea(aHalfPerimeter,aTria[2]);
559     aSumArea += anArea;
560     aHalfPerimeter = getHalfPerimeter(aTria[3]);
561     anArea = getArea(aHalfPerimeter,aTria[3]);
562     aSumArea += anArea;
563     double aVolume = getVolume(P);
564     //double aVolume = getVolume(aLen);
565     double aHeight = getMaxHeight(aLen);
566     static double aCoeff = sqrt(2.0)/12.0;
567     aQuality = aCoeff*aHeight*aSumArea/aVolume;
568     break;
569   }
570   case 5:{
571     {
572       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
573       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
574     }
575     {
576       gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
577       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
578     }
579     {
580       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
581       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
582     }
583     {
584       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
585       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
586     }
587     break;
588   }
589   case 6:{
590     {
591       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
592       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
593     }
594     {
595       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
596       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
597     }
598     {
599       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
600       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
601     }
602     {
603       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
604       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
605     }
606     {
607       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
608       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
609     }
610     {
611       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
612       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
613     }
614     break;
615   }
616   case 8:{
617     {
618       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
619       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
620     }
621     {
622       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
623       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
624     }
625     {
626       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
627       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
628     }
629     {
630       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
631       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
632     }
633     {
634       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
635       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
636     }
637     {
638       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
639       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
640     }
641     {
642       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
643       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
644     }
645     {
646       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
647       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
648     }
649     {
650       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
651       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
652     }
653     {
654       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
655       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
656     }
657     {
658       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
659       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
660     }
661     {
662       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
663       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
664     }
665     {
666       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
667       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
668     }
669     {
670       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
671       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
672     }
673     {
674       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
675       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
676     }
677     {
678       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
679       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
680     }
681     {
682       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
683       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
684     }
685     {
686       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
687       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
688     }
689     {
690       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
691       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
692     }
693     {
694       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
695       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
696     }
697     {
698       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
699       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
700     }
701     {
702       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
703       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
704     }
705     {
706       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
707       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
708     }
709     {
710       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
711       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
712     }
713     {
714       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
715       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
716     }
717     {
718       gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
719       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
720     }
721     {
722       gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
723       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
724     }
725     {
726       gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
727       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
728     }
729     {
730       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
731       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
732     }
733     {
734       gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
735       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
736     }
737     {
738       gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
739       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
740     }
741     {
742       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
743       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
744     }
745     {
746       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
747       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
748     }
749     break;
750   }
751   }
752   if ( nbNodes > 4 ) {
753     // avaluate aspect ratio of quadranle faces
754     AspectRatio aspect2D;
755     SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes );
756     int nbFaces = SMDS_VolumeTool::NbFaces( type );
757     TSequenceOfXYZ points(4);
758     for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume
759       if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 )
760         continue;
761       const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true );
762       for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadranle face
763         points( p + 1 ) = P( pInd[ p ] + 1 );
764       aQuality = max( aQuality, aspect2D.GetValue( points ));
765     }
766   }
767   return aQuality;
768 }
769
770 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
771 {
772   // the aspect ratio is in the range [1.0,infinity]
773   // 1.0 = good
774   // infinity = bad
775   return Value / 1000.;
776 }
777
778 SMDSAbs_ElementType AspectRatio3D::GetType() const
779 {
780   return SMDSAbs_Volume;
781 }
782
783
784 /*
785   Class       : Warping
786   Description : Functor for calculating warping
787 */
788 double Warping::GetValue( const TSequenceOfXYZ& P )
789 {
790   if ( P.size() != 4 )
791     return 0;
792
793   gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4.;
794
795   double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G );
796   double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G );
797   double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G );
798   double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G );
799
800   return Max( Max( A1, A2 ), Max( A3, A4 ) );
801 }
802
803 double Warping::ComputeA( const gp_XYZ& thePnt1,
804                           const gp_XYZ& thePnt2,
805                           const gp_XYZ& thePnt3,
806                           const gp_XYZ& theG ) const
807 {
808   double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
809   double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
810   double L = Min( aLen1, aLen2 ) * 0.5;
811   if ( L < Precision::Confusion())
812     return 0.;
813
814   gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG;
815   gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG;
816   gp_XYZ N  = GI.Crossed( GJ );
817
818   if ( N.Modulus() < gp::Resolution() )
819     return PI / 2;
820
821   N.Normalize();
822
823   double H = ( thePnt2 - theG ).Dot( N );
824   return asin( fabs( H / L ) ) * 180. / PI;
825 }
826
827 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
828 {
829   // the warp is in the range [0.0,PI/2]
830   // 0.0 = good (no warp)
831   // PI/2 = bad  (face pliee)
832   return Value;
833 }
834
835 SMDSAbs_ElementType Warping::GetType() const
836 {
837   return SMDSAbs_Face;
838 }
839
840
841 /*
842   Class       : Taper
843   Description : Functor for calculating taper
844 */
845 double Taper::GetValue( const TSequenceOfXYZ& P )
846 {
847   if ( P.size() != 4 )
848     return 0.;
849
850   // Compute taper
851   double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ) / 2.;
852   double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ) / 2.;
853   double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ) / 2.;
854   double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ) / 2.;
855
856   double JA = 0.25 * ( J1 + J2 + J3 + J4 );
857   if ( JA <= Precision::Confusion() )
858     return 0.;
859
860   double T1 = fabs( ( J1 - JA ) / JA );
861   double T2 = fabs( ( J2 - JA ) / JA );
862   double T3 = fabs( ( J3 - JA ) / JA );
863   double T4 = fabs( ( J4 - JA ) / JA );
864
865   return Max( Max( T1, T2 ), Max( T3, T4 ) );
866 }
867
868 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
869 {
870   // the taper is in the range [0.0,1.0]
871   // 0.0  = good (no taper)
872   // 1.0 = bad  (les cotes opposes sont allignes)
873   return Value;
874 }
875
876 SMDSAbs_ElementType Taper::GetType() const
877 {
878   return SMDSAbs_Face;
879 }
880
881
882 /*
883   Class       : Skew
884   Description : Functor for calculating skew in degrees
885 */
886 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
887 {
888   gp_XYZ p12 = ( p2 + p1 ) / 2.;
889   gp_XYZ p23 = ( p3 + p2 ) / 2.;
890   gp_XYZ p31 = ( p3 + p1 ) / 2.;
891
892   gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
893
894   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
895 }
896
897 double Skew::GetValue( const TSequenceOfXYZ& P )
898 {
899   if ( P.size() != 3 && P.size() != 4 )
900     return 0.;
901
902   // Compute skew
903   static double PI2 = PI / 2.;
904   if ( P.size() == 3 )
905   {
906     double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
907     double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
908     double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
909
910     return Max( A0, Max( A1, A2 ) ) * 180. / PI;
911   }
912   else
913   {
914     gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2.;
915     gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2.;
916     gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2.;
917     gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2.;
918
919     gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
920     double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
921       ? 0. : fabs( PI2 - v1.Angle( v2 ) );
922
923     //BUG SWP12743
924     if ( A < Precision::Angular() )
925       return 0.;
926
927     return A * 180. / PI;
928   }
929 }
930
931 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
932 {
933   // the skew is in the range [0.0,PI/2].
934   // 0.0 = good
935   // PI/2 = bad
936   return Value;
937 }
938
939 SMDSAbs_ElementType Skew::GetType() const
940 {
941   return SMDSAbs_Face;
942 }
943
944
945 /*
946   Class       : Area
947   Description : Functor for calculating area
948 */
949 double Area::GetValue( const TSequenceOfXYZ& P )
950 {
951   gp_Vec aVec1( P(2) - P(1) );
952   gp_Vec aVec2( P(3) - P(1) );
953   gp_Vec SumVec = aVec1 ^ aVec2;
954   for (int i=4; i<=P.size(); i++) {
955     gp_Vec aVec1( P(i-1) - P(1) );
956     gp_Vec aVec2( P(i) - P(1) );
957     gp_Vec tmp = aVec1 ^ aVec2;
958     SumVec.Add(tmp);
959   }
960   return SumVec.Magnitude() * 0.5;
961 }
962
963 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
964 {
965   // meaningless as it is not a quality control functor
966   return Value;
967 }
968
969 SMDSAbs_ElementType Area::GetType() const
970 {
971   return SMDSAbs_Face;
972 }
973
974
975 /*
976   Class       : Length
977   Description : Functor for calculating length off edge
978 */
979 double Length::GetValue( const TSequenceOfXYZ& P )
980 {
981   switch ( P.size() ) {
982   case 2:  return getDistance( P( 1 ), P( 2 ) );
983   case 3:  return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) );
984   default: return 0.;
985   }
986 }
987
988 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
989 {
990   // meaningless as it is not quality control functor
991   return Value;
992 }
993
994 SMDSAbs_ElementType Length::GetType() const
995 {
996   return SMDSAbs_Edge;
997 }
998
999 /*
1000   Class       : Length2D
1001   Description : Functor for calculating length of edge
1002 */
1003
1004 double Length2D::GetValue( long theElementId)
1005 {
1006   TSequenceOfXYZ P;
1007
1008   //cout<<"Length2D::GetValue"<<endl;
1009   if (GetPoints(theElementId,P)){
1010     //for(int jj=1; jj<=P.size(); jj++)
1011     //  cout<<"jj="<<jj<<" P("<<P(jj).X()<<","<<P(jj).Y()<<","<<P(jj).Z()<<")"<<endl;
1012
1013     double  aVal;// = GetValue( P );
1014     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
1015     SMDSAbs_ElementType aType = aElem->GetType();
1016
1017     int len = P.size();
1018
1019     switch (aType){
1020     case SMDSAbs_All:
1021     case SMDSAbs_Node:
1022     case SMDSAbs_Edge:
1023       if (len == 2){
1024         aVal = getDistance( P( 1 ), P( 2 ) );
1025         break;
1026       }
1027       else if (len == 3){ // quadratic edge
1028         aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
1029         break;
1030       }
1031     case SMDSAbs_Face:
1032       if (len == 3){ // triangles
1033         double L1 = getDistance(P( 1 ),P( 2 ));
1034         double L2 = getDistance(P( 2 ),P( 3 ));
1035         double L3 = getDistance(P( 3 ),P( 1 ));
1036         aVal = Max(L1,Max(L2,L3));
1037         break;
1038       }
1039       else if (len == 4){ // quadrangles
1040         double L1 = getDistance(P( 1 ),P( 2 ));
1041         double L2 = getDistance(P( 2 ),P( 3 ));
1042         double L3 = getDistance(P( 3 ),P( 4 ));
1043         double L4 = getDistance(P( 4 ),P( 1 ));
1044         aVal = Max(Max(L1,L2),Max(L3,L4));
1045         break;
1046       }
1047       if (len == 6){ // quadratic triangles
1048         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1049         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1050         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
1051         aVal = Max(L1,Max(L2,L3));
1052         //cout<<"L1="<<L1<<" L2="<<L2<<"L3="<<L3<<" aVal="<<aVal<<endl;
1053         break;
1054       }
1055       else if (len == 8){ // quadratic quadrangles
1056         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1057         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1058         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
1059         double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
1060         aVal = Max(Max(L1,L2),Max(L3,L4));
1061         break;
1062       }
1063     case SMDSAbs_Volume:
1064       if (len == 4){ // tetraidrs
1065         double L1 = getDistance(P( 1 ),P( 2 ));
1066         double L2 = getDistance(P( 2 ),P( 3 ));
1067         double L3 = getDistance(P( 3 ),P( 1 ));
1068         double L4 = getDistance(P( 1 ),P( 4 ));
1069         double L5 = getDistance(P( 2 ),P( 4 ));
1070         double L6 = getDistance(P( 3 ),P( 4 ));
1071         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1072         break;
1073       }
1074       else if (len == 5){ // piramids
1075         double L1 = getDistance(P( 1 ),P( 2 ));
1076         double L2 = getDistance(P( 2 ),P( 3 ));
1077         double L3 = getDistance(P( 3 ),P( 1 ));
1078         double L4 = getDistance(P( 4 ),P( 1 ));
1079         double L5 = getDistance(P( 1 ),P( 5 ));
1080         double L6 = getDistance(P( 2 ),P( 5 ));
1081         double L7 = getDistance(P( 3 ),P( 5 ));
1082         double L8 = getDistance(P( 4 ),P( 5 ));
1083
1084         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1085         aVal = Max(aVal,Max(L7,L8));
1086         break;
1087       }
1088       else if (len == 6){ // pentaidres
1089         double L1 = getDistance(P( 1 ),P( 2 ));
1090         double L2 = getDistance(P( 2 ),P( 3 ));
1091         double L3 = getDistance(P( 3 ),P( 1 ));
1092         double L4 = getDistance(P( 4 ),P( 5 ));
1093         double L5 = getDistance(P( 5 ),P( 6 ));
1094         double L6 = getDistance(P( 6 ),P( 4 ));
1095         double L7 = getDistance(P( 1 ),P( 4 ));
1096         double L8 = getDistance(P( 2 ),P( 5 ));
1097         double L9 = getDistance(P( 3 ),P( 6 ));
1098
1099         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1100         aVal = Max(aVal,Max(Max(L7,L8),L9));
1101         break;
1102       }
1103       else if (len == 8){ // hexaider
1104         double L1 = getDistance(P( 1 ),P( 2 ));
1105         double L2 = getDistance(P( 2 ),P( 3 ));
1106         double L3 = getDistance(P( 3 ),P( 4 ));
1107         double L4 = getDistance(P( 4 ),P( 1 ));
1108         double L5 = getDistance(P( 5 ),P( 6 ));
1109         double L6 = getDistance(P( 6 ),P( 7 ));
1110         double L7 = getDistance(P( 7 ),P( 8 ));
1111         double L8 = getDistance(P( 8 ),P( 5 ));
1112         double L9 = getDistance(P( 1 ),P( 5 ));
1113         double L10= getDistance(P( 2 ),P( 6 ));
1114         double L11= getDistance(P( 3 ),P( 7 ));
1115         double L12= getDistance(P( 4 ),P( 8 ));
1116
1117         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1118         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
1119         aVal = Max(aVal,Max(L11,L12));
1120         break;
1121
1122       }
1123
1124       if (len == 10){ // quadratic tetraidrs
1125         double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
1126         double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
1127         double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
1128         double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1129         double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
1130         double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
1131         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1132         break;
1133       }
1134       else if (len == 13){ // quadratic piramids
1135         double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
1136         double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
1137         double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
1138         double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1139         double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1140         double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
1141         double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
1142         double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
1143         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1144         aVal = Max(aVal,Max(L7,L8));
1145         break;
1146       }
1147       else if (len == 15){ // quadratic pentaidres
1148         double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
1149         double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
1150         double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1151         double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1152         double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
1153         double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
1154         double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
1155         double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
1156         double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
1157         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1158         aVal = Max(aVal,Max(Max(L7,L8),L9));
1159         break;
1160       }
1161       else if (len == 20){ // quadratic hexaider
1162         double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
1163         double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
1164         double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
1165         double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
1166         double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
1167         double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
1168         double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
1169         double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
1170         double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
1171         double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
1172         double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
1173         double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
1174         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
1175         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
1176         aVal = Max(aVal,Max(L11,L12));
1177         break;
1178
1179       }
1180
1181     default: aVal=-1;
1182     }
1183
1184     if (aVal <0){
1185       return 0.;
1186     }
1187
1188     if ( myPrecision >= 0 )
1189     {
1190       double prec = pow( 10., (double)( myPrecision ) );
1191       aVal = floor( aVal * prec + 0.5 ) / prec;
1192     }
1193
1194     return aVal;
1195
1196   }
1197   return 0.;
1198 }
1199
1200 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1201 {
1202   // meaningless as it is not quality control functor
1203   return Value;
1204 }
1205
1206 SMDSAbs_ElementType Length2D::GetType() const
1207 {
1208   return SMDSAbs_Face;
1209 }
1210
1211 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
1212   myLength(theLength)
1213 {
1214   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1215   if(thePntId1 > thePntId2){
1216     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1217   }
1218 }
1219
1220 bool Length2D::Value::operator<(const Length2D::Value& x) const{
1221   if(myPntId[0] < x.myPntId[0]) return true;
1222   if(myPntId[0] == x.myPntId[0])
1223     if(myPntId[1] < x.myPntId[1]) return true;
1224   return false;
1225 }
1226
1227 void Length2D::GetValues(TValues& theValues){
1228   TValues aValues;
1229   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1230   for(; anIter->more(); ){
1231     const SMDS_MeshFace* anElem = anIter->next();
1232
1233     if(anElem->IsQuadratic()) {
1234       const SMDS_QuadraticFaceOfNodes* F =
1235         static_cast<const SMDS_QuadraticFaceOfNodes*>(anElem);
1236       // use special nodes iterator
1237       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
1238       long aNodeId[4];
1239       gp_Pnt P[4];
1240
1241       double aLength;
1242       const SMDS_MeshElement* aNode;
1243       if(anIter->more()){
1244         aNode = anIter->next();
1245         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1246         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1247         aNodeId[0] = aNodeId[1] = aNode->GetID();
1248         aLength = 0;
1249       }
1250       for(; anIter->more(); ){
1251         const SMDS_MeshNode* N1 = static_cast<const SMDS_MeshNode*> (anIter->next());
1252         P[2] = gp_Pnt(N1->X(),N1->Y(),N1->Z());
1253         aNodeId[2] = N1->GetID();
1254         aLength = P[1].Distance(P[2]);
1255         if(!anIter->more()) break;
1256         const SMDS_MeshNode* N2 = static_cast<const SMDS_MeshNode*> (anIter->next());
1257         P[3] = gp_Pnt(N2->X(),N2->Y(),N2->Z());
1258         aNodeId[3] = N2->GetID();
1259         aLength += P[2].Distance(P[3]);
1260         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1261         Value aValue2(aLength,aNodeId[2],aNodeId[3]);
1262         P[1] = P[3];
1263         aNodeId[1] = aNodeId[3];
1264         theValues.insert(aValue1);
1265         theValues.insert(aValue2);
1266       }
1267       aLength += P[2].Distance(P[0]);
1268       Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1269       Value aValue2(aLength,aNodeId[2],aNodeId[0]);
1270       theValues.insert(aValue1);
1271       theValues.insert(aValue2);
1272     }
1273     else {
1274       SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
1275       long aNodeId[2];
1276       gp_Pnt P[3];
1277
1278       double aLength;
1279       const SMDS_MeshElement* aNode;
1280       if(aNodesIter->more()){
1281         aNode = aNodesIter->next();
1282         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1283         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1284         aNodeId[0] = aNodeId[1] = aNode->GetID();
1285         aLength = 0;
1286       }
1287       for(; aNodesIter->more(); ){
1288         aNode = aNodesIter->next();
1289         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1290         long anId = aNode->GetID();
1291         
1292         P[2] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1293         
1294         aLength = P[1].Distance(P[2]);
1295         
1296         Value aValue(aLength,aNodeId[1],anId);
1297         aNodeId[1] = anId;
1298         P[1] = P[2];
1299         theValues.insert(aValue);
1300       }
1301
1302       aLength = P[0].Distance(P[1]);
1303
1304       Value aValue(aLength,aNodeId[0],aNodeId[1]);
1305       theValues.insert(aValue);
1306     }
1307   }
1308 }
1309
1310 /*
1311   Class       : MultiConnection
1312   Description : Functor for calculating number of faces conneted to the edge
1313 */
1314 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
1315 {
1316   return 0;
1317 }
1318 double MultiConnection::GetValue( long theId )
1319 {
1320   return getNbMultiConnection( myMesh, theId );
1321 }
1322
1323 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
1324 {
1325   // meaningless as it is not quality control functor
1326   return Value;
1327 }
1328
1329 SMDSAbs_ElementType MultiConnection::GetType() const
1330 {
1331   return SMDSAbs_Edge;
1332 }
1333
1334 /*
1335   Class       : MultiConnection2D
1336   Description : Functor for calculating number of faces conneted to the edge
1337 */
1338 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
1339 {
1340   return 0;
1341 }
1342
1343 double MultiConnection2D::GetValue( long theElementId )
1344 {
1345   int aResult = 0;
1346
1347   const SMDS_MeshElement* aFaceElem = myMesh->FindElement(theElementId);
1348   SMDSAbs_ElementType aType = aFaceElem->GetType();
1349
1350   switch (aType) {
1351   case SMDSAbs_Face:
1352     {
1353       int i = 0, len = aFaceElem->NbNodes();
1354       SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
1355       if (!anIter) break;
1356
1357       const SMDS_MeshNode *aNode, *aNode0;
1358       TColStd_MapOfInteger aMap, aMapPrev;
1359
1360       for (i = 0; i <= len; i++) {
1361         aMapPrev = aMap;
1362         aMap.Clear();
1363
1364         int aNb = 0;
1365         if (anIter->more()) {
1366           aNode = (SMDS_MeshNode*)anIter->next();
1367         } else {
1368           if (i == len)
1369             aNode = aNode0;
1370           else
1371             break;
1372         }
1373         if (!aNode) break;
1374         if (i == 0) aNode0 = aNode;
1375
1376         SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
1377         while (anElemIter->more()) {
1378           const SMDS_MeshElement* anElem = anElemIter->next();
1379           if (anElem != 0 && anElem->GetType() == SMDSAbs_Face) {
1380             int anId = anElem->GetID();
1381
1382             aMap.Add(anId);
1383             if (aMapPrev.Contains(anId)) {
1384               aNb++;
1385             }
1386           }
1387         }
1388         aResult = Max(aResult, aNb);
1389       }
1390     }
1391     break;
1392   default:
1393     aResult = 0;
1394   }
1395
1396   return aResult;
1397 }
1398
1399 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1400 {
1401   // meaningless as it is not quality control functor
1402   return Value;
1403 }
1404
1405 SMDSAbs_ElementType MultiConnection2D::GetType() const
1406 {
1407   return SMDSAbs_Face;
1408 }
1409
1410 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
1411 {
1412   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1413   if(thePntId1 > thePntId2){
1414     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1415   }
1416 }
1417
1418 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const{
1419   if(myPntId[0] < x.myPntId[0]) return true;
1420   if(myPntId[0] == x.myPntId[0])
1421     if(myPntId[1] < x.myPntId[1]) return true;
1422   return false;
1423 }
1424
1425 void MultiConnection2D::GetValues(MValues& theValues){
1426   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1427   for(; anIter->more(); ){
1428     const SMDS_MeshFace* anElem = anIter->next();
1429     SMDS_ElemIteratorPtr aNodesIter;
1430     if ( anElem->IsQuadratic() )
1431       aNodesIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
1432         (anElem)->interlacedNodesElemIterator();
1433     else
1434       aNodesIter = anElem->nodesIterator();
1435     long aNodeId[3];
1436
1437     //int aNbConnects=0;
1438     const SMDS_MeshNode* aNode0;
1439     const SMDS_MeshNode* aNode1;
1440     const SMDS_MeshNode* aNode2;
1441     if(aNodesIter->more()){
1442       aNode0 = (SMDS_MeshNode*) aNodesIter->next();
1443       aNode1 = aNode0;
1444       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode1;
1445       aNodeId[0] = aNodeId[1] = aNodes->GetID();
1446     }
1447     for(; aNodesIter->more(); ) {
1448       aNode2 = (SMDS_MeshNode*) aNodesIter->next();
1449       long anId = aNode2->GetID();
1450       aNodeId[2] = anId;
1451
1452       Value aValue(aNodeId[1],aNodeId[2]);
1453       MValues::iterator aItr = theValues.find(aValue);
1454       if (aItr != theValues.end()){
1455         aItr->second += 1;
1456         //aNbConnects = nb;
1457       }
1458       else {
1459         theValues[aValue] = 1;
1460         //aNbConnects = 1;
1461       }
1462       //cout << "NodeIds: "<<aNodeId[1]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1463       aNodeId[1] = aNodeId[2];
1464       aNode1 = aNode2;
1465     }
1466     Value aValue(aNodeId[0],aNodeId[2]);
1467     MValues::iterator aItr = theValues.find(aValue);
1468     if (aItr != theValues.end()) {
1469       aItr->second += 1;
1470       //aNbConnects = nb;
1471     }
1472     else {
1473       theValues[aValue] = 1;
1474       //aNbConnects = 1;
1475     }
1476     //cout << "NodeIds: "<<aNodeId[0]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1477   }
1478
1479 }
1480
1481 /*
1482                             PREDICATES
1483 */
1484
1485 /*
1486   Class       : BadOrientedVolume
1487   Description : Predicate bad oriented volumes
1488 */
1489
1490 BadOrientedVolume::BadOrientedVolume()
1491 {
1492   myMesh = 0;
1493 }
1494
1495 void BadOrientedVolume::SetMesh( const SMDS_Mesh* theMesh )
1496 {
1497   myMesh = theMesh;
1498 }
1499
1500 bool BadOrientedVolume::IsSatisfy( long theId )
1501 {
1502   if ( myMesh == 0 )
1503     return false;
1504
1505   SMDS_VolumeTool vTool( myMesh->FindElement( theId ));
1506   return !vTool.IsForward();
1507 }
1508
1509 SMDSAbs_ElementType BadOrientedVolume::GetType() const
1510 {
1511   return SMDSAbs_Volume;
1512 }
1513
1514
1515
1516 /*
1517   Class       : FreeBorders
1518   Description : Predicate for free borders
1519 */
1520
1521 FreeBorders::FreeBorders()
1522 {
1523   myMesh = 0;
1524 }
1525
1526 void FreeBorders::SetMesh( const SMDS_Mesh* theMesh )
1527 {
1528   myMesh = theMesh;
1529 }
1530
1531 bool FreeBorders::IsSatisfy( long theId )
1532 {
1533   return getNbMultiConnection( myMesh, theId ) == 1;
1534 }
1535
1536 SMDSAbs_ElementType FreeBorders::GetType() const
1537 {
1538   return SMDSAbs_Edge;
1539 }
1540
1541
1542 /*
1543   Class       : FreeEdges
1544   Description : Predicate for free Edges
1545 */
1546 FreeEdges::FreeEdges()
1547 {
1548   myMesh = 0;
1549 }
1550
1551 void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
1552 {
1553   myMesh = theMesh;
1554 }
1555
1556 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
1557 {
1558   TColStd_MapOfInteger aMap;
1559   for ( int i = 0; i < 2; i++ )
1560   {
1561     SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator();
1562     while( anElemIter->more() )
1563     {
1564       const SMDS_MeshElement* anElem = anElemIter->next();
1565       if ( anElem != 0 && anElem->GetType() == SMDSAbs_Face )
1566       {
1567         int anId = anElem->GetID();
1568
1569         if ( i == 0 )
1570           aMap.Add( anId );
1571         else if ( aMap.Contains( anId ) && anId != theFaceId )
1572           return false;
1573       }
1574     }
1575   }
1576   return true;
1577 }
1578
1579 bool FreeEdges::IsSatisfy( long theId )
1580 {
1581   if ( myMesh == 0 )
1582     return false;
1583
1584   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
1585   if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
1586     return false;
1587
1588   SMDS_ElemIteratorPtr anIter;
1589   if ( aFace->IsQuadratic() ) {
1590     anIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
1591       (aFace)->interlacedNodesElemIterator();
1592   }
1593   else {
1594     anIter = aFace->nodesIterator();
1595   }
1596   if ( anIter == 0 )
1597     return false;
1598
1599   int i = 0, nbNodes = aFace->NbNodes();
1600   vector <const SMDS_MeshNode*> aNodes( nbNodes+1 );
1601   while( anIter->more() )
1602   {
1603     const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
1604     if ( aNode == 0 )
1605       return false;
1606     aNodes[ i++ ] = aNode;
1607   }
1608   aNodes[ nbNodes ] = aNodes[ 0 ];
1609
1610   for ( i = 0; i < nbNodes; i++ )
1611     if ( IsFreeEdge( &aNodes[ i ], theId ) )
1612       return true;
1613
1614   return false;
1615 }
1616
1617 SMDSAbs_ElementType FreeEdges::GetType() const
1618 {
1619   return SMDSAbs_Face;
1620 }
1621
1622 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
1623   myElemId(theElemId)
1624 {
1625   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1626   if(thePntId1 > thePntId2){
1627     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1628   }
1629 }
1630
1631 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
1632   if(myPntId[0] < x.myPntId[0]) return true;
1633   if(myPntId[0] == x.myPntId[0])
1634     if(myPntId[1] < x.myPntId[1]) return true;
1635   return false;
1636 }
1637
1638 inline void UpdateBorders(const FreeEdges::Border& theBorder,
1639                           FreeEdges::TBorders& theRegistry,
1640                           FreeEdges::TBorders& theContainer)
1641 {
1642   if(theRegistry.find(theBorder) == theRegistry.end()){
1643     theRegistry.insert(theBorder);
1644     theContainer.insert(theBorder);
1645   }else{
1646     theContainer.erase(theBorder);
1647   }
1648 }
1649
1650 void FreeEdges::GetBoreders(TBorders& theBorders)
1651 {
1652   TBorders aRegistry;
1653   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1654   for(; anIter->more(); ){
1655     const SMDS_MeshFace* anElem = anIter->next();
1656     long anElemId = anElem->GetID();
1657     SMDS_ElemIteratorPtr aNodesIter;
1658     if ( anElem->IsQuadratic() )
1659       aNodesIter = static_cast<const SMDS_QuadraticFaceOfNodes*>(anElem)->
1660         interlacedNodesElemIterator();
1661     else
1662       aNodesIter = anElem->nodesIterator();
1663     long aNodeId[2];
1664     const SMDS_MeshElement* aNode;
1665     if(aNodesIter->more()){
1666       aNode = aNodesIter->next();
1667       aNodeId[0] = aNodeId[1] = aNode->GetID();
1668     }
1669     for(; aNodesIter->more(); ){
1670       aNode = aNodesIter->next();
1671       long anId = aNode->GetID();
1672       Border aBorder(anElemId,aNodeId[1],anId);
1673       aNodeId[1] = anId;
1674       //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
1675       UpdateBorders(aBorder,aRegistry,theBorders);
1676     }
1677     Border aBorder(anElemId,aNodeId[0],aNodeId[1]);
1678     //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
1679     UpdateBorders(aBorder,aRegistry,theBorders);
1680   }
1681   //std::cout<<"theBorders.size() = "<<theBorders.size()<<endl;
1682 }
1683
1684 /*
1685   Class       : RangeOfIds
1686   Description : Predicate for Range of Ids.
1687                 Range may be specified with two ways.
1688                 1. Using AddToRange method
1689                 2. With SetRangeStr method. Parameter of this method is a string
1690                    like as "1,2,3,50-60,63,67,70-"
1691 */
1692
1693 //=======================================================================
1694 // name    : RangeOfIds
1695 // Purpose : Constructor
1696 //=======================================================================
1697 RangeOfIds::RangeOfIds()
1698 {
1699   myMesh = 0;
1700   myType = SMDSAbs_All;
1701 }
1702
1703 //=======================================================================
1704 // name    : SetMesh
1705 // Purpose : Set mesh
1706 //=======================================================================
1707 void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
1708 {
1709   myMesh = theMesh;
1710 }
1711
1712 //=======================================================================
1713 // name    : AddToRange
1714 // Purpose : Add ID to the range
1715 //=======================================================================
1716 bool RangeOfIds::AddToRange( long theEntityId )
1717 {
1718   myIds.Add( theEntityId );
1719   return true;
1720 }
1721
1722 //=======================================================================
1723 // name    : GetRangeStr
1724 // Purpose : Get range as a string.
1725 //           Example: "1,2,3,50-60,63,67,70-"
1726 //=======================================================================
1727 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
1728 {
1729   theResStr.Clear();
1730
1731   TColStd_SequenceOfInteger     anIntSeq;
1732   TColStd_SequenceOfAsciiString aStrSeq;
1733
1734   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
1735   for ( ; anIter.More(); anIter.Next() )
1736   {
1737     int anId = anIter.Key();
1738     TCollection_AsciiString aStr( anId );
1739     anIntSeq.Append( anId );
1740     aStrSeq.Append( aStr );
1741   }
1742
1743   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1744   {
1745     int aMinId = myMin( i );
1746     int aMaxId = myMax( i );
1747
1748     TCollection_AsciiString aStr;
1749     if ( aMinId != IntegerFirst() )
1750       aStr += aMinId;
1751
1752     aStr += "-";
1753
1754     if ( aMaxId != IntegerLast() )
1755       aStr += aMaxId;
1756
1757     // find position of the string in result sequence and insert string in it
1758     if ( anIntSeq.Length() == 0 )
1759     {
1760       anIntSeq.Append( aMinId );
1761       aStrSeq.Append( aStr );
1762     }
1763     else
1764     {
1765       if ( aMinId < anIntSeq.First() )
1766       {
1767         anIntSeq.Prepend( aMinId );
1768         aStrSeq.Prepend( aStr );
1769       }
1770       else if ( aMinId > anIntSeq.Last() )
1771       {
1772         anIntSeq.Append( aMinId );
1773         aStrSeq.Append( aStr );
1774       }
1775       else
1776         for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
1777           if ( aMinId < anIntSeq( j ) )
1778           {
1779             anIntSeq.InsertBefore( j, aMinId );
1780             aStrSeq.InsertBefore( j, aStr );
1781             break;
1782           }
1783     }
1784   }
1785
1786   if ( aStrSeq.Length() == 0 )
1787     return;
1788
1789   theResStr = aStrSeq( 1 );
1790   for ( int j = 2, k = aStrSeq.Length(); j <= k; j++  )
1791   {
1792     theResStr += ",";
1793     theResStr += aStrSeq( j );
1794   }
1795 }
1796
1797 //=======================================================================
1798 // name    : SetRangeStr
1799 // Purpose : Define range with string
1800 //           Example of entry string: "1,2,3,50-60,63,67,70-"
1801 //=======================================================================
1802 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
1803 {
1804   myMin.Clear();
1805   myMax.Clear();
1806   myIds.Clear();
1807
1808   TCollection_AsciiString aStr = theStr;
1809   aStr.RemoveAll( ' ' );
1810   aStr.RemoveAll( '\t' );
1811
1812   for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) )
1813     aStr.Remove( aPos, 2 );
1814
1815   TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
1816   int i = 1;
1817   while ( tmpStr != "" )
1818   {
1819     tmpStr = aStr.Token( ",", i++ );
1820     int aPos = tmpStr.Search( '-' );
1821
1822     if ( aPos == -1 )
1823     {
1824       if ( tmpStr.IsIntegerValue() )
1825         myIds.Add( tmpStr.IntegerValue() );
1826       else
1827         return false;
1828     }
1829     else
1830     {
1831       TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
1832       TCollection_AsciiString aMinStr = tmpStr;
1833
1834       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
1835       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
1836
1837       if ( !aMinStr.IsEmpty() && !aMinStr.IsIntegerValue() ||
1838            !aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue() )
1839         return false;
1840
1841       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
1842       myMax.Append( aMaxStr.IsEmpty() ? IntegerLast()  : aMaxStr.IntegerValue() );
1843     }
1844   }
1845
1846   return true;
1847 }
1848
1849 //=======================================================================
1850 // name    : GetType
1851 // Purpose : Get type of supported entities
1852 //=======================================================================
1853 SMDSAbs_ElementType RangeOfIds::GetType() const
1854 {
1855   return myType;
1856 }
1857
1858 //=======================================================================
1859 // name    : SetType
1860 // Purpose : Set type of supported entities
1861 //=======================================================================
1862 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
1863 {
1864   myType = theType;
1865 }
1866
1867 //=======================================================================
1868 // name    : IsSatisfy
1869 // Purpose : Verify whether entity satisfies to this rpedicate
1870 //=======================================================================
1871 bool RangeOfIds::IsSatisfy( long theId )
1872 {
1873   if ( !myMesh )
1874     return false;
1875
1876   if ( myType == SMDSAbs_Node )
1877   {
1878     if ( myMesh->FindNode( theId ) == 0 )
1879       return false;
1880   }
1881   else
1882   {
1883     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
1884     if ( anElem == 0 || myType != anElem->GetType() && myType != SMDSAbs_All )
1885       return false;
1886   }
1887
1888   if ( myIds.Contains( theId ) )
1889     return true;
1890
1891   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1892     if ( theId >= myMin( i ) && theId <= myMax( i ) )
1893       return true;
1894
1895   return false;
1896 }
1897
1898 /*
1899   Class       : Comparator
1900   Description : Base class for comparators
1901 */
1902 Comparator::Comparator():
1903   myMargin(0)
1904 {}
1905
1906 Comparator::~Comparator()
1907 {}
1908
1909 void Comparator::SetMesh( const SMDS_Mesh* theMesh )
1910 {
1911   if ( myFunctor )
1912     myFunctor->SetMesh( theMesh );
1913 }
1914
1915 void Comparator::SetMargin( double theValue )
1916 {
1917   myMargin = theValue;
1918 }
1919
1920 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
1921 {
1922   myFunctor = theFunct;
1923 }
1924
1925 SMDSAbs_ElementType Comparator::GetType() const
1926 {
1927   return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
1928 }
1929
1930 double Comparator::GetMargin()
1931 {
1932   return myMargin;
1933 }
1934
1935
1936 /*
1937   Class       : LessThan
1938   Description : Comparator "<"
1939 */
1940 bool LessThan::IsSatisfy( long theId )
1941 {
1942   return myFunctor && myFunctor->GetValue( theId ) < myMargin;
1943 }
1944
1945
1946 /*
1947   Class       : MoreThan
1948   Description : Comparator ">"
1949 */
1950 bool MoreThan::IsSatisfy( long theId )
1951 {
1952   return myFunctor && myFunctor->GetValue( theId ) > myMargin;
1953 }
1954
1955
1956 /*
1957   Class       : EqualTo
1958   Description : Comparator "="
1959 */
1960 EqualTo::EqualTo():
1961   myToler(Precision::Confusion())
1962 {}
1963
1964 bool EqualTo::IsSatisfy( long theId )
1965 {
1966   return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
1967 }
1968
1969 void EqualTo::SetTolerance( double theToler )
1970 {
1971   myToler = theToler;
1972 }
1973
1974 double EqualTo::GetTolerance()
1975 {
1976   return myToler;
1977 }
1978
1979 /*
1980   Class       : LogicalNOT
1981   Description : Logical NOT predicate
1982 */
1983 LogicalNOT::LogicalNOT()
1984 {}
1985
1986 LogicalNOT::~LogicalNOT()
1987 {}
1988
1989 bool LogicalNOT::IsSatisfy( long theId )
1990 {
1991   return myPredicate && !myPredicate->IsSatisfy( theId );
1992 }
1993
1994 void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
1995 {
1996   if ( myPredicate )
1997     myPredicate->SetMesh( theMesh );
1998 }
1999
2000 void LogicalNOT::SetPredicate( PredicatePtr thePred )
2001 {
2002   myPredicate = thePred;
2003 }
2004
2005 SMDSAbs_ElementType LogicalNOT::GetType() const
2006 {
2007   return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
2008 }
2009
2010
2011 /*
2012   Class       : LogicalBinary
2013   Description : Base class for binary logical predicate
2014 */
2015 LogicalBinary::LogicalBinary()
2016 {}
2017
2018 LogicalBinary::~LogicalBinary()
2019 {}
2020
2021 void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
2022 {
2023   if ( myPredicate1 )
2024     myPredicate1->SetMesh( theMesh );
2025
2026   if ( myPredicate2 )
2027     myPredicate2->SetMesh( theMesh );
2028 }
2029
2030 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
2031 {
2032   myPredicate1 = thePredicate;
2033 }
2034
2035 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
2036 {
2037   myPredicate2 = thePredicate;
2038 }
2039
2040 SMDSAbs_ElementType LogicalBinary::GetType() const
2041 {
2042   if ( !myPredicate1 || !myPredicate2 )
2043     return SMDSAbs_All;
2044
2045   SMDSAbs_ElementType aType1 = myPredicate1->GetType();
2046   SMDSAbs_ElementType aType2 = myPredicate2->GetType();
2047
2048   return aType1 == aType2 ? aType1 : SMDSAbs_All;
2049 }
2050
2051
2052 /*
2053   Class       : LogicalAND
2054   Description : Logical AND
2055 */
2056 bool LogicalAND::IsSatisfy( long theId )
2057 {
2058   return
2059     myPredicate1 &&
2060     myPredicate2 &&
2061     myPredicate1->IsSatisfy( theId ) &&
2062     myPredicate2->IsSatisfy( theId );
2063 }
2064
2065
2066 /*
2067   Class       : LogicalOR
2068   Description : Logical OR
2069 */
2070 bool LogicalOR::IsSatisfy( long theId )
2071 {
2072   return
2073     myPredicate1 &&
2074     myPredicate2 &&
2075     myPredicate1->IsSatisfy( theId ) ||
2076     myPredicate2->IsSatisfy( theId );
2077 }
2078
2079
2080 /*
2081                               FILTER
2082 */
2083
2084 Filter::Filter()
2085 {}
2086
2087 Filter::~Filter()
2088 {}
2089
2090 void Filter::SetPredicate( PredicatePtr thePredicate )
2091 {
2092   myPredicate = thePredicate;
2093 }
2094
2095 template<class TElement, class TIterator, class TPredicate>
2096 inline void FillSequence(const TIterator& theIterator,
2097                          TPredicate& thePredicate,
2098                          Filter::TIdSequence& theSequence)
2099 {
2100   if ( theIterator ) {
2101     while( theIterator->more() ) {
2102       TElement anElem = theIterator->next();
2103       long anId = anElem->GetID();
2104       if ( thePredicate->IsSatisfy( anId ) )
2105         theSequence.push_back( anId );
2106     }
2107   }
2108 }
2109
2110 void
2111 Filter::
2112 GetElementsId( const SMDS_Mesh* theMesh,
2113                PredicatePtr thePredicate,
2114                TIdSequence& theSequence )
2115 {
2116   theSequence.clear();
2117
2118   if ( !theMesh || !thePredicate )
2119     return;
2120
2121   thePredicate->SetMesh( theMesh );
2122
2123   SMDSAbs_ElementType aType = thePredicate->GetType();
2124   switch(aType){
2125   case SMDSAbs_Node:
2126     FillSequence<const SMDS_MeshNode*>(theMesh->nodesIterator(),thePredicate,theSequence);
2127     break;
2128   case SMDSAbs_Edge:
2129     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),thePredicate,theSequence);
2130     break;
2131   case SMDSAbs_Face:
2132     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),thePredicate,theSequence);
2133     break;
2134   case SMDSAbs_Volume:
2135     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),thePredicate,theSequence);
2136     break;
2137   case SMDSAbs_All:
2138     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),thePredicate,theSequence);
2139     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),thePredicate,theSequence);
2140     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),thePredicate,theSequence);
2141     break;
2142   }
2143 }
2144
2145 void
2146 Filter::GetElementsId( const SMDS_Mesh* theMesh,
2147                        Filter::TIdSequence& theSequence )
2148 {
2149   GetElementsId(theMesh,myPredicate,theSequence);
2150 }
2151
2152 /*
2153                               ManifoldPart
2154 */
2155
2156 typedef std::set<SMDS_MeshFace*>                    TMapOfFacePtr;
2157
2158 /*
2159    Internal class Link
2160 */
2161
2162 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
2163                           SMDS_MeshNode* theNode2 )
2164 {
2165   myNode1 = theNode1;
2166   myNode2 = theNode2;
2167 }
2168
2169 ManifoldPart::Link::~Link()
2170 {
2171   myNode1 = 0;
2172   myNode2 = 0;
2173 }
2174
2175 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
2176 {
2177   if ( myNode1 == theLink.myNode1 &&
2178        myNode2 == theLink.myNode2 )
2179     return true;
2180   else if ( myNode1 == theLink.myNode2 &&
2181             myNode2 == theLink.myNode1 )
2182     return true;
2183   else
2184     return false;
2185 }
2186
2187 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
2188 {
2189   if(myNode1 < x.myNode1) return true;
2190   if(myNode1 == x.myNode1)
2191     if(myNode2 < x.myNode2) return true;
2192   return false;
2193 }
2194
2195 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
2196                             const ManifoldPart::Link& theLink2 )
2197 {
2198   return theLink1.IsEqual( theLink2 );
2199 }
2200
2201 ManifoldPart::ManifoldPart()
2202 {
2203   myMesh = 0;
2204   myAngToler = Precision::Angular();
2205   myIsOnlyManifold = true;
2206 }
2207
2208 ManifoldPart::~ManifoldPart()
2209 {
2210   myMesh = 0;
2211 }
2212
2213 void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
2214 {
2215   myMesh = theMesh;
2216   process();
2217 }
2218
2219 SMDSAbs_ElementType ManifoldPart::GetType() const
2220 { return SMDSAbs_Face; }
2221
2222 bool ManifoldPart::IsSatisfy( long theElementId )
2223 {
2224   return myMapIds.Contains( theElementId );
2225 }
2226
2227 void ManifoldPart::SetAngleTolerance( const double theAngToler )
2228 { myAngToler = theAngToler; }
2229
2230 double ManifoldPart::GetAngleTolerance() const
2231 { return myAngToler; }
2232
2233 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
2234 { myIsOnlyManifold = theIsOnly; }
2235
2236 void ManifoldPart::SetStartElem( const long  theStartId )
2237 { myStartElemId = theStartId; }
2238
2239 bool ManifoldPart::process()
2240 {
2241   myMapIds.Clear();
2242   myMapBadGeomIds.Clear();
2243
2244   myAllFacePtr.clear();
2245   myAllFacePtrIntDMap.clear();
2246   if ( !myMesh )
2247     return false;
2248
2249   // collect all faces into own map
2250   SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
2251   for (; anFaceItr->more(); )
2252   {
2253     SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
2254     myAllFacePtr.push_back( aFacePtr );
2255     myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
2256   }
2257
2258   SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
2259   if ( !aStartFace )
2260     return false;
2261
2262   // the map of non manifold links and bad geometry
2263   TMapOfLink aMapOfNonManifold;
2264   TColStd_MapOfInteger aMapOfTreated;
2265
2266   // begin cycle on faces from start index and run on vector till the end
2267   //  and from begin to start index to cover whole vector
2268   const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
2269   bool isStartTreat = false;
2270   for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
2271   {
2272     if ( fi == aStartIndx )
2273       isStartTreat = true;
2274     // as result next time when fi will be equal to aStartIndx
2275
2276     SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
2277     if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
2278       continue;
2279
2280     aMapOfTreated.Add( aFacePtr->GetID() );
2281     TColStd_MapOfInteger aResFaces;
2282     if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
2283                          aMapOfNonManifold, aResFaces ) )
2284       continue;
2285     TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
2286     for ( ; anItr.More(); anItr.Next() )
2287     {
2288       int aFaceId = anItr.Key();
2289       aMapOfTreated.Add( aFaceId );
2290       myMapIds.Add( aFaceId );
2291     }
2292
2293     if ( fi == ( myAllFacePtr.size() - 1 ) )
2294       fi = 0;
2295   } // end run on vector of faces
2296   return !myMapIds.IsEmpty();
2297 }
2298
2299 static void getLinks( const SMDS_MeshFace* theFace,
2300                       ManifoldPart::TVectorOfLink& theLinks )
2301 {
2302   int aNbNode = theFace->NbNodes();
2303   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
2304   int i = 1;
2305   SMDS_MeshNode* aNode = 0;
2306   for ( ; aNodeItr->more() && i <= aNbNode; )
2307   {
2308
2309     SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
2310     if ( i == 1 )
2311       aNode = aN1;
2312     i++;
2313     SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
2314     i++;
2315     ManifoldPart::Link aLink( aN1, aN2 );
2316     theLinks.push_back( aLink );
2317   }
2318 }
2319
2320 static gp_XYZ getNormale( const SMDS_MeshFace* theFace )
2321 {
2322   gp_XYZ n;
2323   int aNbNode = theFace->NbNodes();
2324   TColgp_Array1OfXYZ anArrOfXYZ(1,4);
2325   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
2326   int i = 1;
2327   for ( ; aNodeItr->more() && i <= 4; i++ ) {
2328     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
2329     anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
2330   }
2331
2332   gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1);
2333   gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1);
2334   n  = q1 ^ q2;
2335   if ( aNbNode > 3 ) {
2336     gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1);
2337     n += q2 ^ q3;
2338   }
2339   double len = n.Modulus();
2340   if ( len > 0 )
2341     n /= len;
2342
2343   return n;
2344 }
2345
2346 bool ManifoldPart::findConnected
2347                  ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
2348                   SMDS_MeshFace*                           theStartFace,
2349                   ManifoldPart::TMapOfLink&                theNonManifold,
2350                   TColStd_MapOfInteger&                    theResFaces )
2351 {
2352   theResFaces.Clear();
2353   if ( !theAllFacePtrInt.size() )
2354     return false;
2355
2356   if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
2357   {
2358     myMapBadGeomIds.Add( theStartFace->GetID() );
2359     return false;
2360   }
2361
2362   ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
2363   ManifoldPart::TVectorOfLink aSeqOfBoundary;
2364   theResFaces.Add( theStartFace->GetID() );
2365   ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
2366
2367   expandBoundary( aMapOfBoundary, aSeqOfBoundary,
2368                  aDMapLinkFace, theNonManifold, theStartFace );
2369
2370   bool isDone = false;
2371   while ( !isDone && aMapOfBoundary.size() != 0 )
2372   {
2373     bool isToReset = false;
2374     ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
2375     for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
2376     {
2377       ManifoldPart::Link aLink = *pLink;
2378       if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
2379         continue;
2380       // each link could be treated only once
2381       aMapToSkip.insert( aLink );
2382
2383       ManifoldPart::TVectorOfFacePtr aFaces;
2384       // find next
2385       if ( myIsOnlyManifold &&
2386            (theNonManifold.find( aLink ) != theNonManifold.end()) )
2387         continue;
2388       else
2389       {
2390         getFacesByLink( aLink, aFaces );
2391         // filter the element to keep only indicated elements
2392         ManifoldPart::TVectorOfFacePtr aFiltered;
2393         ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
2394         for ( ; pFace != aFaces.end(); ++pFace )
2395         {
2396           SMDS_MeshFace* aFace = *pFace;
2397           if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
2398             aFiltered.push_back( aFace );
2399         }
2400         aFaces = aFiltered;
2401         if ( aFaces.size() < 2 )  // no neihgbour faces
2402           continue;
2403         else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
2404         {
2405           theNonManifold.insert( aLink );
2406           continue;
2407         }
2408       }
2409
2410       // compare normal with normals of neighbor element
2411       SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
2412       ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
2413       for ( ; pFace != aFaces.end(); ++pFace )
2414       {
2415         SMDS_MeshFace* aNextFace = *pFace;
2416         if ( aPrevFace == aNextFace )
2417           continue;
2418         int anNextFaceID = aNextFace->GetID();
2419         if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
2420          // should not be with non manifold restriction. probably bad topology
2421           continue;
2422         // check if face was treated and skipped
2423         if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
2424              !isInPlane( aPrevFace, aNextFace ) )
2425           continue;
2426         // add new element to connected and extend the boundaries.
2427         theResFaces.Add( anNextFaceID );
2428         expandBoundary( aMapOfBoundary, aSeqOfBoundary,
2429                         aDMapLinkFace, theNonManifold, aNextFace );
2430         isToReset = true;
2431       }
2432     }
2433     isDone = !isToReset;
2434   }
2435
2436   return !theResFaces.IsEmpty();
2437 }
2438
2439 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
2440                               const SMDS_MeshFace* theFace2 )
2441 {
2442   gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
2443   gp_XYZ aNorm2XYZ = getNormale( theFace2 );
2444   if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
2445   {
2446     myMapBadGeomIds.Add( theFace2->GetID() );
2447     return false;
2448   }
2449   if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
2450     return true;
2451
2452   return false;
2453 }
2454
2455 void ManifoldPart::expandBoundary
2456                    ( ManifoldPart::TMapOfLink&            theMapOfBoundary,
2457                      ManifoldPart::TVectorOfLink&         theSeqOfBoundary,
2458                      ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
2459                      ManifoldPart::TMapOfLink&            theNonManifold,
2460                      SMDS_MeshFace*                       theNextFace ) const
2461 {
2462   ManifoldPart::TVectorOfLink aLinks;
2463   getLinks( theNextFace, aLinks );
2464   int aNbLink = (int)aLinks.size();
2465   for ( int i = 0; i < aNbLink; i++ )
2466   {
2467     ManifoldPart::Link aLink = aLinks[ i ];
2468     if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
2469       continue;
2470     if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
2471     {
2472       if ( myIsOnlyManifold )
2473       {
2474         // remove from boundary
2475         theMapOfBoundary.erase( aLink );
2476         ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
2477         for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
2478         {
2479           ManifoldPart::Link aBoundLink = *pLink;
2480           if ( aBoundLink.IsEqual( aLink ) )
2481           {
2482             theSeqOfBoundary.erase( pLink );
2483             break;
2484           }
2485         }
2486       }
2487     }
2488     else
2489     {
2490       theMapOfBoundary.insert( aLink );
2491       theSeqOfBoundary.push_back( aLink );
2492       theDMapLinkFacePtr[ aLink ] = theNextFace;
2493     }
2494   }
2495 }
2496
2497 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
2498                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
2499 {
2500   SMDS_Mesh::SetOfFaces aSetOfFaces;
2501   // take all faces that shared first node
2502   SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
2503   for ( ; anItr->more(); )
2504   {
2505     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2506     if ( !aFace )
2507       continue;
2508     aSetOfFaces.Add( aFace );
2509   }
2510   // take all faces that shared second node
2511   anItr = theLink.myNode2->facesIterator();
2512   // find the common part of two sets
2513   for ( ; anItr->more(); )
2514   {
2515     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2516     if ( aSetOfFaces.Contains( aFace ) )
2517       theFaces.push_back( aFace );
2518   }
2519 }
2520
2521
2522 /*
2523    ElementsOnSurface
2524 */
2525
2526 ElementsOnSurface::ElementsOnSurface()
2527 {
2528   myMesh = 0;
2529   myIds.Clear();
2530   myType = SMDSAbs_All;
2531   mySurf.Nullify();
2532   myToler = Precision::Confusion();
2533 }
2534
2535 ElementsOnSurface::~ElementsOnSurface()
2536 {
2537   myMesh = 0;
2538 }
2539
2540 void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
2541 {
2542   if ( myMesh == theMesh )
2543     return;
2544   myMesh = theMesh;
2545   myIds.Clear();
2546   process();
2547 }
2548
2549 bool ElementsOnSurface::IsSatisfy( long theElementId )
2550 {
2551   return myIds.Contains( theElementId );
2552 }
2553
2554 SMDSAbs_ElementType ElementsOnSurface::GetType() const
2555 { return myType; }
2556
2557 void ElementsOnSurface::SetTolerance( const double theToler )
2558 { myToler = theToler; }
2559
2560 double ElementsOnSurface::GetTolerance() const
2561 {
2562   return myToler;
2563 }
2564
2565 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
2566                                     const SMDSAbs_ElementType theType )
2567 {
2568   myType = theType;
2569   mySurf.Nullify();
2570   if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
2571   {
2572     mySurf.Nullify();
2573     return;
2574   }
2575   TopoDS_Face aFace = TopoDS::Face( theShape );
2576   mySurf = BRep_Tool::Surface( aFace );
2577 }
2578
2579 void ElementsOnSurface::process()
2580 {
2581   myIds.Clear();
2582   if ( mySurf.IsNull() )
2583     return;
2584
2585   if ( myMesh == 0 )
2586     return;
2587
2588   if ( myType == SMDSAbs_Face || myType == SMDSAbs_All )
2589   {
2590     SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
2591     for(; anIter->more(); )
2592       process( anIter->next() );
2593   }
2594
2595   if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All )
2596   {
2597     SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator();
2598     for(; anIter->more(); )
2599       process( anIter->next() );
2600   }
2601
2602   if ( myType == SMDSAbs_Node )
2603   {
2604     SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator();
2605     for(; anIter->more(); )
2606       process( anIter->next() );
2607   }
2608 }
2609
2610 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
2611 {
2612   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
2613   bool isSatisfy = true;
2614   for ( ; aNodeItr->more(); )
2615   {
2616     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
2617     if ( !isOnSurface( aNode ) )
2618     {
2619       isSatisfy = false;
2620       break;
2621     }
2622   }
2623   if ( isSatisfy )
2624     myIds.Add( theElemPtr->GetID() );
2625 }
2626
2627 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) const
2628 {
2629   if ( mySurf.IsNull() )
2630     return false;
2631
2632   gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
2633   double aToler2 = myToler * myToler;
2634   if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
2635   {
2636     gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
2637     if ( aPln.SquareDistance( aPnt ) > aToler2 )
2638       return false;
2639   }
2640   else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
2641   {
2642     gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
2643     double aRad = aCyl.Radius();
2644     gp_Ax3 anAxis = aCyl.Position();
2645     gp_XYZ aLoc = aCyl.Location().XYZ();
2646     double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
2647     double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
2648     if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
2649       return false;
2650   }
2651   else
2652     return false;
2653
2654   return true;
2655 }