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