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