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