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