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