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