Salome HOME
refs #256: 7.5.7. Quality check algorithms
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
1 // Copyright (C) 2007-2016  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, or (at your option) any later version.
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 "SMDS_BallElement.hxx"
26 #include "SMDS_FacePosition.hxx"
27 #include "SMDS_Iterator.hxx"
28 #include "SMDS_Mesh.hxx"
29 #include "SMDS_MeshElement.hxx"
30 #include "SMDS_MeshNode.hxx"
31 #include "SMDS_QuadraticEdge.hxx"
32 #include "SMDS_QuadraticFaceOfNodes.hxx"
33 #include "SMDS_VolumeTool.hxx"
34 #include "SMESHDS_GroupBase.hxx"
35 #include "SMESHDS_GroupOnFilter.hxx"
36 #include "SMESHDS_Mesh.hxx"
37 #include "SMESH_MeshAlgos.hxx"
38 #include "SMESH_OctreeNode.hxx"
39
40 #include <Basics_Utils.hxx>
41
42 #include <BRepAdaptor_Surface.hxx>
43 #include <BRepBndLib.hxx>
44 #include <BRepBuilderAPI_Copy.hxx>
45 #include <BRepClass3d_SolidClassifier.hxx>
46 #include <BRepClass_FaceClassifier.hxx>
47 #include <BRep_Tool.hxx>
48 #include <GeomLib_IsPlanarSurface.hxx>
49 #include <Geom_CylindricalSurface.hxx>
50 #include <Geom_Plane.hxx>
51 #include <Geom_Surface.hxx>
52 #include <NCollection_Map.hxx>
53 #include <Precision.hxx>
54 #include <ShapeAnalysis_Surface.hxx>
55 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
56 #include <TColStd_MapOfInteger.hxx>
57 #include <TColStd_SequenceOfAsciiString.hxx>
58 #include <TColgp_Array1OfXYZ.hxx>
59 #include <TopAbs.hxx>
60 #include <TopExp.hxx>
61 #include <TopoDS.hxx>
62 #include <TopoDS_Edge.hxx>
63 #include <TopoDS_Face.hxx>
64 #include <TopoDS_Iterator.hxx>
65 #include <TopoDS_Shape.hxx>
66 #include <TopoDS_Vertex.hxx>
67 #include <gp_Ax3.hxx>
68 #include <gp_Cylinder.hxx>
69 #include <gp_Dir.hxx>
70 #include <gp_Pln.hxx>
71 #include <gp_Pnt.hxx>
72 #include <gp_Vec.hxx>
73 #include <gp_XYZ.hxx>
74
75 #include <vtkMeshQuality.h>
76
77 #include <set>
78 #include <limits>
79
80 /*
81                             AUXILIARY METHODS
82 */
83
84 namespace {
85
86   const double theEps = 1e-100;
87   const double theInf = 1e+100;
88
89   inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode )
90   {
91     return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() );
92   }
93
94   inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
95   {
96     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
97
98     return v1.Magnitude() < gp::Resolution() ||
99       v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
100   }
101
102   inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
103   {
104     gp_Vec aVec1( P2 - P1 );
105     gp_Vec aVec2( P3 - P1 );
106     return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
107   }
108
109   inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
110   {
111     return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
112   }
113
114
115
116   inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
117   {
118     double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
119     return aDist;
120   }
121
122   int getNbMultiConnection( const SMDS_Mesh* theMesh, const int theId )
123   {
124     if ( theMesh == 0 )
125       return 0;
126
127     const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
128     if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */)
129       return 0;
130
131     // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge)
132     // count elements containing both nodes of the pair.
133     // Note that there may be such cases for a quadratic edge (a horizontal line):
134     //
135     //  Case 1          Case 2
136     //  |     |      |        |      |
137     //  |     |      |        |      |
138     //  +-----+------+  +-----+------+ 
139     //  |            |  |            |
140     //  |            |  |            |
141     // result should be 2 in both cases
142     //
143     int aResult0 = 0, aResult1 = 0;
144      // last node, it is a medium one in a quadratic edge
145     const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 );
146     const SMDS_MeshNode*    aNode0 = anEdge->GetNode( 0 );
147     const SMDS_MeshNode*    aNode1 = anEdge->GetNode( 1 );
148     if ( aNode1 == aLastNode ) aNode1 = 0;
149
150     SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator();
151     while( anElemIter->more() ) {
152       const SMDS_MeshElement* anElem = anElemIter->next();
153       if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
154         SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
155         while ( anIter->more() ) {
156           if ( const SMDS_MeshElement* anElemNode = anIter->next() ) {
157             if ( anElemNode == aNode0 ) {
158               aResult0++;
159               if ( !aNode1 ) break; // not a quadratic edge
160             }
161             else if ( anElemNode == aNode1 )
162               aResult1++;
163           }
164         }
165       }
166     }
167     int aResult = std::max ( aResult0, aResult1 );
168
169     return aResult;
170   }
171
172   gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 )
173   {
174     int aNbNode = theFace->NbNodes();
175
176     gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0));
177     gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0));
178     gp_XYZ n  = q1 ^ q2;
179     if ( aNbNode > 3 ) {
180       gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0));
181       n += q2 ^ q3;
182     }
183     double len = n.Modulus();
184     bool zeroLen = ( len <= std::numeric_limits<double>::min());
185     if ( !zeroLen )
186       n /= len;
187
188     if (ok) *ok = !zeroLen;
189
190     return n;
191   }
192 }
193
194
195
196 using namespace SMESH::Controls;
197
198 /*
199  *                               FUNCTORS
200  */
201
202 //================================================================================
203 /*
204   Class       : NumericalFunctor
205   Description : Base class for numerical functors
206 */
207 //================================================================================
208
209 NumericalFunctor::NumericalFunctor():
210   myMesh(NULL)
211 {
212   myPrecision = -1;
213 }
214
215 void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh )
216 {
217   myMesh = theMesh;
218 }
219
220 bool NumericalFunctor::GetPoints(const int       theId,
221                                  TSequenceOfXYZ& theRes ) const
222 {
223   theRes.clear();
224
225   if ( myMesh == 0 )
226     return false;
227
228   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
229   if ( !anElem || anElem->GetType() != this->GetType() )
230     return false;
231
232   return GetPoints( anElem, theRes );
233 }
234
235 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
236                                  TSequenceOfXYZ&         theRes )
237 {
238   theRes.clear();
239
240   if ( anElem == 0 )
241     return false;
242
243   theRes.reserve( anElem->NbNodes() );
244   theRes.setElement( anElem );
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 = dynamic_cast<const SMDS_VtkEdge*>
253         (anElem)->interlacedNodesElemIterator();
254       break;
255     case SMDSAbs_Face:
256       anIter = dynamic_cast<const SMDS_VtkFace*>
257         (anElem)->interlacedNodesElemIterator();
258       break;
259     default:
260       anIter = anElem->nodesIterator();
261     }
262   }
263   else {
264     anIter = anElem->nodesIterator();
265   }
266
267   if ( anIter ) {
268     SMESH_NodeXYZ p;
269     while( anIter->more() ) {
270       if ( p.Set( anIter->next() ))
271         theRes.push_back( p );
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   myPrecisionValue = pow( 10., (double)( myPrecision ) );
287 }
288
289 double NumericalFunctor::GetValue( long theId )
290 {
291   double aVal = 0;
292
293   myCurrElement = myMesh->FindElement( theId );
294
295   TSequenceOfXYZ P;
296   if ( GetPoints( theId, P )) // elem type is checked here
297     aVal = Round( GetValue( P ));
298
299   return aVal;
300 }
301
302 double NumericalFunctor::Round( const double & aVal )
303 {
304   return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
305 }
306
307 //================================================================================
308 /*!
309  * \brief Return histogram of functor values
310  *  \param nbIntervals - number of intervals
311  *  \param nbEvents - number of mesh elements having values within i-th interval
312  *  \param funValues - boundaries of intervals
313  *  \param elements - elements to check vulue of; empty list means "of all"
314  *  \param minmax - boundaries of diapason of values to divide into intervals
315  */
316 //================================================================================
317
318 void NumericalFunctor::GetHistogram(int                     nbIntervals,
319                                     std::vector<int>&       nbEvents,
320                                     std::vector<double>&    funValues,
321                                     const std::vector<int>& elements,
322                                     const double*           minmax,
323                                     const bool              isLogarithmic)
324 {
325   if ( nbIntervals < 1 ||
326        !myMesh ||
327        !myMesh->GetMeshInfo().NbElements( GetType() ))
328     return;
329   nbEvents.resize( nbIntervals, 0 );
330   funValues.resize( nbIntervals+1 );
331
332   // get all values sorted
333   std::multiset< double > values;
334   if ( elements.empty() )
335   {
336     SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() );
337     while ( elemIt->more() )
338       values.insert( GetValue( elemIt->next()->GetID() ));
339   }
340   else
341   {
342     std::vector<int>::const_iterator id = elements.begin();
343     for ( ; id != elements.end(); ++id )
344       values.insert( GetValue( *id ));
345   }
346
347   if ( minmax )
348   {
349     funValues[0] = minmax[0];
350     funValues[nbIntervals] = minmax[1];
351   }
352   else
353   {
354     funValues[0] = *values.begin();
355     funValues[nbIntervals] = *values.rbegin();
356   }
357   // case nbIntervals == 1
358   if ( nbIntervals == 1 )
359   {
360     nbEvents[0] = values.size();
361     return;
362   }
363   // case of 1 value
364   if (funValues.front() == funValues.back())
365   {
366     nbEvents.resize( 1 );
367     nbEvents[0] = values.size();
368     funValues[1] = funValues.back();
369     funValues.resize( 2 );
370   }
371   // generic case
372   std::multiset< double >::iterator min = values.begin(), max;
373   for ( int i = 0; i < nbIntervals; ++i )
374   {
375     // find end value of i-th interval
376     double r = (i+1) / double(nbIntervals);
377     if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) {
378       double logmin = log10(funValues.front());
379       double lval = logmin + r * (log10(funValues.back()) - logmin);
380       funValues[i+1] = pow(10.0, lval);
381     }
382     else {
383       funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r;
384     }
385
386     // count values in the i-th interval if there are any
387     if ( min != values.end() && *min <= funValues[i+1] )
388     {
389       // find the first value out of the interval
390       max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end()
391       nbEvents[i] = std::distance( min, max );
392       min = max;
393     }
394   }
395   // add values larger than minmax[1]
396   nbEvents.back() += std::distance( min, values.end() );
397 }
398
399 //=======================================================================
400 /*
401   Class       : Volume
402   Description : Functor calculating volume of a 3D element
403 */
404 //================================================================================
405
406 double Volume::GetValue( long theElementId )
407 {
408   if ( theElementId && myMesh ) {
409     SMDS_VolumeTool aVolumeTool;
410     if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
411       return aVolumeTool.GetSize();
412   }
413   return 0;
414 }
415
416 double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const
417 {
418   return Value;
419 }
420
421 SMDSAbs_ElementType Volume::GetType() const
422 {
423   return SMDSAbs_Volume;
424 }
425
426 //=======================================================================
427 /*
428   Class       : MaxElementLength2D
429   Description : Functor calculating maximum length of 2D element
430 */
431 //================================================================================
432
433 double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P )
434 {
435   if(P.size() == 0)
436     return 0.;
437   double aVal = 0;
438   int len = P.size();
439   if( len == 3 ) { // triangles
440     double L1 = getDistance(P( 1 ),P( 2 ));
441     double L2 = getDistance(P( 2 ),P( 3 ));
442     double L3 = getDistance(P( 3 ),P( 1 ));
443     aVal = Max(L1,Max(L2,L3));
444   }
445   else if( len == 4 ) { // quadrangles
446     double L1 = getDistance(P( 1 ),P( 2 ));
447     double L2 = getDistance(P( 2 ),P( 3 ));
448     double L3 = getDistance(P( 3 ),P( 4 ));
449     double L4 = getDistance(P( 4 ),P( 1 ));
450     double D1 = getDistance(P( 1 ),P( 3 ));
451     double D2 = getDistance(P( 2 ),P( 4 ));
452     aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
453   }
454   else if( len == 6 ) { // quadratic triangles
455     double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
456     double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
457     double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
458     aVal = Max(L1,Max(L2,L3));
459   }
460   else if( len == 8 || len == 9 ) { // quadratic quadrangles
461     double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
462     double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
463     double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
464     double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
465     double D1 = getDistance(P( 1 ),P( 5 ));
466     double D2 = getDistance(P( 3 ),P( 7 ));
467     aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
468   }
469   // Diagonals are undefined for concave polygons
470   // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon
471   // {
472   //   // sides
473   //   aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 ));
474   //   for ( size_t i = 1; i < P.size()-1; i += 2 )
475   //   {
476   //     double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 ));
477   //     aVal = Max( aVal, L );
478   //   }
479   //   // diagonals
480   //   for ( int i = P.size()-5; i > 0; i -= 2 )
481   //     for ( int j = i + 4; j < P.size() + i - 2; i += 2 )
482   //     {
483   //       double D = getDistance( P( i ), P( j ));
484   //       aVal = Max( aVal, D );
485   //     }
486   // }
487   // { // polygons
488     
489   // }
490
491   if( myPrecision >= 0 )
492   {
493     double prec = pow( 10., (double)myPrecision );
494     aVal = floor( aVal * prec + 0.5 ) / prec;
495   }
496   return aVal;
497 }
498
499 double MaxElementLength2D::GetValue( long theElementId )
500 {
501   TSequenceOfXYZ P;
502   return GetPoints( theElementId, P ) ? GetValue(P) : 0.0;
503 }
504
505 double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const
506 {
507   return Value;
508 }
509
510 SMDSAbs_ElementType MaxElementLength2D::GetType() const
511 {
512   return SMDSAbs_Face;
513 }
514
515 //=======================================================================
516 /*
517   Class       : MaxElementLength3D
518   Description : Functor calculating maximum length of 3D element
519 */
520 //================================================================================
521
522 double MaxElementLength3D::GetValue( long theElementId )
523 {
524   TSequenceOfXYZ P;
525   if( GetPoints( theElementId, P ) ) {
526     double aVal = 0;
527     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
528     SMDSAbs_EntityType      aType = aElem->GetEntityType();
529     int len = P.size();
530     switch ( aType ) {
531     case SMDSEntity_Tetra: { // tetras
532       double L1 = getDistance(P( 1 ),P( 2 ));
533       double L2 = getDistance(P( 2 ),P( 3 ));
534       double L3 = getDistance(P( 3 ),P( 1 ));
535       double L4 = getDistance(P( 1 ),P( 4 ));
536       double L5 = getDistance(P( 2 ),P( 4 ));
537       double L6 = getDistance(P( 3 ),P( 4 ));
538       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
539       break;
540     }
541     case SMDSEntity_Pyramid: { // pyramids
542       double L1 = getDistance(P( 1 ),P( 2 ));
543       double L2 = getDistance(P( 2 ),P( 3 ));
544       double L3 = getDistance(P( 3 ),P( 4 ));
545       double L4 = getDistance(P( 4 ),P( 1 ));
546       double L5 = getDistance(P( 1 ),P( 5 ));
547       double L6 = getDistance(P( 2 ),P( 5 ));
548       double L7 = getDistance(P( 3 ),P( 5 ));
549       double L8 = getDistance(P( 4 ),P( 5 ));
550       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
551       aVal = Max(aVal,Max(L7,L8));
552       break;
553     }
554     case SMDSEntity_Penta: { // pentas
555       double L1 = getDistance(P( 1 ),P( 2 ));
556       double L2 = getDistance(P( 2 ),P( 3 ));
557       double L3 = getDistance(P( 3 ),P( 1 ));
558       double L4 = getDistance(P( 4 ),P( 5 ));
559       double L5 = getDistance(P( 5 ),P( 6 ));
560       double L6 = getDistance(P( 6 ),P( 4 ));
561       double L7 = getDistance(P( 1 ),P( 4 ));
562       double L8 = getDistance(P( 2 ),P( 5 ));
563       double L9 = getDistance(P( 3 ),P( 6 ));
564       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
565       aVal = Max(aVal,Max(Max(L7,L8),L9));
566       break;
567     }
568     case SMDSEntity_Hexa: { // hexas
569       double L1 = getDistance(P( 1 ),P( 2 ));
570       double L2 = getDistance(P( 2 ),P( 3 ));
571       double L3 = getDistance(P( 3 ),P( 4 ));
572       double L4 = getDistance(P( 4 ),P( 1 ));
573       double L5 = getDistance(P( 5 ),P( 6 ));
574       double L6 = getDistance(P( 6 ),P( 7 ));
575       double L7 = getDistance(P( 7 ),P( 8 ));
576       double L8 = getDistance(P( 8 ),P( 5 ));
577       double L9 = getDistance(P( 1 ),P( 5 ));
578       double L10= getDistance(P( 2 ),P( 6 ));
579       double L11= getDistance(P( 3 ),P( 7 ));
580       double L12= getDistance(P( 4 ),P( 8 ));
581       double D1 = getDistance(P( 1 ),P( 7 ));
582       double D2 = getDistance(P( 2 ),P( 8 ));
583       double D3 = getDistance(P( 3 ),P( 5 ));
584       double D4 = getDistance(P( 4 ),P( 6 ));
585       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
586       aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
587       aVal = Max(aVal,Max(L11,L12));
588       aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
589       break;
590     }
591     case SMDSEntity_Hexagonal_Prism: { // hexagonal prism
592       for ( int i1 = 1; i1 < 12; ++i1 )
593         for ( int i2 = i1+1; i1 <= 12; ++i1 )
594           aVal = Max( aVal, getDistance(P( i1 ),P( i2 )));
595       break;
596     }
597     case SMDSEntity_Quad_Tetra: { // quadratic tetras
598       double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
599       double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
600       double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
601       double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
602       double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
603       double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
604       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
605       break;
606     }
607     case SMDSEntity_Quad_Pyramid: { // quadratic pyramids
608       double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
609       double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
610       double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
611       double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
612       double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
613       double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
614       double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
615       double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
616       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
617       aVal = Max(aVal,Max(L7,L8));
618       break;
619     }
620     case SMDSEntity_Quad_Penta:
621     /*case SMDSEntity_BiQuad_Penta:*/ { // quadratic pentas
622       double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
623       double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
624       double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
625       double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
626       double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
627       double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
628       double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
629       double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
630       double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
631       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
632       aVal = Max(aVal,Max(Max(L7,L8),L9));
633       break;
634     }
635     case SMDSEntity_Quad_Hexa:
636     case SMDSEntity_TriQuad_Hexa: { // quadratic hexas
637       double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
638       double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
639       double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
640       double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
641       double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
642       double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
643       double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
644       double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
645       double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
646       double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
647       double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
648       double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
649       double D1 = getDistance(P( 1 ),P( 7 ));
650       double D2 = getDistance(P( 2 ),P( 8 ));
651       double D3 = getDistance(P( 3 ),P( 5 ));
652       double D4 = getDistance(P( 4 ),P( 6 ));
653       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
654       aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
655       aVal = Max(aVal,Max(L11,L12));
656       aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
657       break;
658     }
659     case SMDSEntity_Quad_Polyhedra:
660     case SMDSEntity_Polyhedra: { // polys
661       // get the maximum distance between all pairs of nodes
662       for( int i = 1; i <= len; i++ ) {
663         for( int j = 1; j <= len; j++ ) {
664           if( j > i ) { // optimization of the loop
665             double D = getDistance( P(i), P(j) );
666             aVal = Max( aVal, D );
667           }
668         }
669       }
670       break;
671     }
672     case SMDSEntity_Node:
673     case SMDSEntity_0D:
674     case SMDSEntity_Edge:
675     case SMDSEntity_Quad_Edge:
676     case SMDSEntity_Triangle:
677     case SMDSEntity_Quad_Triangle:
678     case SMDSEntity_BiQuad_Triangle:
679     case SMDSEntity_Quadrangle:
680     case SMDSEntity_Quad_Quadrangle:
681     case SMDSEntity_BiQuad_Quadrangle:
682     case SMDSEntity_Polygon:
683     case SMDSEntity_Quad_Polygon:
684     case SMDSEntity_Ball:
685     case SMDSEntity_Last: return 0;
686     } // switch ( aType )
687
688     if( myPrecision >= 0 )
689     {
690       double prec = pow( 10., (double)myPrecision );
691       aVal = floor( aVal * prec + 0.5 ) / prec;
692     }
693     return aVal;
694   }
695   return 0.;
696 }
697
698 double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const
699 {
700   return Value;
701 }
702
703 SMDSAbs_ElementType MaxElementLength3D::GetType() const
704 {
705   return SMDSAbs_Volume;
706 }
707
708 //=======================================================================
709 /*
710   Class       : MinimumAngle
711   Description : Functor for calculation of minimum angle
712 */
713 //================================================================================
714
715 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
716 {
717   double aMin;
718
719   if (P.size() <3)
720     return 0.;
721
722   aMin = getAngle(P( P.size() ), P( 1 ), P( 2 ));
723   aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 )));
724
725   for ( size_t i = 2; i < P.size(); i++ )
726   {
727     double A0 = getAngle( P( i-1 ), P( i ), P( i+1 ) );
728     aMin = Min(aMin,A0);
729   }
730
731   return aMin * 180.0 / M_PI;
732 }
733
734 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
735 {
736   //const double aBestAngle = PI / nbNodes;
737   const double aBestAngle = 180.0 - ( 360.0 / double(nbNodes) );
738   return ( fabs( aBestAngle - Value ));
739 }
740
741 SMDSAbs_ElementType MinimumAngle::GetType() const
742 {
743   return SMDSAbs_Face;
744 }
745
746
747 //================================================================================
748 /*
749   Class       : AspectRatio
750   Description : Functor for calculating aspect ratio
751 */
752 //================================================================================
753
754 double AspectRatio::GetValue( long theId )
755 {
756   double aVal = 0;
757   myCurrElement = myMesh->FindElement( theId );
758   if ( myCurrElement && myCurrElement->GetVtkType() == VTK_QUAD )
759   {
760     // issue 21723
761     vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid();
762     if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() ))
763       aVal = Round( vtkMeshQuality::QuadAspectRatio( avtkCell ));
764   }
765   else
766   {
767     TSequenceOfXYZ P;
768     if ( GetPoints( myCurrElement, P ))
769       aVal = Round( GetValue( P ));
770   }
771   return aVal;
772 }
773
774 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
775 {
776   // According to "Mesh quality control" by Nadir Bouhamau referring to
777   // Pascal Jean Frey and Paul-Louis George. Maillages, applications aux elements finis.
778   // Hermes Science publications, Paris 1999 ISBN 2-7462-0024-4
779   // PAL10872
780
781   int nbNodes = P.size();
782
783   if ( nbNodes < 3 )
784     return 0;
785
786   // Compute aspect ratio
787
788   if ( nbNodes == 3 ) {
789     // Compute lengths of the sides
790     std::vector< double > aLen (nbNodes);
791     for ( int i = 0; i < nbNodes - 1; i++ )
792       aLen[ i ] = getDistance( P( i + 1 ), P( i + 2 ) );
793     aLen[ nbNodes - 1 ] = getDistance( P( 1 ), P( nbNodes ) );
794     // Q = alfa * h * p / S, where
795     //
796     // alfa = sqrt( 3 ) / 6
797     // h - length of the longest edge
798     // p - half perimeter
799     // S - triangle surface
800     const double alfa = sqrt( 3. ) / 6.;
801     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
802     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
803     double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) );
804     if ( anArea <= theEps  )
805       return theInf;
806     return alfa * maxLen * half_perimeter / anArea;
807   }
808   else if ( nbNodes == 6 ) { // quadratic triangles
809     // Compute lengths of the sides
810     std::vector< double > aLen (3);
811     aLen[0] = getDistance( P(1), P(3) );
812     aLen[1] = getDistance( P(3), P(5) );
813     aLen[2] = getDistance( P(5), P(1) );
814     // Q = alfa * h * p / S, where
815     //
816     // alfa = sqrt( 3 ) / 6
817     // h - length of the longest edge
818     // p - half perimeter
819     // S - triangle surface
820     const double alfa = sqrt( 3. ) / 6.;
821     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
822     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
823     double anArea = getArea( P(1), P(3), P(5) );
824     if ( anArea <= theEps )
825       return theInf;
826     return alfa * maxLen * half_perimeter / anArea;
827   }
828   else if( nbNodes == 4 ) { // quadrangle
829     // Compute lengths of the sides
830     std::vector< double > aLen (4);
831     aLen[0] = getDistance( P(1), P(2) );
832     aLen[1] = getDistance( P(2), P(3) );
833     aLen[2] = getDistance( P(3), P(4) );
834     aLen[3] = getDistance( P(4), P(1) );
835     // Compute lengths of the diagonals
836     std::vector< double > aDia (2);
837     aDia[0] = getDistance( P(1), P(3) );
838     aDia[1] = getDistance( P(2), P(4) );
839     // Compute areas of all triangles which can be built
840     // taking three nodes of the quadrangle
841     std::vector< double > anArea (4);
842     anArea[0] = getArea( P(1), P(2), P(3) );
843     anArea[1] = getArea( P(1), P(2), P(4) );
844     anArea[2] = getArea( P(1), P(3), P(4) );
845     anArea[3] = getArea( P(2), P(3), P(4) );
846     // Q = alpha * L * C1 / C2, where
847     //
848     // alpha = sqrt( 1/32 )
849     // L = max( L1, L2, L3, L4, D1, D2 )
850     // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 )
851     // C2 = min( S1, S2, S3, S4 )
852     // Li - lengths of the edges
853     // Di - lengths of the diagonals
854     // Si - areas of the triangles
855     const double alpha = sqrt( 1 / 32. );
856     double L = Max( aLen[ 0 ],
857                  Max( aLen[ 1 ],
858                    Max( aLen[ 2 ],
859                      Max( aLen[ 3 ],
860                        Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
861     double C1 = sqrt( ( aLen[0] * aLen[0] +
862                         aLen[1] * aLen[1] +
863                         aLen[2] * aLen[2] +
864                         aLen[3] * aLen[3] ) / 4. );
865     double C2 = Min( anArea[ 0 ],
866                   Min( anArea[ 1 ],
867                     Min( anArea[ 2 ], anArea[ 3 ] ) ) );
868     if ( C2 <= theEps )
869       return theInf;
870     return alpha * L * C1 / C2;
871   }
872   else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle
873     // Compute lengths of the sides
874     std::vector< double > aLen (4);
875     aLen[0] = getDistance( P(1), P(3) );
876     aLen[1] = getDistance( P(3), P(5) );
877     aLen[2] = getDistance( P(5), P(7) );
878     aLen[3] = getDistance( P(7), P(1) );
879     // Compute lengths of the diagonals
880     std::vector< double > aDia (2);
881     aDia[0] = getDistance( P(1), P(5) );
882     aDia[1] = getDistance( P(3), P(7) );
883     // Compute areas of all triangles which can be built
884     // taking three nodes of the quadrangle
885     std::vector< double > anArea (4);
886     anArea[0] = getArea( P(1), P(3), P(5) );
887     anArea[1] = getArea( P(1), P(3), P(7) );
888     anArea[2] = getArea( P(1), P(5), P(7) );
889     anArea[3] = getArea( P(3), P(5), P(7) );
890     // Q = alpha * L * C1 / C2, where
891     //
892     // alpha = sqrt( 1/32 )
893     // L = max( L1, L2, L3, L4, D1, D2 )
894     // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 )
895     // C2 = min( S1, S2, S3, S4 )
896     // Li - lengths of the edges
897     // Di - lengths of the diagonals
898     // Si - areas of the triangles
899     const double alpha = sqrt( 1 / 32. );
900     double L = Max( aLen[ 0 ],
901                  Max( aLen[ 1 ],
902                    Max( aLen[ 2 ],
903                      Max( aLen[ 3 ],
904                        Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
905     double C1 = sqrt( ( aLen[0] * aLen[0] +
906                         aLen[1] * aLen[1] +
907                         aLen[2] * aLen[2] +
908                         aLen[3] * aLen[3] ) / 4. );
909     double C2 = Min( anArea[ 0 ],
910                   Min( anArea[ 1 ],
911                     Min( anArea[ 2 ], anArea[ 3 ] ) ) );
912     if ( C2 <= theEps )
913       return theInf;
914     return alpha * L * C1 / C2;
915   }
916   return 0;
917 }
918
919 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
920 {
921   // the aspect ratio is in the range [1.0,infinity]
922   // < 1.0 = very bad, zero area
923   // 1.0 = good
924   // infinity = bad
925   return ( Value < 0.9 ) ? 1000 : Value / 1000.;
926 }
927
928 SMDSAbs_ElementType AspectRatio::GetType() const
929 {
930   return SMDSAbs_Face;
931 }
932
933
934 //================================================================================
935 /*
936   Class       : AspectRatio3D
937   Description : Functor for calculating aspect ratio
938 */
939 //================================================================================
940
941 namespace{
942
943   inline double getHalfPerimeter(double theTria[3]){
944     return (theTria[0] + theTria[1] + theTria[2])/2.0;
945   }
946
947   inline double getArea(double theHalfPerim, double theTria[3]){
948     return sqrt(theHalfPerim*
949                 (theHalfPerim-theTria[0])*
950                 (theHalfPerim-theTria[1])*
951                 (theHalfPerim-theTria[2]));
952   }
953
954   inline double getVolume(double theLen[6]){
955     double a2 = theLen[0]*theLen[0];
956     double b2 = theLen[1]*theLen[1];
957     double c2 = theLen[2]*theLen[2];
958     double d2 = theLen[3]*theLen[3];
959     double e2 = theLen[4]*theLen[4];
960     double f2 = theLen[5]*theLen[5];
961     double P = 4.0*a2*b2*d2;
962     double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
963     double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
964     return sqrt(P-Q+R)/12.0;
965   }
966
967   inline double getVolume2(double theLen[6]){
968     double a2 = theLen[0]*theLen[0];
969     double b2 = theLen[1]*theLen[1];
970     double c2 = theLen[2]*theLen[2];
971     double d2 = theLen[3]*theLen[3];
972     double e2 = theLen[4]*theLen[4];
973     double f2 = theLen[5]*theLen[5];
974
975     double P = a2*e2*(b2+c2+d2+f2-a2-e2);
976     double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
977     double R = c2*d2*(a2+b2+e2+f2-c2-d2);
978     double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
979
980     return sqrt(P+Q+R-S)/12.0;
981   }
982
983   inline double getVolume(const TSequenceOfXYZ& P){
984     gp_Vec aVec1( P( 2 ) - P( 1 ) );
985     gp_Vec aVec2( P( 3 ) - P( 1 ) );
986     gp_Vec aVec3( P( 4 ) - P( 1 ) );
987     gp_Vec anAreaVec( aVec1 ^ aVec2 );
988     return fabs(aVec3 * anAreaVec) / 6.0;
989   }
990
991   inline double getMaxHeight(double theLen[6])
992   {
993     double aHeight = std::max(theLen[0],theLen[1]);
994     aHeight = std::max(aHeight,theLen[2]);
995     aHeight = std::max(aHeight,theLen[3]);
996     aHeight = std::max(aHeight,theLen[4]);
997     aHeight = std::max(aHeight,theLen[5]);
998     return aHeight;
999   }
1000
1001 }
1002
1003 double AspectRatio3D::GetValue( long theId )
1004 {
1005   double aVal = 0;
1006   myCurrElement = myMesh->FindElement( theId );
1007   if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA )
1008   {
1009     // Action from CoTech | ACTION 31.3:
1010     // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with
1011     // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH.
1012     vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid();
1013     if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() ))
1014       aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell ));
1015   }
1016   else
1017   {
1018     TSequenceOfXYZ P;
1019     if ( GetPoints( myCurrElement, P ))
1020       aVal = Round( GetValue( P ));
1021   }
1022   return aVal;
1023 }
1024
1025 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
1026 {
1027   double aQuality = 0.0;
1028   if(myCurrElement->IsPoly()) return aQuality;
1029
1030   int nbNodes = P.size();
1031
1032   if(myCurrElement->IsQuadratic()) {
1033     if(nbNodes==10) nbNodes=4; // quadratic tetrahedron
1034     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
1035     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
1036     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
1037     else if(nbNodes==27) nbNodes=8; // quadratic hexahedron
1038     else return aQuality;
1039   }
1040
1041   switch(nbNodes) {
1042   case 4:{
1043     double aLen[6] = {
1044       getDistance(P( 1 ),P( 2 )), // a
1045       getDistance(P( 2 ),P( 3 )), // b
1046       getDistance(P( 3 ),P( 1 )), // c
1047       getDistance(P( 2 ),P( 4 )), // d
1048       getDistance(P( 3 ),P( 4 )), // e
1049       getDistance(P( 1 ),P( 4 ))  // f
1050     };
1051     double aTria[4][3] = {
1052       {aLen[0],aLen[1],aLen[2]}, // abc
1053       {aLen[0],aLen[3],aLen[5]}, // adf
1054       {aLen[1],aLen[3],aLen[4]}, // bde
1055       {aLen[2],aLen[4],aLen[5]}  // cef
1056     };
1057     double aSumArea = 0.0;
1058     double aHalfPerimeter = getHalfPerimeter(aTria[0]);
1059     double anArea = getArea(aHalfPerimeter,aTria[0]);
1060     aSumArea += anArea;
1061     aHalfPerimeter = getHalfPerimeter(aTria[1]);
1062     anArea = getArea(aHalfPerimeter,aTria[1]);
1063     aSumArea += anArea;
1064     aHalfPerimeter = getHalfPerimeter(aTria[2]);
1065     anArea = getArea(aHalfPerimeter,aTria[2]);
1066     aSumArea += anArea;
1067     aHalfPerimeter = getHalfPerimeter(aTria[3]);
1068     anArea = getArea(aHalfPerimeter,aTria[3]);
1069     aSumArea += anArea;
1070     double aVolume = getVolume(P);
1071     //double aVolume = getVolume(aLen);
1072     double aHeight = getMaxHeight(aLen);
1073     static double aCoeff = sqrt(2.0)/12.0;
1074     if ( aVolume > DBL_MIN )
1075       aQuality = aCoeff*aHeight*aSumArea/aVolume;
1076     break;
1077   }
1078   case 5:{
1079     {
1080       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
1081       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1082     }
1083     {
1084       gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
1085       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1086     }
1087     {
1088       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
1089       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1090     }
1091     {
1092       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
1093       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1094     }
1095     break;
1096   }
1097   case 6:{
1098     {
1099       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
1100       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1101     }
1102     {
1103       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
1104       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1105     }
1106     {
1107       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
1108       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1109     }
1110     {
1111       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1112       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1113     }
1114     {
1115       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
1116       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1117     }
1118     {
1119       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
1120       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1121     }
1122     break;
1123   }
1124   case 8:{
1125     {
1126       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1127       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1128     }
1129     {
1130       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
1131       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1132     }
1133     {
1134       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
1135       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1136     }
1137     {
1138       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
1139       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1140     }
1141     {
1142       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
1143       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1144     }
1145     {
1146       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
1147       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1148     }
1149     {
1150       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
1151       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1152     }
1153     {
1154       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
1155       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1156     }
1157     {
1158       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
1159       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1160     }
1161     {
1162       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
1163       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1164     }
1165     {
1166       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
1167       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1168     }
1169     {
1170       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
1171       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1172     }
1173     {
1174       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
1175       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1176     }
1177     {
1178       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
1179       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1180     }
1181     {
1182       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
1183       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1184     }
1185     {
1186       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
1187       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1188     }
1189     {
1190       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
1191       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1192     }
1193     {
1194       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
1195       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1196     }
1197     {
1198       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
1199       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1200     }
1201     {
1202       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
1203       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1204     }
1205     {
1206       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
1207       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1208     }
1209     {
1210       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1211       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1212     }
1213     {
1214       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
1215       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1216     }
1217     {
1218       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
1219       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1220     }
1221     {
1222       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1223       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1224     }
1225     {
1226       gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
1227       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1228     }
1229     {
1230       gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
1231       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1232     }
1233     {
1234       gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
1235       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1236     }
1237     {
1238       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
1239       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1240     }
1241     {
1242       gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
1243       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1244     }
1245     {
1246       gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
1247       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1248     }
1249     {
1250       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
1251       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1252     }
1253     {
1254       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
1255       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1256     }
1257     break;
1258   }
1259   case 12:
1260     {
1261       gp_XYZ aXYZ[8] = {P( 1 ),P( 2 ),P( 4 ),P( 5 ),P( 7 ),P( 8 ),P( 10 ),P( 11 )};
1262       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1263     }
1264     {
1265       gp_XYZ aXYZ[8] = {P( 2 ),P( 3 ),P( 5 ),P( 6 ),P( 8 ),P( 9 ),P( 11 ),P( 12 )};
1266       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1267     }
1268     {
1269       gp_XYZ aXYZ[8] = {P( 3 ),P( 4 ),P( 6 ),P( 1 ),P( 9 ),P( 10 ),P( 12 ),P( 7 )};
1270       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1271     }
1272     break;
1273   } // switch(nbNodes)
1274
1275   if ( nbNodes > 4 ) {
1276     // avaluate aspect ratio of quadranle faces
1277     AspectRatio aspect2D;
1278     SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes );
1279     int nbFaces = SMDS_VolumeTool::NbFaces( type );
1280     TSequenceOfXYZ points(4);
1281     for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume
1282       if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 )
1283         continue;
1284       const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true );
1285       for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadranle face
1286         points( p + 1 ) = P( pInd[ p ] + 1 );
1287       aQuality = std::max( aQuality, aspect2D.GetValue( points ));
1288     }
1289   }
1290   return aQuality;
1291 }
1292
1293 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
1294 {
1295   // the aspect ratio is in the range [1.0,infinity]
1296   // 1.0 = good
1297   // infinity = bad
1298   return Value / 1000.;
1299 }
1300
1301 SMDSAbs_ElementType AspectRatio3D::GetType() const
1302 {
1303   return SMDSAbs_Volume;
1304 }
1305
1306
1307 //================================================================================
1308 /*
1309   Class       : Warping
1310   Description : Functor for calculating warping
1311 */
1312 //================================================================================
1313
1314 double Warping::GetValue( const TSequenceOfXYZ& P )
1315 {
1316   if ( P.size() != 4 )
1317     return 0;
1318
1319   gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4.;
1320
1321   double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G );
1322   double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G );
1323   double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G );
1324   double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G );
1325
1326   double val = Max( Max( A1, A2 ), Max( A3, A4 ) );
1327
1328   const double eps = 0.1; // val is in degrees
1329
1330   return val < eps ? 0. : val;
1331 }
1332
1333 double Warping::ComputeA( const gp_XYZ& thePnt1,
1334                           const gp_XYZ& thePnt2,
1335                           const gp_XYZ& thePnt3,
1336                           const gp_XYZ& theG ) const
1337 {
1338   double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
1339   double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
1340   double L = Min( aLen1, aLen2 ) * 0.5;
1341   if ( L < theEps )
1342     return theInf;
1343
1344   gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG;
1345   gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG;
1346   gp_XYZ N  = GI.Crossed( GJ );
1347
1348   if ( N.Modulus() < gp::Resolution() )
1349     return M_PI / 2;
1350
1351   N.Normalize();
1352
1353   double H = ( thePnt2 - theG ).Dot( N );
1354   return asin( fabs( H / L ) ) * 180. / M_PI;
1355 }
1356
1357 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
1358 {
1359   // the warp is in the range [0.0,PI/2]
1360   // 0.0 = good (no warp)
1361   // PI/2 = bad  (face pliee)
1362   return Value;
1363 }
1364
1365 SMDSAbs_ElementType Warping::GetType() const
1366 {
1367   return SMDSAbs_Face;
1368 }
1369
1370
1371 //================================================================================
1372 /*
1373   Class       : Taper
1374   Description : Functor for calculating taper
1375 */
1376 //================================================================================
1377
1378 double Taper::GetValue( const TSequenceOfXYZ& P )
1379 {
1380   if ( P.size() != 4 )
1381     return 0.;
1382
1383   // Compute taper
1384   double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) );
1385   double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) );
1386   double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) );
1387   double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) );
1388
1389   double JA = 0.25 * ( J1 + J2 + J3 + J4 );
1390   if ( JA <= theEps )
1391     return theInf;
1392
1393   double T1 = fabs( ( J1 - JA ) / JA );
1394   double T2 = fabs( ( J2 - JA ) / JA );
1395   double T3 = fabs( ( J3 - JA ) / JA );
1396   double T4 = fabs( ( J4 - JA ) / JA );
1397
1398   double val = Max( Max( T1, T2 ), Max( T3, T4 ) );
1399
1400   const double eps = 0.01;
1401
1402   return val < eps ? 0. : val;
1403 }
1404
1405 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
1406 {
1407   // the taper is in the range [0.0,1.0]
1408   // 0.0 = good (no taper)
1409   // 1.0 = bad  (les cotes opposes sont allignes)
1410   return Value;
1411 }
1412
1413 SMDSAbs_ElementType Taper::GetType() const
1414 {
1415   return SMDSAbs_Face;
1416 }
1417
1418 //================================================================================
1419 /*
1420   Class       : Skew
1421   Description : Functor for calculating skew in degrees
1422 */
1423 //================================================================================
1424
1425 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
1426 {
1427   gp_XYZ p12 = ( p2 + p1 ) / 2.;
1428   gp_XYZ p23 = ( p3 + p2 ) / 2.;
1429   gp_XYZ p31 = ( p3 + p1 ) / 2.;
1430
1431   gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
1432
1433   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
1434 }
1435
1436 double Skew::GetValue( const TSequenceOfXYZ& P )
1437 {
1438   if ( P.size() != 3 && P.size() != 4 )
1439     return 0.;
1440
1441   // Compute skew
1442   const double PI2 = M_PI / 2.;
1443   if ( P.size() == 3 )
1444   {
1445     double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
1446     double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
1447     double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
1448
1449     return Max( A0, Max( A1, A2 ) ) * 180. / M_PI;
1450   }
1451   else
1452   {
1453     gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2.;
1454     gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2.;
1455     gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2.;
1456     gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2.;
1457
1458     gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
1459     double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
1460       ? 0. : fabs( PI2 - v1.Angle( v2 ) );
1461
1462     double val = A * 180. / M_PI;
1463
1464     const double eps = 0.1; // val is in degrees
1465
1466     return val < eps ? 0. : val;
1467   }
1468 }
1469
1470 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
1471 {
1472   // the skew is in the range [0.0,PI/2].
1473   // 0.0 = good
1474   // PI/2 = bad
1475   return Value;
1476 }
1477
1478 SMDSAbs_ElementType Skew::GetType() const
1479 {
1480   return SMDSAbs_Face;
1481 }
1482
1483
1484 //================================================================================
1485 /*
1486   Class       : Area
1487   Description : Functor for calculating area
1488 */
1489 //================================================================================
1490
1491 double Area::GetValue( const TSequenceOfXYZ& P )
1492 {
1493   double val = 0.0;
1494   if ( P.size() > 2 )
1495   {
1496     gp_Vec aVec1( P(2) - P(1) );
1497     gp_Vec aVec2( P(3) - P(1) );
1498     gp_Vec SumVec = aVec1 ^ aVec2;
1499
1500     for (size_t i=4; i<=P.size(); i++)
1501     {
1502       gp_Vec aVec1( P(i-1) - P(1) );
1503       gp_Vec aVec2( P(i  ) - P(1) );
1504       gp_Vec tmp = aVec1 ^ aVec2;
1505       SumVec.Add(tmp);
1506     }
1507     val = SumVec.Magnitude() * 0.5;
1508   }
1509   return val;
1510 }
1511
1512 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
1513 {
1514   // meaningless as it is not a quality control functor
1515   return Value;
1516 }
1517
1518 SMDSAbs_ElementType Area::GetType() const
1519 {
1520   return SMDSAbs_Face;
1521 }
1522
1523 //================================================================================
1524 /*
1525   Class       : Length
1526   Description : Functor for calculating length of edge
1527 */
1528 //================================================================================
1529
1530 double Length::GetValue( const TSequenceOfXYZ& P )
1531 {
1532   switch ( P.size() ) {
1533   case 2:  return getDistance( P( 1 ), P( 2 ) );
1534   case 3:  return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) );
1535   default: return 0.;
1536   }
1537 }
1538
1539 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
1540 {
1541   // meaningless as it is not quality control functor
1542   return Value;
1543 }
1544
1545 SMDSAbs_ElementType Length::GetType() const
1546 {
1547   return SMDSAbs_Edge;
1548 }
1549
1550 //================================================================================
1551 /*
1552   Class       : Length2D
1553   Description : Functor for calculating minimal length of edge
1554 */
1555 //================================================================================
1556
1557 double Length2D::GetValue( const TSequenceOfXYZ& P )
1558 {
1559   double aVal = 0;
1560   int len = P.size();
1561   SMDSAbs_EntityType aType = P.getElementEntity();
1562
1563   switch (aType) {
1564   case SMDSEntity_Edge:
1565     if (len == 2)
1566       aVal = getDistance( P( 1 ), P( 2 ) );
1567     break;
1568   case SMDSEntity_Quad_Edge:
1569     if (len == 3) // quadratic edge
1570       aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
1571     break;
1572   case SMDSEntity_Triangle:
1573     if (len == 3){ // triangles
1574       double L1 = getDistance(P( 1 ),P( 2 ));
1575       double L2 = getDistance(P( 2 ),P( 3 ));
1576       double L3 = getDistance(P( 3 ),P( 1 ));
1577       aVal = Min(L1,Min(L2,L3));
1578     }
1579     break;
1580   case SMDSEntity_Quadrangle:
1581     if (len == 4){ // quadrangles
1582       double L1 = getDistance(P( 1 ),P( 2 ));
1583       double L2 = getDistance(P( 2 ),P( 3 ));
1584       double L3 = getDistance(P( 3 ),P( 4 ));
1585       double L4 = getDistance(P( 4 ),P( 1 ));
1586       aVal = Min(Min(L1,L2),Min(L3,L4));
1587     }
1588     break;
1589   case SMDSEntity_Quad_Triangle:
1590   case SMDSEntity_BiQuad_Triangle:
1591     if (len >= 6){ // quadratic triangles
1592       double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1593       double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1594       double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
1595       aVal = Min(L1,Min(L2,L3));
1596     }
1597     break;
1598   case SMDSEntity_Quad_Quadrangle:
1599   case SMDSEntity_BiQuad_Quadrangle:
1600     if (len >= 8){ // quadratic quadrangles
1601       double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1602       double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1603       double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
1604       double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
1605       aVal = Min(Min(L1,L2),Min(L3,L4));
1606     }
1607     break;
1608   case SMDSEntity_Tetra:
1609     if (len == 4){ // tetrahedra
1610       double L1 = getDistance(P( 1 ),P( 2 ));
1611       double L2 = getDistance(P( 2 ),P( 3 ));
1612       double L3 = getDistance(P( 3 ),P( 1 ));
1613       double L4 = getDistance(P( 1 ),P( 4 ));
1614       double L5 = getDistance(P( 2 ),P( 4 ));
1615       double L6 = getDistance(P( 3 ),P( 4 ));
1616       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1617     }
1618     break;
1619   case SMDSEntity_Pyramid:
1620     if (len == 5){ // pyramid
1621       double L1 = getDistance(P( 1 ),P( 2 ));
1622       double L2 = getDistance(P( 2 ),P( 3 ));
1623       double L3 = getDistance(P( 3 ),P( 4 ));
1624       double L4 = getDistance(P( 4 ),P( 1 ));
1625       double L5 = getDistance(P( 1 ),P( 5 ));
1626       double L6 = getDistance(P( 2 ),P( 5 ));
1627       double L7 = getDistance(P( 3 ),P( 5 ));
1628       double L8 = getDistance(P( 4 ),P( 5 ));
1629
1630       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1631       aVal = Min(aVal,Min(L7,L8));
1632     }
1633     break;
1634   case SMDSEntity_Penta:
1635     if (len == 6) { // pentahedron
1636       double L1 = getDistance(P( 1 ),P( 2 ));
1637       double L2 = getDistance(P( 2 ),P( 3 ));
1638       double L3 = getDistance(P( 3 ),P( 1 ));
1639       double L4 = getDistance(P( 4 ),P( 5 ));
1640       double L5 = getDistance(P( 5 ),P( 6 ));
1641       double L6 = getDistance(P( 6 ),P( 4 ));
1642       double L7 = getDistance(P( 1 ),P( 4 ));
1643       double L8 = getDistance(P( 2 ),P( 5 ));
1644       double L9 = getDistance(P( 3 ),P( 6 ));
1645
1646       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1647       aVal = Min(aVal,Min(Min(L7,L8),L9));
1648     }
1649     break;
1650   case SMDSEntity_Hexa:
1651     if (len == 8){ // hexahedron
1652       double L1 = getDistance(P( 1 ),P( 2 ));
1653       double L2 = getDistance(P( 2 ),P( 3 ));
1654       double L3 = getDistance(P( 3 ),P( 4 ));
1655       double L4 = getDistance(P( 4 ),P( 1 ));
1656       double L5 = getDistance(P( 5 ),P( 6 ));
1657       double L6 = getDistance(P( 6 ),P( 7 ));
1658       double L7 = getDistance(P( 7 ),P( 8 ));
1659       double L8 = getDistance(P( 8 ),P( 5 ));
1660       double L9 = getDistance(P( 1 ),P( 5 ));
1661       double L10= getDistance(P( 2 ),P( 6 ));
1662       double L11= getDistance(P( 3 ),P( 7 ));
1663       double L12= getDistance(P( 4 ),P( 8 ));
1664
1665       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1666       aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1667       aVal = Min(aVal,Min(L11,L12));
1668     }
1669     break;
1670   case SMDSEntity_Quad_Tetra:
1671     if (len == 10){ // quadratic tetrahedron
1672       double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
1673       double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
1674       double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
1675       double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1676       double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
1677       double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
1678       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1679     }
1680     break;
1681   case SMDSEntity_Quad_Pyramid:
1682     if (len == 13){ // quadratic pyramid
1683       double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
1684       double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
1685       double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1686       double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1687       double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1688       double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
1689       double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
1690       double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
1691       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1692       aVal = Min(aVal,Min(L7,L8));
1693     }
1694     break;
1695   case SMDSEntity_Quad_Penta:
1696     //case SMDSEntity_BiQuad_Penta:
1697     if (len >= 15){ // quadratic pentahedron
1698       double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
1699       double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
1700       double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1701       double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1702       double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
1703       double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
1704       double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
1705       double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
1706       double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
1707       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1708       aVal = Min(aVal,Min(Min(L7,L8),L9));
1709     }
1710     break;
1711   case SMDSEntity_Quad_Hexa:
1712   case SMDSEntity_TriQuad_Hexa:
1713     if (len >= 20) { // quadratic hexahedron
1714       double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
1715       double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
1716       double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
1717       double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
1718       double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
1719       double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
1720       double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
1721       double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
1722       double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
1723       double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
1724       double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
1725       double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
1726       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1727       aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1728       aVal = Min(aVal,Min(L11,L12));
1729     }
1730     break;
1731   case SMDSEntity_Polygon:
1732     if ( len > 1 ) {
1733       aVal = getDistance( P(1), P( P.size() ));
1734       for ( size_t i = 1; i < P.size(); ++i )
1735         aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
1736     }
1737     break;
1738   case SMDSEntity_Quad_Polygon:
1739     if ( len > 2 ) {
1740       aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
1741       for ( size_t i = 1; i < P.size()-1; i += 2 )
1742         aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
1743     }
1744     break;
1745   case SMDSEntity_Hexagonal_Prism:
1746     if (len == 12) { // hexagonal prism
1747       double L1 = getDistance(P( 1 ),P( 2 ));
1748       double L2 = getDistance(P( 2 ),P( 3 ));
1749       double L3 = getDistance(P( 3 ),P( 4 ));
1750       double L4 = getDistance(P( 4 ),P( 5 ));
1751       double L5 = getDistance(P( 5 ),P( 6 ));
1752       double L6 = getDistance(P( 6 ),P( 1 ));
1753
1754       double L7 = getDistance(P( 7 ), P( 8 ));
1755       double L8 = getDistance(P( 8 ), P( 9 ));
1756       double L9 = getDistance(P( 9 ), P( 10 ));
1757       double L10= getDistance(P( 10 ),P( 11 ));
1758       double L11= getDistance(P( 11 ),P( 12 ));
1759       double L12= getDistance(P( 12 ),P( 7 ));
1760
1761       double L13 = getDistance(P( 1 ),P( 7 ));
1762       double L14 = getDistance(P( 2 ),P( 8 ));
1763       double L15 = getDistance(P( 3 ),P( 9 ));
1764       double L16 = getDistance(P( 4 ),P( 10 ));
1765       double L17 = getDistance(P( 5 ),P( 11 ));
1766       double L18 = getDistance(P( 6 ),P( 12 ));
1767       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1768       aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
1769       aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
1770     }
1771     break;
1772   case SMDSEntity_Polyhedra:
1773   {
1774   }
1775   break;
1776   default:
1777     return 0;
1778   }
1779
1780   if (aVal < 0 ) {
1781     return 0.;
1782   }
1783
1784   if ( myPrecision >= 0 )
1785   {
1786     double prec = pow( 10., (double)( myPrecision ) );
1787     aVal = floor( aVal * prec + 0.5 ) / prec;
1788   }
1789
1790   return aVal;
1791 }
1792
1793 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1794 {
1795   // meaningless as it is not a quality control functor
1796   return Value;
1797 }
1798
1799 SMDSAbs_ElementType Length2D::GetType() const
1800 {
1801   return SMDSAbs_Face;
1802 }
1803
1804 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
1805   myLength(theLength)
1806 {
1807   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1808   if(thePntId1 > thePntId2){
1809     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1810   }
1811 }
1812
1813 bool Length2D::Value::operator<(const Length2D::Value& x) const
1814 {
1815   if(myPntId[0] < x.myPntId[0]) return true;
1816   if(myPntId[0] == x.myPntId[0])
1817     if(myPntId[1] < x.myPntId[1]) return true;
1818   return false;
1819 }
1820
1821 void Length2D::GetValues(TValues& theValues)
1822 {
1823   TValues aValues;
1824   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1825   for(; anIter->more(); ){
1826     const SMDS_MeshFace* anElem = anIter->next();
1827
1828     if(anElem->IsQuadratic()) {
1829       const SMDS_VtkFace* F =
1830         dynamic_cast<const SMDS_VtkFace*>(anElem);
1831       // use special nodes iterator
1832       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
1833       long aNodeId[4] = { 0,0,0,0 };
1834       gp_Pnt P[4];
1835
1836       double aLength = 0;
1837       const SMDS_MeshElement* aNode;
1838       if(anIter->more()){
1839         aNode = anIter->next();
1840         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1841         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1842         aNodeId[0] = aNodeId[1] = aNode->GetID();
1843         aLength = 0;
1844       }
1845       for(; anIter->more(); ){
1846         const SMDS_MeshNode* N1 = static_cast<const SMDS_MeshNode*> (anIter->next());
1847         P[2] = gp_Pnt(N1->X(),N1->Y(),N1->Z());
1848         aNodeId[2] = N1->GetID();
1849         aLength = P[1].Distance(P[2]);
1850         if(!anIter->more()) break;
1851         const SMDS_MeshNode* N2 = static_cast<const SMDS_MeshNode*> (anIter->next());
1852         P[3] = gp_Pnt(N2->X(),N2->Y(),N2->Z());
1853         aNodeId[3] = N2->GetID();
1854         aLength += P[2].Distance(P[3]);
1855         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1856         Value aValue2(aLength,aNodeId[2],aNodeId[3]);
1857         P[1] = P[3];
1858         aNodeId[1] = aNodeId[3];
1859         theValues.insert(aValue1);
1860         theValues.insert(aValue2);
1861       }
1862       aLength += P[2].Distance(P[0]);
1863       Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1864       Value aValue2(aLength,aNodeId[2],aNodeId[0]);
1865       theValues.insert(aValue1);
1866       theValues.insert(aValue2);
1867     }
1868     else {
1869       SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
1870       long aNodeId[2] = {0,0};
1871       gp_Pnt P[3];
1872
1873       double aLength;
1874       const SMDS_MeshElement* aNode;
1875       if(aNodesIter->more()){
1876         aNode = aNodesIter->next();
1877         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1878         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1879         aNodeId[0] = aNodeId[1] = aNode->GetID();
1880         aLength = 0;
1881       }
1882       for(; aNodesIter->more(); ){
1883         aNode = aNodesIter->next();
1884         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
1885         long anId = aNode->GetID();
1886         
1887         P[2] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
1888         
1889         aLength = P[1].Distance(P[2]);
1890         
1891         Value aValue(aLength,aNodeId[1],anId);
1892         aNodeId[1] = anId;
1893         P[1] = P[2];
1894         theValues.insert(aValue);
1895       }
1896
1897       aLength = P[0].Distance(P[1]);
1898
1899       Value aValue(aLength,aNodeId[0],aNodeId[1]);
1900       theValues.insert(aValue);
1901     }
1902   }
1903 }
1904
1905 //================================================================================
1906 /*
1907   Class       : Deflection2D
1908   Description : Functor for calculating number of faces conneted to the edge
1909 */
1910 //================================================================================
1911
1912 double Deflection2D::GetValue( const TSequenceOfXYZ& P )
1913 {
1914   if ( myMesh && P.getElement() )
1915   {
1916     // get underlying surface
1917     if ( myShapeIndex != P.getElement()->getshapeId() )
1918     {
1919       mySurface.Nullify();
1920       myShapeIndex = P.getElement()->getshapeId();
1921       const TopoDS_Shape& S =
1922         static_cast< const SMESHDS_Mesh* >( myMesh )->IndexToShape( myShapeIndex );
1923       if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
1924       {
1925         mySurface = new ShapeAnalysis_Surface( BRep_Tool::Surface( TopoDS::Face( S )));
1926
1927         GeomLib_IsPlanarSurface isPlaneCheck( mySurface->Surface() );
1928         if ( isPlaneCheck.IsPlanar() )
1929           myPlane.reset( new gp_Pln( isPlaneCheck.Plan() ));
1930         else
1931           myPlane.reset();
1932       }
1933     }
1934     // project gravity center to the surface
1935     if ( !mySurface.IsNull() )
1936     {
1937       gp_XYZ gc(0,0,0);
1938       gp_XY  uv(0,0);
1939       int nbUV = 0;
1940       for ( size_t i = 0; i < P.size(); ++i )
1941       {
1942         gc += P(i+1);
1943
1944         if ( const SMDS_FacePosition* fPos = dynamic_cast<const SMDS_FacePosition*>
1945              ( P.getElement()->GetNode( i )->GetPosition() ))
1946         {
1947           uv.ChangeCoord(1) += fPos->GetUParameter();
1948           uv.ChangeCoord(2) += fPos->GetVParameter();
1949           ++nbUV;
1950         }
1951       }
1952       gc /= P.size();
1953       if ( nbUV ) uv /= nbUV;
1954
1955       double maxLen = MaxElementLength2D().GetValue( P );
1956       double    tol = 1e-3 * maxLen;
1957       double dist;
1958       if ( myPlane )
1959       {
1960         dist = myPlane->Distance( gc );
1961         if ( dist < tol )
1962           dist = 0;
1963       }
1964       else
1965       {
1966         if ( uv.X() != 0 && uv.Y() != 0 ) // faster way
1967           mySurface->NextValueOfUV( uv, gc, tol, 0.5 * maxLen );
1968         else
1969           mySurface->ValueOfUV( gc, tol );
1970         dist = mySurface->Gap();
1971       }
1972       return Round( dist );
1973     }
1974   }
1975   return 0;
1976 }
1977
1978 void Deflection2D::SetMesh( const SMDS_Mesh* theMesh )
1979 {
1980   NumericalFunctor::SetMesh( dynamic_cast<const SMESHDS_Mesh* >( theMesh ));
1981   myShapeIndex = -100;
1982   myPlane.reset();
1983 }
1984
1985 SMDSAbs_ElementType Deflection2D::GetType() const
1986 {
1987   return SMDSAbs_Face;
1988 }
1989
1990 double Deflection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1991 {
1992   // meaningless as it is not quality control functor
1993   return Value;
1994 }
1995
1996 //================================================================================
1997 /*
1998   Class       : MultiConnection
1999   Description : Functor for calculating number of faces conneted to the edge
2000 */
2001 //================================================================================
2002
2003 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
2004 {
2005   return 0;
2006 }
2007 double MultiConnection::GetValue( long theId )
2008 {
2009   return getNbMultiConnection( myMesh, theId );
2010 }
2011
2012 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
2013 {
2014   // meaningless as it is not quality control functor
2015   return Value;
2016 }
2017
2018 SMDSAbs_ElementType MultiConnection::GetType() const
2019 {
2020   return SMDSAbs_Edge;
2021 }
2022
2023 //================================================================================
2024 /*
2025   Class       : MultiConnection2D
2026   Description : Functor for calculating number of faces conneted to the edge
2027 */
2028 //================================================================================
2029
2030 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
2031 {
2032   return 0;
2033 }
2034
2035 double MultiConnection2D::GetValue( long theElementId )
2036 {
2037   int aResult = 0;
2038
2039   const SMDS_MeshElement* aFaceElem = myMesh->FindElement(theElementId);
2040   SMDSAbs_ElementType aType = aFaceElem->GetType();
2041
2042   switch (aType) {
2043   case SMDSAbs_Face:
2044     {
2045       int i = 0, len = aFaceElem->NbNodes();
2046       SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
2047       if (!anIter) break;
2048
2049       const SMDS_MeshNode *aNode, *aNode0 = 0;
2050       TColStd_MapOfInteger aMap, aMapPrev;
2051
2052       for (i = 0; i <= len; i++) {
2053         aMapPrev = aMap;
2054         aMap.Clear();
2055
2056         int aNb = 0;
2057         if (anIter->more()) {
2058           aNode = (SMDS_MeshNode*)anIter->next();
2059         } else {
2060           if (i == len)
2061             aNode = aNode0;
2062           else
2063             break;
2064         }
2065         if (!aNode) break;
2066         if (i == 0) aNode0 = aNode;
2067
2068         SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
2069         while (anElemIter->more()) {
2070           const SMDS_MeshElement* anElem = anElemIter->next();
2071           if (anElem != 0 && anElem->GetType() == SMDSAbs_Face) {
2072             int anId = anElem->GetID();
2073
2074             aMap.Add(anId);
2075             if (aMapPrev.Contains(anId)) {
2076               aNb++;
2077             }
2078           }
2079         }
2080         aResult = Max(aResult, aNb);
2081       }
2082     }
2083     break;
2084   default:
2085     aResult = 0;
2086   }
2087
2088   return aResult;
2089 }
2090
2091 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2092 {
2093   // meaningless as it is not quality control functor
2094   return Value;
2095 }
2096
2097 SMDSAbs_ElementType MultiConnection2D::GetType() const
2098 {
2099   return SMDSAbs_Face;
2100 }
2101
2102 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
2103 {
2104   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
2105   if(thePntId1 > thePntId2){
2106     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
2107   }
2108 }
2109
2110 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const
2111 {
2112   if(myPntId[0] < x.myPntId[0]) return true;
2113   if(myPntId[0] == x.myPntId[0])
2114     if(myPntId[1] < x.myPntId[1]) return true;
2115   return false;
2116 }
2117
2118 void MultiConnection2D::GetValues(MValues& theValues)
2119 {
2120   if ( !myMesh ) return;
2121   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
2122   for(; anIter->more(); ){
2123     const SMDS_MeshFace* anElem = anIter->next();
2124     SMDS_ElemIteratorPtr aNodesIter;
2125     if ( anElem->IsQuadratic() )
2126       aNodesIter = dynamic_cast<const SMDS_VtkFace*>
2127         (anElem)->interlacedNodesElemIterator();
2128     else
2129       aNodesIter = anElem->nodesIterator();
2130     long aNodeId[3] = {0,0,0};
2131
2132     //int aNbConnects=0;
2133     const SMDS_MeshNode* aNode0;
2134     const SMDS_MeshNode* aNode1;
2135     const SMDS_MeshNode* aNode2;
2136     if(aNodesIter->more()){
2137       aNode0 = (SMDS_MeshNode*) aNodesIter->next();
2138       aNode1 = aNode0;
2139       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode1;
2140       aNodeId[0] = aNodeId[1] = aNodes->GetID();
2141     }
2142     for(; aNodesIter->more(); ) {
2143       aNode2 = (SMDS_MeshNode*) aNodesIter->next();
2144       long anId = aNode2->GetID();
2145       aNodeId[2] = anId;
2146
2147       Value aValue(aNodeId[1],aNodeId[2]);
2148       MValues::iterator aItr = theValues.find(aValue);
2149       if (aItr != theValues.end()){
2150         aItr->second += 1;
2151         //aNbConnects = nb;
2152       }
2153       else {
2154         theValues[aValue] = 1;
2155         //aNbConnects = 1;
2156       }
2157       //cout << "NodeIds: "<<aNodeId[1]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
2158       aNodeId[1] = aNodeId[2];
2159       aNode1 = aNode2;
2160     }
2161     Value aValue(aNodeId[0],aNodeId[2]);
2162     MValues::iterator aItr = theValues.find(aValue);
2163     if (aItr != theValues.end()) {
2164       aItr->second += 1;
2165       //aNbConnects = nb;
2166     }
2167     else {
2168       theValues[aValue] = 1;
2169       //aNbConnects = 1;
2170     }
2171     //cout << "NodeIds: "<<aNodeId[0]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
2172   }
2173
2174 }
2175
2176 //================================================================================
2177 /*
2178   Class       : BallDiameter
2179   Description : Functor returning diameter of a ball element
2180 */
2181 //================================================================================
2182
2183 double BallDiameter::GetValue( long theId )
2184 {
2185   double diameter = 0;
2186
2187   if ( const SMDS_BallElement* ball =
2188        dynamic_cast<const SMDS_BallElement*>( myMesh->FindElement( theId )))
2189   {
2190     diameter = ball->GetDiameter();
2191   }
2192   return diameter;
2193 }
2194
2195 double BallDiameter::GetBadRate( double Value, int /*nbNodes*/ ) const
2196 {
2197   // meaningless as it is not a quality control functor
2198   return Value;
2199 }
2200
2201 SMDSAbs_ElementType BallDiameter::GetType() const
2202 {
2203   return SMDSAbs_Ball;
2204 }
2205
2206 //================================================================================
2207 /*
2208   Class       : NodeConnectivityNumber
2209   Description : Functor returning number of elements connected to a node
2210 */
2211 //================================================================================
2212
2213 double NodeConnectivityNumber::GetValue( long theId )
2214 {
2215   double nb = 0;
2216
2217   if ( const SMDS_MeshNode* node = myMesh->FindNode( theId ))
2218   {
2219     SMDSAbs_ElementType type;
2220     if ( myMesh->NbVolumes() > 0 )
2221       type = SMDSAbs_Volume;
2222     else if ( myMesh->NbFaces() > 0 )
2223       type = SMDSAbs_Face;
2224     else if ( myMesh->NbEdges() > 0 )
2225       type = SMDSAbs_Edge;
2226     else
2227       return 0;
2228     nb = node->NbInverseElements( type );
2229   }
2230   return nb;
2231 }
2232
2233 double NodeConnectivityNumber::GetBadRate( double Value, int /*nbNodes*/ ) const
2234 {
2235   return Value;
2236 }
2237
2238 SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
2239 {
2240   return SMDSAbs_Node;
2241 }
2242
2243 /*
2244                             PREDICATES
2245 */
2246
2247 //================================================================================
2248 /*
2249   Class       : BadOrientedVolume
2250   Description : Predicate bad oriented volumes
2251 */
2252 //================================================================================
2253
2254 BadOrientedVolume::BadOrientedVolume()
2255 {
2256   myMesh = 0;
2257 }
2258
2259 void BadOrientedVolume::SetMesh( const SMDS_Mesh* theMesh )
2260 {
2261   myMesh = theMesh;
2262 }
2263
2264 bool BadOrientedVolume::IsSatisfy( long theId )
2265 {
2266   if ( myMesh == 0 )
2267     return false;
2268
2269   SMDS_VolumeTool vTool( myMesh->FindElement( theId ));
2270   return !vTool.IsForward();
2271 }
2272
2273 SMDSAbs_ElementType BadOrientedVolume::GetType() const
2274 {
2275   return SMDSAbs_Volume;
2276 }
2277
2278 /*
2279   Class       : BareBorderVolume
2280 */
2281
2282 bool BareBorderVolume::IsSatisfy(long theElementId )
2283 {
2284   SMDS_VolumeTool  myTool;
2285   if ( myTool.Set( myMesh->FindElement(theElementId)))
2286   {
2287     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
2288       if ( myTool.IsFreeFace( iF ))
2289       {
2290         const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
2291         std::vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF));
2292         if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
2293           return true;
2294       }
2295   }
2296   return false;
2297 }
2298
2299 //================================================================================
2300 /*
2301   Class       : BareBorderFace
2302 */
2303 //================================================================================
2304
2305 bool BareBorderFace::IsSatisfy(long theElementId )
2306 {
2307   bool ok = false;
2308   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
2309   {
2310     if ( face->GetType() == SMDSAbs_Face )
2311     {
2312       int nbN = face->NbCornerNodes();
2313       for ( int i = 0; i < nbN && !ok; ++i )
2314       {
2315         // check if a link is shared by another face
2316         const SMDS_MeshNode* n1 = face->GetNode( i );
2317         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
2318         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
2319         bool isShared = false;
2320         while ( !isShared && fIt->more() )
2321         {
2322           const SMDS_MeshElement* f = fIt->next();
2323           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
2324         }
2325         if ( !isShared )
2326         {
2327           const int iQuad = face->IsQuadratic();
2328           myLinkNodes.resize( 2 + iQuad);
2329           myLinkNodes[0] = n1;
2330           myLinkNodes[1] = n2;
2331           if ( iQuad )
2332             myLinkNodes[2] = face->GetNode( i+nbN );
2333           ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false);
2334         }
2335       }
2336     }
2337   }
2338   return ok;
2339 }
2340
2341 //================================================================================
2342 /*
2343   Class       : OverConstrainedVolume
2344 */
2345 //================================================================================
2346
2347 bool OverConstrainedVolume::IsSatisfy(long theElementId )
2348 {
2349   // An element is over-constrained if it has N-1 free borders where
2350   // N is the number of edges/faces for a 2D/3D element.
2351   SMDS_VolumeTool  myTool;
2352   if ( myTool.Set( myMesh->FindElement(theElementId)))
2353   {
2354     int nbSharedFaces = 0;
2355     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
2356       if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 )
2357         break;
2358     return ( nbSharedFaces == 1 );
2359   }
2360   return false;
2361 }
2362
2363 //================================================================================
2364 /*
2365   Class       : OverConstrainedFace
2366 */
2367 //================================================================================
2368
2369 bool OverConstrainedFace::IsSatisfy(long theElementId )
2370 {
2371   // An element is over-constrained if it has N-1 free borders where
2372   // N is the number of edges/faces for a 2D/3D element.
2373   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
2374     if ( face->GetType() == SMDSAbs_Face )
2375     {
2376       int nbSharedBorders = 0;
2377       int nbN = face->NbCornerNodes();
2378       for ( int i = 0; i < nbN; ++i )
2379       {
2380         // check if a link is shared by another face
2381         const SMDS_MeshNode* n1 = face->GetNode( i );
2382         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
2383         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
2384         bool isShared = false;
2385         while ( !isShared && fIt->more() )
2386         {
2387           const SMDS_MeshElement* f = fIt->next();
2388           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
2389         }
2390         if ( isShared && ++nbSharedBorders > 1 )
2391           break;
2392       }
2393       return ( nbSharedBorders == 1 );
2394     }
2395   return false;
2396 }
2397
2398 //================================================================================
2399 /*
2400   Class       : CoincidentNodes
2401   Description : Predicate of Coincident nodes
2402 */
2403 //================================================================================
2404
2405 CoincidentNodes::CoincidentNodes()
2406 {
2407   myToler = 1e-5;
2408 }
2409
2410 bool CoincidentNodes::IsSatisfy( long theElementId )
2411 {
2412   return myCoincidentIDs.Contains( theElementId );
2413 }
2414
2415 SMDSAbs_ElementType CoincidentNodes::GetType() const
2416 {
2417   return SMDSAbs_Node;
2418 }
2419
2420 void CoincidentNodes::SetMesh( const SMDS_Mesh* theMesh )
2421 {
2422   myMeshModifTracer.SetMesh( theMesh );
2423   if ( myMeshModifTracer.IsMeshModified() )
2424   {
2425     TIDSortedNodeSet nodesToCheck;
2426     SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
2427     while ( nIt->more() )
2428       nodesToCheck.insert( nodesToCheck.end(), nIt->next() );
2429
2430     std::list< std::list< const SMDS_MeshNode*> > nodeGroups;
2431     SMESH_OctreeNode::FindCoincidentNodes ( nodesToCheck, &nodeGroups, myToler );
2432
2433     myCoincidentIDs.Clear();
2434     std::list< std::list< const SMDS_MeshNode*> >::iterator groupIt = nodeGroups.begin();
2435     for ( ; groupIt != nodeGroups.end(); ++groupIt )
2436     {
2437       std::list< const SMDS_MeshNode*>& coincNodes = *groupIt;
2438       std::list< const SMDS_MeshNode*>::iterator n = coincNodes.begin();
2439       for ( ; n != coincNodes.end(); ++n )
2440         myCoincidentIDs.Add( (*n)->GetID() );
2441     }
2442   }
2443 }
2444
2445 //================================================================================
2446 /*
2447   Class       : CoincidentElements
2448   Description : Predicate of Coincident Elements
2449   Note        : This class is suitable only for visualization of Coincident Elements
2450 */
2451 //================================================================================
2452
2453 CoincidentElements::CoincidentElements()
2454 {
2455   myMesh = 0;
2456 }
2457
2458 void CoincidentElements::SetMesh( const SMDS_Mesh* theMesh )
2459 {
2460   myMesh = theMesh;
2461 }
2462
2463 bool CoincidentElements::IsSatisfy( long theElementId )
2464 {
2465   if ( !myMesh ) return false;
2466
2467   if ( const SMDS_MeshElement* e = myMesh->FindElement( theElementId ))
2468   {
2469     if ( e->GetType() != GetType() ) return false;
2470     std::set< const SMDS_MeshNode* > elemNodes( e->begin_nodes(), e->end_nodes() );
2471     const int nbNodes = e->NbNodes();
2472     SMDS_ElemIteratorPtr invIt = (*elemNodes.begin())->GetInverseElementIterator( GetType() );
2473     while ( invIt->more() )
2474     {
2475       const SMDS_MeshElement* e2 = invIt->next();
2476       if ( e2 == e || e2->NbNodes() != nbNodes ) continue;
2477
2478       bool sameNodes = true;
2479       for ( size_t i = 0; i < elemNodes.size() && sameNodes; ++i )
2480         sameNodes = ( elemNodes.count( e2->GetNode( i )));
2481       if ( sameNodes )
2482         return true;
2483     }
2484   }
2485   return false;
2486 }
2487
2488 SMDSAbs_ElementType CoincidentElements1D::GetType() const
2489 {
2490   return SMDSAbs_Edge;
2491 }
2492 SMDSAbs_ElementType CoincidentElements2D::GetType() const
2493 {
2494   return SMDSAbs_Face;
2495 }
2496 SMDSAbs_ElementType CoincidentElements3D::GetType() const
2497 {
2498   return SMDSAbs_Volume;
2499 }
2500
2501
2502 //================================================================================
2503 /*
2504   Class       : FreeBorders
2505   Description : Predicate for free borders
2506 */
2507 //================================================================================
2508
2509 FreeBorders::FreeBorders()
2510 {
2511   myMesh = 0;
2512 }
2513
2514 void FreeBorders::SetMesh( const SMDS_Mesh* theMesh )
2515 {
2516   myMesh = theMesh;
2517 }
2518
2519 bool FreeBorders::IsSatisfy( long theId )
2520 {
2521   return getNbMultiConnection( myMesh, theId ) == 1;
2522 }
2523
2524 SMDSAbs_ElementType FreeBorders::GetType() const
2525 {
2526   return SMDSAbs_Edge;
2527 }
2528
2529
2530 //================================================================================
2531 /*
2532   Class       : FreeEdges
2533   Description : Predicate for free Edges
2534 */
2535 //================================================================================
2536
2537 FreeEdges::FreeEdges()
2538 {
2539   myMesh = 0;
2540 }
2541
2542 void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
2543 {
2544   myMesh = theMesh;
2545 }
2546
2547 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
2548 {
2549   TColStd_MapOfInteger aMap;
2550   for ( int i = 0; i < 2; i++ )
2551   {
2552     SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator(SMDSAbs_Face);
2553     while( anElemIter->more() )
2554     {
2555       if ( const SMDS_MeshElement* anElem = anElemIter->next())
2556       {
2557         const int anId = anElem->GetID();
2558         if ( anId != theFaceId && !aMap.Add( anId ))
2559           return false;
2560       }
2561     }
2562   }
2563   return true;
2564 }
2565
2566 bool FreeEdges::IsSatisfy( long theId )
2567 {
2568   if ( myMesh == 0 )
2569     return false;
2570
2571   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2572   if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
2573     return false;
2574
2575   SMDS_NodeIteratorPtr anIter = aFace->interlacedNodesIterator();
2576   if ( !anIter )
2577     return false;
2578
2579   int i = 0, nbNodes = aFace->NbNodes();
2580   std::vector <const SMDS_MeshNode*> aNodes( nbNodes+1 );
2581   while( anIter->more() )
2582     if ( ! ( aNodes[ i++ ] = anIter->next() ))
2583       return false;
2584   aNodes[ nbNodes ] = aNodes[ 0 ];
2585
2586   for ( i = 0; i < nbNodes; i++ )
2587     if ( IsFreeEdge( &aNodes[ i ], theId ) )
2588       return true;
2589
2590   return false;
2591 }
2592
2593 SMDSAbs_ElementType FreeEdges::GetType() const
2594 {
2595   return SMDSAbs_Face;
2596 }
2597
2598 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
2599   myElemId(theElemId)
2600 {
2601   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
2602   if(thePntId1 > thePntId2){
2603     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
2604   }
2605 }
2606
2607 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
2608   if(myPntId[0] < x.myPntId[0]) return true;
2609   if(myPntId[0] == x.myPntId[0])
2610     if(myPntId[1] < x.myPntId[1]) return true;
2611   return false;
2612 }
2613
2614 inline void UpdateBorders(const FreeEdges::Border& theBorder,
2615                           FreeEdges::TBorders& theRegistry,
2616                           FreeEdges::TBorders& theContainer)
2617 {
2618   if(theRegistry.find(theBorder) == theRegistry.end()){
2619     theRegistry.insert(theBorder);
2620     theContainer.insert(theBorder);
2621   }else{
2622     theContainer.erase(theBorder);
2623   }
2624 }
2625
2626 void FreeEdges::GetBoreders(TBorders& theBorders)
2627 {
2628   TBorders aRegistry;
2629   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
2630   for(; anIter->more(); ){
2631     const SMDS_MeshFace* anElem = anIter->next();
2632     long anElemId = anElem->GetID();
2633     SMDS_ElemIteratorPtr aNodesIter;
2634     if ( anElem->IsQuadratic() )
2635       aNodesIter = static_cast<const SMDS_VtkFace*>(anElem)->
2636         interlacedNodesElemIterator();
2637     else
2638       aNodesIter = anElem->nodesIterator();
2639     long aNodeId[2] = {0,0};
2640     const SMDS_MeshElement* aNode;
2641     if(aNodesIter->more()){
2642       aNode = aNodesIter->next();
2643       aNodeId[0] = aNodeId[1] = aNode->GetID();
2644     }
2645     for(; aNodesIter->more(); ){
2646       aNode = aNodesIter->next();
2647       long anId = aNode->GetID();
2648       Border aBorder(anElemId,aNodeId[1],anId);
2649       aNodeId[1] = anId;
2650       UpdateBorders(aBorder,aRegistry,theBorders);
2651     }
2652     Border aBorder(anElemId,aNodeId[0],aNodeId[1]);
2653     UpdateBorders(aBorder,aRegistry,theBorders);
2654   }
2655 }
2656
2657 //================================================================================
2658 /*
2659   Class       : FreeNodes
2660   Description : Predicate for free nodes
2661 */
2662 //================================================================================
2663
2664 FreeNodes::FreeNodes()
2665 {
2666   myMesh = 0;
2667 }
2668
2669 void FreeNodes::SetMesh( const SMDS_Mesh* theMesh )
2670 {
2671   myMesh = theMesh;
2672 }
2673
2674 bool FreeNodes::IsSatisfy( long theNodeId )
2675 {
2676   const SMDS_MeshNode* aNode = myMesh->FindNode( theNodeId );
2677   if (!aNode)
2678     return false;
2679
2680   return (aNode->NbInverseElements() < 1);
2681 }
2682
2683 SMDSAbs_ElementType FreeNodes::GetType() const
2684 {
2685   return SMDSAbs_Node;
2686 }
2687
2688
2689 //================================================================================
2690 /*
2691   Class       : FreeFaces
2692   Description : Predicate for free faces
2693 */
2694 //================================================================================
2695
2696 FreeFaces::FreeFaces()
2697 {
2698   myMesh = 0;
2699 }
2700
2701 void FreeFaces::SetMesh( const SMDS_Mesh* theMesh )
2702 {
2703   myMesh = theMesh;
2704 }
2705
2706 bool FreeFaces::IsSatisfy( long theId )
2707 {
2708   if (!myMesh) return false;
2709   // check that faces nodes refers to less than two common volumes
2710   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2711   if ( !aFace || aFace->GetType() != SMDSAbs_Face )
2712     return false;
2713
2714   int nbNode = aFace->NbNodes();
2715
2716   // collect volumes to check that number of volumes with count equal nbNode not less than 2
2717   typedef std::map< SMDS_MeshElement*, int > TMapOfVolume; // map of volume counters
2718   typedef std::map< SMDS_MeshElement*, int >::iterator TItrMapOfVolume; // iterator
2719   TMapOfVolume mapOfVol;
2720
2721   SMDS_ElemIteratorPtr nodeItr = aFace->nodesIterator();
2722   while ( nodeItr->more() )
2723   {
2724     const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
2725     if ( !aNode ) continue;
2726     SMDS_ElemIteratorPtr volItr = aNode->GetInverseElementIterator(SMDSAbs_Volume);
2727     while ( volItr->more() )
2728     {
2729       SMDS_MeshElement* aVol = (SMDS_MeshElement*)volItr->next();
2730       TItrMapOfVolume    itr = mapOfVol.insert( std::make_pair( aVol, 0 )).first;
2731       (*itr).second++;
2732     } 
2733   }
2734   int nbVol = 0;
2735   TItrMapOfVolume volItr = mapOfVol.begin();
2736   TItrMapOfVolume volEnd = mapOfVol.end();
2737   for ( ; volItr != volEnd; ++volItr )
2738     if ( (*volItr).second >= nbNode )
2739        nbVol++;
2740   // face is not free if number of volumes constructed on their nodes more than one
2741   return (nbVol < 2);
2742 }
2743
2744 SMDSAbs_ElementType FreeFaces::GetType() const
2745 {
2746   return SMDSAbs_Face;
2747 }
2748
2749 //================================================================================
2750 /*
2751   Class       : LinearOrQuadratic
2752   Description : Predicate to verify whether a mesh element is linear
2753 */
2754 //================================================================================
2755
2756 LinearOrQuadratic::LinearOrQuadratic()
2757 {
2758   myMesh = 0;
2759 }
2760
2761 void LinearOrQuadratic::SetMesh( const SMDS_Mesh* theMesh )
2762 {
2763   myMesh = theMesh;
2764 }
2765
2766 bool LinearOrQuadratic::IsSatisfy( long theId )
2767 {
2768   if (!myMesh) return false;
2769   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2770   if ( !anElem || (myType != SMDSAbs_All && anElem->GetType() != myType) )
2771     return false;
2772   return (!anElem->IsQuadratic());
2773 }
2774
2775 void LinearOrQuadratic::SetType( SMDSAbs_ElementType theType )
2776 {
2777   myType = theType;
2778 }
2779
2780 SMDSAbs_ElementType LinearOrQuadratic::GetType() const
2781 {
2782   return myType;
2783 }
2784
2785 //================================================================================
2786 /*
2787   Class       : GroupColor
2788   Description : Functor for check color of group to which mesh element belongs to
2789 */
2790 //================================================================================
2791
2792 GroupColor::GroupColor()
2793 {
2794 }
2795
2796 bool GroupColor::IsSatisfy( long theId )
2797 {
2798   return myIDs.count( theId );
2799 }
2800
2801 void GroupColor::SetType( SMDSAbs_ElementType theType )
2802 {
2803   myType = theType;
2804 }
2805
2806 SMDSAbs_ElementType GroupColor::GetType() const
2807 {
2808   return myType;
2809 }
2810
2811 static bool isEqual( const Quantity_Color& theColor1,
2812                      const Quantity_Color& theColor2 )
2813 {
2814   // tolerance to compare colors
2815   const double tol = 5*1e-3;
2816   return ( fabs( theColor1.Red()   - theColor2.Red() )   < tol &&
2817            fabs( theColor1.Green() - theColor2.Green() ) < tol &&
2818            fabs( theColor1.Blue()  - theColor2.Blue() )  < tol );
2819 }
2820
2821 void GroupColor::SetMesh( const SMDS_Mesh* theMesh )
2822 {
2823   myIDs.clear();
2824
2825   const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
2826   if ( !aMesh )
2827     return;
2828
2829   int nbGrp = aMesh->GetNbGroups();
2830   if ( !nbGrp )
2831     return;
2832
2833   // iterates on groups and find necessary elements ids
2834   const std::set<SMESHDS_GroupBase*>&       aGroups = aMesh->GetGroups();
2835   std::set<SMESHDS_GroupBase*>::const_iterator GrIt = aGroups.begin();
2836   for (; GrIt != aGroups.end(); GrIt++)
2837   {
2838     SMESHDS_GroupBase* aGrp = (*GrIt);
2839     if ( !aGrp )
2840       continue;
2841     // check type and color of group
2842     if ( !isEqual( myColor, aGrp->GetColor() ))
2843       continue;
2844
2845     // IPAL52867 (prevent infinite recursion via GroupOnFilter)
2846     if ( SMESHDS_GroupOnFilter * gof = dynamic_cast< SMESHDS_GroupOnFilter* >( aGrp ))
2847       if ( gof->GetPredicate().get() == this )
2848         continue;
2849
2850     SMDSAbs_ElementType aGrpElType = (SMDSAbs_ElementType)aGrp->GetType();
2851     if ( myType == aGrpElType || (myType == SMDSAbs_All && aGrpElType != SMDSAbs_Node) ) {
2852       // add elements IDS into control
2853       int aSize = aGrp->Extent();
2854       for (int i = 0; i < aSize; i++)
2855         myIDs.insert( aGrp->GetID(i+1) );
2856     }
2857   }
2858 }
2859
2860 void GroupColor::SetColorStr( const TCollection_AsciiString& theStr )
2861 {
2862   Kernel_Utils::Localizer loc;
2863   TCollection_AsciiString aStr = theStr;
2864   aStr.RemoveAll( ' ' );
2865   aStr.RemoveAll( '\t' );
2866   for ( int aPos = aStr.Search( ";;" ); aPos != -1; aPos = aStr.Search( ";;" ) )
2867     aStr.Remove( aPos, 2 );
2868   Standard_Real clr[3];
2869   clr[0] = clr[1] = clr[2] = 0.;
2870   for ( int i = 0; i < 3; i++ ) {
2871     TCollection_AsciiString tmpStr = aStr.Token( ";", i+1 );
2872     if ( !tmpStr.IsEmpty() && tmpStr.IsRealValue() )
2873       clr[i] = tmpStr.RealValue();
2874   }
2875   myColor = Quantity_Color( clr[0], clr[1], clr[2], Quantity_TOC_RGB );
2876 }
2877
2878 //=======================================================================
2879 // name    : GetRangeStr
2880 // Purpose : Get range as a string.
2881 //           Example: "1,2,3,50-60,63,67,70-"
2882 //=======================================================================
2883
2884 void GroupColor::GetColorStr( TCollection_AsciiString& theResStr ) const
2885 {
2886   theResStr.Clear();
2887   theResStr += TCollection_AsciiString( myColor.Red() );
2888   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Green() );
2889   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Blue() );
2890 }
2891
2892 //================================================================================
2893 /*
2894   Class       : ElemGeomType
2895   Description : Predicate to check element geometry type
2896 */
2897 //================================================================================
2898
2899 ElemGeomType::ElemGeomType()
2900 {
2901   myMesh = 0;
2902   myType = SMDSAbs_All;
2903   myGeomType = SMDSGeom_TRIANGLE;
2904 }
2905
2906 void ElemGeomType::SetMesh( const SMDS_Mesh* theMesh )
2907 {
2908   myMesh = theMesh;
2909 }
2910
2911 bool ElemGeomType::IsSatisfy( long theId )
2912 {
2913   if (!myMesh) return false;
2914   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2915   if ( !anElem )
2916     return false;
2917   const SMDSAbs_ElementType anElemType = anElem->GetType();
2918   if ( myType != SMDSAbs_All && anElemType != myType )
2919     return false;
2920   bool isOk = ( anElem->GetGeomType() == myGeomType );
2921   return isOk;
2922 }
2923
2924 void ElemGeomType::SetType( SMDSAbs_ElementType theType )
2925 {
2926   myType = theType;
2927 }
2928
2929 SMDSAbs_ElementType ElemGeomType::GetType() const
2930 {
2931   return myType;
2932 }
2933
2934 void ElemGeomType::SetGeomType( SMDSAbs_GeometryType theType )
2935 {
2936   myGeomType = theType;
2937 }
2938
2939 SMDSAbs_GeometryType ElemGeomType::GetGeomType() const
2940 {
2941   return myGeomType;
2942 }
2943
2944 //================================================================================
2945 /*
2946   Class       : ElemEntityType
2947   Description : Predicate to check element entity type
2948 */
2949 //================================================================================
2950
2951 ElemEntityType::ElemEntityType():
2952   myMesh( 0 ),
2953   myType( SMDSAbs_All ),
2954   myEntityType( SMDSEntity_0D )
2955 {
2956 }
2957
2958 void ElemEntityType::SetMesh( const SMDS_Mesh* theMesh )
2959 {
2960   myMesh = theMesh;
2961 }
2962
2963 bool ElemEntityType::IsSatisfy( long theId )
2964 {
2965   if ( !myMesh ) return false;
2966   if ( myType == SMDSAbs_Node )
2967     return myMesh->FindNode( theId );
2968   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2969   return ( anElem &&
2970            myEntityType == anElem->GetEntityType() );
2971 }
2972
2973 void ElemEntityType::SetType( SMDSAbs_ElementType theType )
2974 {
2975   myType = theType;
2976 }
2977
2978 SMDSAbs_ElementType ElemEntityType::GetType() const
2979 {
2980   return myType;
2981 }
2982
2983 void ElemEntityType::SetElemEntityType( SMDSAbs_EntityType theEntityType )
2984 {
2985   myEntityType = theEntityType;
2986 }
2987
2988 SMDSAbs_EntityType ElemEntityType::GetElemEntityType() const
2989 {
2990   return myEntityType;
2991 }
2992
2993 //================================================================================
2994 /*!
2995  * \brief Class ConnectedElements
2996  */
2997 //================================================================================
2998
2999 ConnectedElements::ConnectedElements():
3000   myNodeID(0), myType( SMDSAbs_All ), myOkIDsReady( false ) {}
3001
3002 SMDSAbs_ElementType ConnectedElements::GetType() const
3003 { return myType; }
3004
3005 int ConnectedElements::GetNode() const
3006 { return myXYZ.empty() ? myNodeID : 0; } // myNodeID can be found by myXYZ
3007
3008 std::vector<double> ConnectedElements::GetPoint() const
3009 { return myXYZ; }
3010
3011 void ConnectedElements::clearOkIDs()
3012 { myOkIDsReady = false; myOkIDs.clear(); }
3013
3014 void ConnectedElements::SetType( SMDSAbs_ElementType theType )
3015 {
3016   if ( myType != theType || myMeshModifTracer.IsMeshModified() )
3017     clearOkIDs();
3018   myType = theType;
3019 }
3020
3021 void ConnectedElements::SetMesh( const SMDS_Mesh* theMesh )
3022 {
3023   myMeshModifTracer.SetMesh( theMesh );
3024   if ( myMeshModifTracer.IsMeshModified() )
3025   {
3026     clearOkIDs();
3027     if ( !myXYZ.empty() )
3028       SetPoint( myXYZ[0], myXYZ[1], myXYZ[2] ); // find a node near myXYZ it in a new mesh
3029   }
3030 }
3031
3032 void ConnectedElements::SetNode( int nodeID )
3033 {
3034   myNodeID = nodeID;
3035   myXYZ.clear();
3036
3037   bool isSameDomain = false;
3038   if ( myOkIDsReady && myMeshModifTracer.GetMesh() && !myMeshModifTracer.IsMeshModified() )
3039     if ( const SMDS_MeshNode* n = myMeshModifTracer.GetMesh()->FindNode( myNodeID ))
3040     {
3041       SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( myType );
3042       while ( !isSameDomain && eIt->more() )
3043         isSameDomain = IsSatisfy( eIt->next()->GetID() );
3044     }
3045   if ( !isSameDomain )
3046     clearOkIDs();
3047 }
3048
3049 void ConnectedElements::SetPoint( double x, double y, double z )
3050 {
3051   myXYZ.resize(3);
3052   myXYZ[0] = x;
3053   myXYZ[1] = y;
3054   myXYZ[2] = z;
3055   myNodeID = 0;
3056
3057   bool isSameDomain = false;
3058
3059   // find myNodeID by myXYZ if possible
3060   if ( myMeshModifTracer.GetMesh() )
3061   {
3062     SMESHUtils::Deleter<SMESH_ElementSearcher> searcher
3063       ( SMESH_MeshAlgos::GetElementSearcher( (SMDS_Mesh&) *myMeshModifTracer.GetMesh() ));
3064
3065     std::vector< const SMDS_MeshElement* > foundElems;
3066     searcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_All, foundElems );
3067
3068     if ( !foundElems.empty() )
3069     {
3070       myNodeID = foundElems[0]->GetNode(0)->GetID();
3071       if ( myOkIDsReady && !myMeshModifTracer.IsMeshModified() )
3072         isSameDomain = IsSatisfy( foundElems[0]->GetID() );
3073     }
3074   }
3075   if ( !isSameDomain )
3076     clearOkIDs();
3077 }
3078
3079 bool ConnectedElements::IsSatisfy( long theElementId )
3080 {
3081   // Here we do NOT check if the mesh has changed, we do it in Set...() only!!!
3082
3083   if ( !myOkIDsReady )
3084   {
3085     if ( !myMeshModifTracer.GetMesh() )
3086       return false;
3087     const SMDS_MeshNode* node0 = myMeshModifTracer.GetMesh()->FindNode( myNodeID );
3088     if ( !node0 )
3089       return false;
3090
3091     std::list< const SMDS_MeshNode* > nodeQueue( 1, node0 );
3092     std::set< int > checkedNodeIDs;
3093     // algo:
3094     // foreach node in nodeQueue:
3095     //   foreach element sharing a node:
3096     //     add ID of an element of myType to myOkIDs;
3097     //     push all element nodes absent from checkedNodeIDs to nodeQueue;
3098     while ( !nodeQueue.empty() )
3099     {
3100       const SMDS_MeshNode* node = nodeQueue.front();
3101       nodeQueue.pop_front();
3102
3103       // loop on elements sharing the node
3104       SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3105       while ( eIt->more() )
3106       {
3107         // keep elements of myType
3108         const SMDS_MeshElement* element = eIt->next();
3109         if ( element->GetType() == myType )
3110           myOkIDs.insert( myOkIDs.end(), element->GetID() );
3111
3112         // enqueue nodes of the element
3113         SMDS_ElemIteratorPtr nIt = element->nodesIterator();
3114         while ( nIt->more() )
3115         {
3116           const SMDS_MeshNode* n = static_cast< const SMDS_MeshNode* >( nIt->next() );
3117           if ( checkedNodeIDs.insert( n->GetID() ).second )
3118             nodeQueue.push_back( n );
3119         }
3120       }
3121     }
3122     if ( myType == SMDSAbs_Node )
3123       std::swap( myOkIDs, checkedNodeIDs );
3124
3125     size_t totalNbElems = myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType );
3126     if ( myOkIDs.size() == totalNbElems )
3127       myOkIDs.clear();
3128
3129     myOkIDsReady = true;
3130   }
3131
3132   return myOkIDs.empty() ? true : myOkIDs.count( theElementId );
3133 }
3134
3135 //================================================================================
3136 /*!
3137  * \brief Class CoplanarFaces
3138  */
3139 //================================================================================
3140
3141 namespace
3142 {
3143   inline bool isLessAngle( const gp_Vec& v1, const gp_Vec& v2, const double cos )
3144   {
3145     double dot = v1 * v2; // cos * |v1| * |v2|
3146     double l1  = v1.SquareMagnitude();
3147     double l2  = v2.SquareMagnitude();
3148     return (( dot * cos >= 0 ) && 
3149             ( dot * dot ) / l1 / l2 >= ( cos * cos ));
3150   }
3151 }
3152 CoplanarFaces::CoplanarFaces()
3153   : myFaceID(0), myToler(0)
3154 {
3155 }
3156 void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh )
3157 {
3158   myMeshModifTracer.SetMesh( theMesh );
3159   if ( myMeshModifTracer.IsMeshModified() )
3160   {
3161     // Build a set of coplanar face ids
3162
3163     myCoplanarIDs.Clear();
3164
3165     if ( !myMeshModifTracer.GetMesh() || !myFaceID || !myToler )
3166       return;
3167
3168     const SMDS_MeshElement* face = myMeshModifTracer.GetMesh()->FindElement( myFaceID );
3169     if ( !face || face->GetType() != SMDSAbs_Face )
3170       return;
3171
3172     bool normOK;
3173     gp_Vec myNorm = getNormale( static_cast<const SMDS_MeshFace*>(face), &normOK );
3174     if (!normOK)
3175       return;
3176
3177     const double cosTol = Cos( myToler * M_PI / 180. );
3178     NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks;
3179
3180     std::list< std::pair< const SMDS_MeshElement*, gp_Vec > > faceQueue;
3181     faceQueue.push_back( std::make_pair( face, myNorm ));
3182     while ( !faceQueue.empty() )
3183     {
3184       face   = faceQueue.front().first;
3185       myNorm = faceQueue.front().second;
3186       faceQueue.pop_front();
3187
3188       for ( int i = 0, nbN = face->NbCornerNodes(); i < nbN; ++i )
3189       {
3190         const SMDS_MeshNode*  n1 = face->GetNode( i );
3191         const SMDS_MeshNode*  n2 = face->GetNode(( i+1 )%nbN);
3192         if ( !checkedLinks.Add( SMESH_TLink( n1, n2 )))
3193           continue;
3194         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator(SMDSAbs_Face);
3195         while ( fIt->more() )
3196         {
3197           const SMDS_MeshElement* f = fIt->next();
3198           if ( f->GetNodeIndex( n2 ) > -1 )
3199           {
3200             gp_Vec norm = getNormale( static_cast<const SMDS_MeshFace*>(f), &normOK );
3201             if (!normOK || isLessAngle( myNorm, norm, cosTol))
3202             {
3203               myCoplanarIDs.Add( f->GetID() );
3204               faceQueue.push_back( std::make_pair( f, norm ));
3205             }
3206           }
3207         }
3208       }
3209     }
3210   }
3211 }
3212 bool CoplanarFaces::IsSatisfy( long theElementId )
3213 {
3214   return myCoplanarIDs.Contains( theElementId );
3215 }
3216
3217 /*
3218  *Class       : RangeOfIds
3219   *Description : Predicate for Range of Ids.
3220   *              Range may be specified with two ways.
3221   *              1. Using AddToRange method
3222   *              2. With SetRangeStr method. Parameter of this method is a string
3223   *                 like as "1,2,3,50-60,63,67,70-"
3224 */
3225
3226 //=======================================================================
3227 // name    : RangeOfIds
3228 // Purpose : Constructor
3229 //=======================================================================
3230 RangeOfIds::RangeOfIds()
3231 {
3232   myMesh = 0;
3233   myType = SMDSAbs_All;
3234 }
3235
3236 //=======================================================================
3237 // name    : SetMesh
3238 // Purpose : Set mesh
3239 //=======================================================================
3240 void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
3241 {
3242   myMesh = theMesh;
3243 }
3244
3245 //=======================================================================
3246 // name    : AddToRange
3247 // Purpose : Add ID to the range
3248 //=======================================================================
3249 bool RangeOfIds::AddToRange( long theEntityId )
3250 {
3251   myIds.Add( theEntityId );
3252   return true;
3253 }
3254
3255 //=======================================================================
3256 // name    : GetRangeStr
3257 // Purpose : Get range as a string.
3258 //           Example: "1,2,3,50-60,63,67,70-"
3259 //=======================================================================
3260 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
3261 {
3262   theResStr.Clear();
3263
3264   TColStd_SequenceOfInteger     anIntSeq;
3265   TColStd_SequenceOfAsciiString aStrSeq;
3266
3267   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
3268   for ( ; anIter.More(); anIter.Next() )
3269   {
3270     int anId = anIter.Key();
3271     TCollection_AsciiString aStr( anId );
3272     anIntSeq.Append( anId );
3273     aStrSeq.Append( aStr );
3274   }
3275
3276   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
3277   {
3278     int aMinId = myMin( i );
3279     int aMaxId = myMax( i );
3280
3281     TCollection_AsciiString aStr;
3282     if ( aMinId != IntegerFirst() )
3283       aStr += aMinId;
3284
3285     aStr += "-";
3286
3287     if ( aMaxId != IntegerLast() )
3288       aStr += aMaxId;
3289
3290     // find position of the string in result sequence and insert string in it
3291     if ( anIntSeq.Length() == 0 )
3292     {
3293       anIntSeq.Append( aMinId );
3294       aStrSeq.Append( aStr );
3295     }
3296     else
3297     {
3298       if ( aMinId < anIntSeq.First() )
3299       {
3300         anIntSeq.Prepend( aMinId );
3301         aStrSeq.Prepend( aStr );
3302       }
3303       else if ( aMinId > anIntSeq.Last() )
3304       {
3305         anIntSeq.Append( aMinId );
3306         aStrSeq.Append( aStr );
3307       }
3308       else
3309         for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
3310           if ( aMinId < anIntSeq( j ) )
3311           {
3312             anIntSeq.InsertBefore( j, aMinId );
3313             aStrSeq.InsertBefore( j, aStr );
3314             break;
3315           }
3316     }
3317   }
3318
3319   if ( aStrSeq.Length() == 0 )
3320     return;
3321
3322   theResStr = aStrSeq( 1 );
3323   for ( int j = 2, k = aStrSeq.Length(); j <= k; j++  )
3324   {
3325     theResStr += ",";
3326     theResStr += aStrSeq( j );
3327   }
3328 }
3329
3330 //=======================================================================
3331 // name    : SetRangeStr
3332 // Purpose : Define range with string
3333 //           Example of entry string: "1,2,3,50-60,63,67,70-"
3334 //=======================================================================
3335 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
3336 {
3337   myMin.Clear();
3338   myMax.Clear();
3339   myIds.Clear();
3340
3341   TCollection_AsciiString aStr = theStr;
3342   for ( int i = 1; i <= aStr.Length(); ++i )
3343   {
3344     char c = aStr.Value( i );
3345     if ( !isdigit( c ) && c != ',' && c != '-' )
3346       aStr.SetValue( i, ',');
3347   }
3348   aStr.RemoveAll( ' ' );
3349
3350   TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
3351   int i = 1;
3352   while ( tmpStr != "" )
3353   {
3354     tmpStr = aStr.Token( ",", i++ );
3355     int aPos = tmpStr.Search( '-' );
3356
3357     if ( aPos == -1 )
3358     {
3359       if ( tmpStr.IsIntegerValue() )
3360         myIds.Add( tmpStr.IntegerValue() );
3361       else
3362         return false;
3363     }
3364     else
3365     {
3366       TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
3367       TCollection_AsciiString aMinStr = tmpStr;
3368
3369       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
3370       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
3371
3372       if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
3373            (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
3374         return false;
3375
3376       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
3377       myMax.Append( aMaxStr.IsEmpty() ? IntegerLast()  : aMaxStr.IntegerValue() );
3378     }
3379   }
3380
3381   return true;
3382 }
3383
3384 //=======================================================================
3385 // name    : GetType
3386 // Purpose : Get type of supported entities
3387 //=======================================================================
3388 SMDSAbs_ElementType RangeOfIds::GetType() const
3389 {
3390   return myType;
3391 }
3392
3393 //=======================================================================
3394 // name    : SetType
3395 // Purpose : Set type of supported entities
3396 //=======================================================================
3397 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
3398 {
3399   myType = theType;
3400 }
3401
3402 //=======================================================================
3403 // name    : IsSatisfy
3404 // Purpose : Verify whether entity satisfies to this rpedicate
3405 //=======================================================================
3406 bool RangeOfIds::IsSatisfy( long theId )
3407 {
3408   if ( !myMesh )
3409     return false;
3410
3411   if ( myType == SMDSAbs_Node )
3412   {
3413     if ( myMesh->FindNode( theId ) == 0 )
3414       return false;
3415   }
3416   else
3417   {
3418     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3419     if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
3420       return false;
3421   }
3422
3423   if ( myIds.Contains( theId ) )
3424     return true;
3425
3426   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
3427     if ( theId >= myMin( i ) && theId <= myMax( i ) )
3428       return true;
3429
3430   return false;
3431 }
3432
3433 /*
3434   Class       : Comparator
3435   Description : Base class for comparators
3436 */
3437 Comparator::Comparator():
3438   myMargin(0)
3439 {}
3440
3441 Comparator::~Comparator()
3442 {}
3443
3444 void Comparator::SetMesh( const SMDS_Mesh* theMesh )
3445 {
3446   if ( myFunctor )
3447     myFunctor->SetMesh( theMesh );
3448 }
3449
3450 void Comparator::SetMargin( double theValue )
3451 {
3452   myMargin = theValue;
3453 }
3454
3455 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
3456 {
3457   myFunctor = theFunct;
3458 }
3459
3460 SMDSAbs_ElementType Comparator::GetType() const
3461 {
3462   return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
3463 }
3464
3465 double Comparator::GetMargin()
3466 {
3467   return myMargin;
3468 }
3469
3470
3471 /*
3472   Class       : LessThan
3473   Description : Comparator "<"
3474 */
3475 bool LessThan::IsSatisfy( long theId )
3476 {
3477   return myFunctor && myFunctor->GetValue( theId ) < myMargin;
3478 }
3479
3480
3481 /*
3482   Class       : MoreThan
3483   Description : Comparator ">"
3484 */
3485 bool MoreThan::IsSatisfy( long theId )
3486 {
3487   return myFunctor && myFunctor->GetValue( theId ) > myMargin;
3488 }
3489
3490
3491 /*
3492   Class       : EqualTo
3493   Description : Comparator "="
3494 */
3495 EqualTo::EqualTo():
3496   myToler(Precision::Confusion())
3497 {}
3498
3499 bool EqualTo::IsSatisfy( long theId )
3500 {
3501   return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
3502 }
3503
3504 void EqualTo::SetTolerance( double theToler )
3505 {
3506   myToler = theToler;
3507 }
3508
3509 double EqualTo::GetTolerance()
3510 {
3511   return myToler;
3512 }
3513
3514 /*
3515   Class       : LogicalNOT
3516   Description : Logical NOT predicate
3517 */
3518 LogicalNOT::LogicalNOT()
3519 {}
3520
3521 LogicalNOT::~LogicalNOT()
3522 {}
3523
3524 bool LogicalNOT::IsSatisfy( long theId )
3525 {
3526   return myPredicate && !myPredicate->IsSatisfy( theId );
3527 }
3528
3529 void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
3530 {
3531   if ( myPredicate )
3532     myPredicate->SetMesh( theMesh );
3533 }
3534
3535 void LogicalNOT::SetPredicate( PredicatePtr thePred )
3536 {
3537   myPredicate = thePred;
3538 }
3539
3540 SMDSAbs_ElementType LogicalNOT::GetType() const
3541 {
3542   return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
3543 }
3544
3545
3546 /*
3547   Class       : LogicalBinary
3548   Description : Base class for binary logical predicate
3549 */
3550 LogicalBinary::LogicalBinary()
3551 {}
3552
3553 LogicalBinary::~LogicalBinary()
3554 {}
3555
3556 void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
3557 {
3558   if ( myPredicate1 )
3559     myPredicate1->SetMesh( theMesh );
3560
3561   if ( myPredicate2 )
3562     myPredicate2->SetMesh( theMesh );
3563 }
3564
3565 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
3566 {
3567   myPredicate1 = thePredicate;
3568 }
3569
3570 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
3571 {
3572   myPredicate2 = thePredicate;
3573 }
3574
3575 SMDSAbs_ElementType LogicalBinary::GetType() const
3576 {
3577   if ( !myPredicate1 || !myPredicate2 )
3578     return SMDSAbs_All;
3579
3580   SMDSAbs_ElementType aType1 = myPredicate1->GetType();
3581   SMDSAbs_ElementType aType2 = myPredicate2->GetType();
3582
3583   return aType1 == aType2 ? aType1 : SMDSAbs_All;
3584 }
3585
3586
3587 /*
3588   Class       : LogicalAND
3589   Description : Logical AND
3590 */
3591 bool LogicalAND::IsSatisfy( long theId )
3592 {
3593   return
3594     myPredicate1 &&
3595     myPredicate2 &&
3596     myPredicate1->IsSatisfy( theId ) &&
3597     myPredicate2->IsSatisfy( theId );
3598 }
3599
3600
3601 /*
3602   Class       : LogicalOR
3603   Description : Logical OR
3604 */
3605 bool LogicalOR::IsSatisfy( long theId )
3606 {
3607   return
3608     myPredicate1 &&
3609     myPredicate2 &&
3610     (myPredicate1->IsSatisfy( theId ) ||
3611     myPredicate2->IsSatisfy( theId ));
3612 }
3613
3614
3615 /*
3616                               FILTER
3617 */
3618
3619 // #ifdef WITH_TBB
3620 // #include <tbb/parallel_for.h>
3621 // #include <tbb/enumerable_thread_specific.h>
3622
3623 // namespace Parallel
3624 // {
3625 //   typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq;
3626
3627 //   struct Predicate
3628 //   {
3629 //     const SMDS_Mesh* myMesh;
3630 //     PredicatePtr     myPredicate;
3631 //     TIdSeq &         myOKIds;
3632 //     Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ):
3633 //       myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {}
3634 //     void operator() ( const tbb::blocked_range<size_t>& r ) const
3635 //     {
3636 //       for ( size_t i = r.begin(); i != r.end(); ++i )
3637 //         if ( myPredicate->IsSatisfy( i ))
3638 //           myOKIds.local().push_back();
3639 //     }
3640 //   }
3641 // }
3642 // #endif
3643
3644 Filter::Filter()
3645 {}
3646
3647 Filter::~Filter()
3648 {}
3649
3650 void Filter::SetPredicate( PredicatePtr thePredicate )
3651 {
3652   myPredicate = thePredicate;
3653 }
3654
3655 void Filter::GetElementsId( const SMDS_Mesh* theMesh,
3656                             PredicatePtr     thePredicate,
3657                             TIdSequence&     theSequence )
3658 {
3659   theSequence.clear();
3660
3661   if ( !theMesh || !thePredicate )
3662     return;
3663
3664   thePredicate->SetMesh( theMesh );
3665
3666   SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() );
3667   if ( elemIt ) {
3668     while ( elemIt->more() ) {
3669       const SMDS_MeshElement* anElem = elemIt->next();
3670       long anId = anElem->GetID();
3671       if ( thePredicate->IsSatisfy( anId ) )
3672         theSequence.push_back( anId );
3673     }
3674   }
3675 }
3676
3677 void Filter::GetElementsId( const SMDS_Mesh*     theMesh,
3678                             Filter::TIdSequence& theSequence )
3679 {
3680   GetElementsId(theMesh,myPredicate,theSequence);
3681 }
3682
3683 /*
3684                               ManifoldPart
3685 */
3686
3687 typedef std::set<SMDS_MeshFace*>                    TMapOfFacePtr;
3688
3689 /*
3690    Internal class Link
3691 */
3692
3693 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
3694                           SMDS_MeshNode* theNode2 )
3695 {
3696   myNode1 = theNode1;
3697   myNode2 = theNode2;
3698 }
3699
3700 ManifoldPart::Link::~Link()
3701 {
3702   myNode1 = 0;
3703   myNode2 = 0;
3704 }
3705
3706 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
3707 {
3708   if ( myNode1 == theLink.myNode1 &&
3709        myNode2 == theLink.myNode2 )
3710     return true;
3711   else if ( myNode1 == theLink.myNode2 &&
3712             myNode2 == theLink.myNode1 )
3713     return true;
3714   else
3715     return false;
3716 }
3717
3718 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
3719 {
3720   if(myNode1 < x.myNode1) return true;
3721   if(myNode1 == x.myNode1)
3722     if(myNode2 < x.myNode2) return true;
3723   return false;
3724 }
3725
3726 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
3727                             const ManifoldPart::Link& theLink2 )
3728 {
3729   return theLink1.IsEqual( theLink2 );
3730 }
3731
3732 ManifoldPart::ManifoldPart()
3733 {
3734   myMesh = 0;
3735   myAngToler = Precision::Angular();
3736   myIsOnlyManifold = true;
3737 }
3738
3739 ManifoldPart::~ManifoldPart()
3740 {
3741   myMesh = 0;
3742 }
3743
3744 void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
3745 {
3746   myMesh = theMesh;
3747   process();
3748 }
3749
3750 SMDSAbs_ElementType ManifoldPart::GetType() const
3751 { return SMDSAbs_Face; }
3752
3753 bool ManifoldPart::IsSatisfy( long theElementId )
3754 {
3755   return myMapIds.Contains( theElementId );
3756 }
3757
3758 void ManifoldPart::SetAngleTolerance( const double theAngToler )
3759 { myAngToler = theAngToler; }
3760
3761 double ManifoldPart::GetAngleTolerance() const
3762 { return myAngToler; }
3763
3764 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
3765 { myIsOnlyManifold = theIsOnly; }
3766
3767 void ManifoldPart::SetStartElem( const long  theStartId )
3768 { myStartElemId = theStartId; }
3769
3770 bool ManifoldPart::process()
3771 {
3772   myMapIds.Clear();
3773   myMapBadGeomIds.Clear();
3774
3775   myAllFacePtr.clear();
3776   myAllFacePtrIntDMap.clear();
3777   if ( !myMesh )
3778     return false;
3779
3780   // collect all faces into own map
3781   SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
3782   for (; anFaceItr->more(); )
3783   {
3784     SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
3785     myAllFacePtr.push_back( aFacePtr );
3786     myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
3787   }
3788
3789   SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
3790   if ( !aStartFace )
3791     return false;
3792
3793   // the map of non manifold links and bad geometry
3794   TMapOfLink aMapOfNonManifold;
3795   TColStd_MapOfInteger aMapOfTreated;
3796
3797   // begin cycle on faces from start index and run on vector till the end
3798   //  and from begin to start index to cover whole vector
3799   const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
3800   bool isStartTreat = false;
3801   for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
3802   {
3803     if ( fi == aStartIndx )
3804       isStartTreat = true;
3805     // as result next time when fi will be equal to aStartIndx
3806
3807     SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
3808     if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
3809       continue;
3810
3811     aMapOfTreated.Add( aFacePtr->GetID() );
3812     TColStd_MapOfInteger aResFaces;
3813     if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
3814                          aMapOfNonManifold, aResFaces ) )
3815       continue;
3816     TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
3817     for ( ; anItr.More(); anItr.Next() )
3818     {
3819       int aFaceId = anItr.Key();
3820       aMapOfTreated.Add( aFaceId );
3821       myMapIds.Add( aFaceId );
3822     }
3823
3824     if ( fi == int( myAllFacePtr.size() - 1 ))
3825       fi = 0;
3826   } // end run on vector of faces
3827   return !myMapIds.IsEmpty();
3828 }
3829
3830 static void getLinks( const SMDS_MeshFace* theFace,
3831                       ManifoldPart::TVectorOfLink& theLinks )
3832 {
3833   int aNbNode = theFace->NbNodes();
3834   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
3835   int i = 1;
3836   SMDS_MeshNode* aNode = 0;
3837   for ( ; aNodeItr->more() && i <= aNbNode; )
3838   {
3839
3840     SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
3841     if ( i == 1 )
3842       aNode = aN1;
3843     i++;
3844     SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
3845     i++;
3846     ManifoldPart::Link aLink( aN1, aN2 );
3847     theLinks.push_back( aLink );
3848   }
3849 }
3850
3851 bool ManifoldPart::findConnected
3852                  ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
3853                   SMDS_MeshFace*                           theStartFace,
3854                   ManifoldPart::TMapOfLink&                theNonManifold,
3855                   TColStd_MapOfInteger&                    theResFaces )
3856 {
3857   theResFaces.Clear();
3858   if ( !theAllFacePtrInt.size() )
3859     return false;
3860
3861   if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
3862   {
3863     myMapBadGeomIds.Add( theStartFace->GetID() );
3864     return false;
3865   }
3866
3867   ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
3868   ManifoldPart::TVectorOfLink aSeqOfBoundary;
3869   theResFaces.Add( theStartFace->GetID() );
3870   ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
3871
3872   expandBoundary( aMapOfBoundary, aSeqOfBoundary,
3873                  aDMapLinkFace, theNonManifold, theStartFace );
3874
3875   bool isDone = false;
3876   while ( !isDone && aMapOfBoundary.size() != 0 )
3877   {
3878     bool isToReset = false;
3879     ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
3880     for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
3881     {
3882       ManifoldPart::Link aLink = *pLink;
3883       if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
3884         continue;
3885       // each link could be treated only once
3886       aMapToSkip.insert( aLink );
3887
3888       ManifoldPart::TVectorOfFacePtr aFaces;
3889       // find next
3890       if ( myIsOnlyManifold &&
3891            (theNonManifold.find( aLink ) != theNonManifold.end()) )
3892         continue;
3893       else
3894       {
3895         getFacesByLink( aLink, aFaces );
3896         // filter the element to keep only indicated elements
3897         ManifoldPart::TVectorOfFacePtr aFiltered;
3898         ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
3899         for ( ; pFace != aFaces.end(); ++pFace )
3900         {
3901           SMDS_MeshFace* aFace = *pFace;
3902           if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
3903             aFiltered.push_back( aFace );
3904         }
3905         aFaces = aFiltered;
3906         if ( aFaces.size() < 2 )  // no neihgbour faces
3907           continue;
3908         else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
3909         {
3910           theNonManifold.insert( aLink );
3911           continue;
3912         }
3913       }
3914
3915       // compare normal with normals of neighbor element
3916       SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
3917       ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
3918       for ( ; pFace != aFaces.end(); ++pFace )
3919       {
3920         SMDS_MeshFace* aNextFace = *pFace;
3921         if ( aPrevFace == aNextFace )
3922           continue;
3923         int anNextFaceID = aNextFace->GetID();
3924         if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
3925          // should not be with non manifold restriction. probably bad topology
3926           continue;
3927         // check if face was treated and skipped
3928         if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
3929              !isInPlane( aPrevFace, aNextFace ) )
3930           continue;
3931         // add new element to connected and extend the boundaries.
3932         theResFaces.Add( anNextFaceID );
3933         expandBoundary( aMapOfBoundary, aSeqOfBoundary,
3934                         aDMapLinkFace, theNonManifold, aNextFace );
3935         isToReset = true;
3936       }
3937     }
3938     isDone = !isToReset;
3939   }
3940
3941   return !theResFaces.IsEmpty();
3942 }
3943
3944 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
3945                               const SMDS_MeshFace* theFace2 )
3946 {
3947   gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
3948   gp_XYZ aNorm2XYZ = getNormale( theFace2 );
3949   if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
3950   {
3951     myMapBadGeomIds.Add( theFace2->GetID() );
3952     return false;
3953   }
3954   if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
3955     return true;
3956
3957   return false;
3958 }
3959
3960 void ManifoldPart::expandBoundary
3961                    ( ManifoldPart::TMapOfLink&            theMapOfBoundary,
3962                      ManifoldPart::TVectorOfLink&         theSeqOfBoundary,
3963                      ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
3964                      ManifoldPart::TMapOfLink&            theNonManifold,
3965                      SMDS_MeshFace*                       theNextFace ) const
3966 {
3967   ManifoldPart::TVectorOfLink aLinks;
3968   getLinks( theNextFace, aLinks );
3969   int aNbLink = (int)aLinks.size();
3970   for ( int i = 0; i < aNbLink; i++ )
3971   {
3972     ManifoldPart::Link aLink = aLinks[ i ];
3973     if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
3974       continue;
3975     if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
3976     {
3977       if ( myIsOnlyManifold )
3978       {
3979         // remove from boundary
3980         theMapOfBoundary.erase( aLink );
3981         ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
3982         for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
3983         {
3984           ManifoldPart::Link aBoundLink = *pLink;
3985           if ( aBoundLink.IsEqual( aLink ) )
3986           {
3987             theSeqOfBoundary.erase( pLink );
3988             break;
3989           }
3990         }
3991       }
3992     }
3993     else
3994     {
3995       theMapOfBoundary.insert( aLink );
3996       theSeqOfBoundary.push_back( aLink );
3997       theDMapLinkFacePtr[ aLink ] = theNextFace;
3998     }
3999   }
4000 }
4001
4002 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
4003                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
4004 {
4005   std::set<SMDS_MeshCell *> aSetOfFaces;
4006   // take all faces that shared first node
4007   SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
4008   for ( ; anItr->more(); )
4009   {
4010     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
4011     if ( !aFace )
4012       continue;
4013     aSetOfFaces.insert( aFace );
4014   }
4015   // take all faces that shared second node
4016   anItr = theLink.myNode2->facesIterator();
4017   // find the common part of two sets
4018   for ( ; anItr->more(); )
4019   {
4020     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
4021     if ( aSetOfFaces.count( aFace ) )
4022       theFaces.push_back( aFace );
4023   }
4024 }
4025
4026 /*
4027   Class       : BelongToMeshGroup
4028   Description : Verify whether a mesh element is included into a mesh group
4029 */
4030 BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 )
4031 {
4032 }
4033
4034 void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g )
4035 {
4036   myGroup = g;
4037 }
4038
4039 void BelongToMeshGroup::SetStoreName( const std::string& sn )
4040 {
4041   myStoreName = sn;
4042 }
4043
4044 void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh )
4045 {
4046   if ( myGroup && myGroup->GetMesh() != theMesh )
4047   {
4048     myGroup = 0;
4049   }
4050   if ( !myGroup && !myStoreName.empty() )
4051   {
4052     if ( const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh))
4053     {
4054       const std::set<SMESHDS_GroupBase*>& grps = aMesh->GetGroups();
4055       std::set<SMESHDS_GroupBase*>::const_iterator g = grps.begin();
4056       for ( ; g != grps.end() && !myGroup; ++g )
4057         if ( *g && myStoreName == (*g)->GetStoreName() )
4058           myGroup = *g;
4059     }
4060   }
4061   if ( myGroup )
4062   {
4063     myGroup->IsEmpty(); // make GroupOnFilter update its predicate
4064   }
4065 }
4066
4067 bool BelongToMeshGroup::IsSatisfy( long theElementId )
4068 {
4069   return myGroup ? myGroup->Contains( theElementId ) : false;
4070 }
4071
4072 SMDSAbs_ElementType BelongToMeshGroup::GetType() const
4073 {
4074   return myGroup ? myGroup->GetType() : SMDSAbs_All;
4075 }
4076
4077 //================================================================================
4078 //  ElementsOnSurface
4079 //================================================================================
4080
4081 ElementsOnSurface::ElementsOnSurface()
4082 {
4083   myIds.Clear();
4084   myType = SMDSAbs_All;
4085   mySurf.Nullify();
4086   myToler = Precision::Confusion();
4087   myUseBoundaries = false;
4088 }
4089
4090 ElementsOnSurface::~ElementsOnSurface()
4091 {
4092 }
4093
4094 void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
4095 {
4096   myMeshModifTracer.SetMesh( theMesh );
4097   if ( myMeshModifTracer.IsMeshModified())
4098     process();
4099 }
4100
4101 bool ElementsOnSurface::IsSatisfy( long theElementId )
4102 {
4103   return myIds.Contains( theElementId );
4104 }
4105
4106 SMDSAbs_ElementType ElementsOnSurface::GetType() const
4107 { return myType; }
4108
4109 void ElementsOnSurface::SetTolerance( const double theToler )
4110 {
4111   if ( myToler != theToler )
4112     myIds.Clear();
4113   myToler = theToler;
4114 }
4115
4116 double ElementsOnSurface::GetTolerance() const
4117 { return myToler; }
4118
4119 void ElementsOnSurface::SetUseBoundaries( bool theUse )
4120 {
4121   if ( myUseBoundaries != theUse ) {
4122     myUseBoundaries = theUse;
4123     SetSurface( mySurf, myType );
4124   }
4125 }
4126
4127 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
4128                                     const SMDSAbs_ElementType theType )
4129 {
4130   myIds.Clear();
4131   myType = theType;
4132   mySurf.Nullify();
4133   if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
4134     return;
4135   mySurf = TopoDS::Face( theShape );
4136   BRepAdaptor_Surface SA( mySurf, myUseBoundaries );
4137   Standard_Real
4138     u1 = SA.FirstUParameter(),
4139     u2 = SA.LastUParameter(),
4140     v1 = SA.FirstVParameter(),
4141     v2 = SA.LastVParameter();
4142   Handle(Geom_Surface) surf = BRep_Tool::Surface( mySurf );
4143   myProjector.Init( surf, u1,u2, v1,v2 );
4144   process();
4145 }
4146
4147 void ElementsOnSurface::process()
4148 {
4149   myIds.Clear();
4150   if ( mySurf.IsNull() )
4151     return;
4152
4153   if ( !myMeshModifTracer.GetMesh() )
4154     return;
4155
4156   myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ));
4157
4158   SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType );
4159   for(; anIter->more(); )
4160     process( anIter->next() );
4161 }
4162
4163 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
4164 {
4165   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
4166   bool isSatisfy = true;
4167   for ( ; aNodeItr->more(); )
4168   {
4169     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
4170     if ( !isOnSurface( aNode ) )
4171     {
4172       isSatisfy = false;
4173       break;
4174     }
4175   }
4176   if ( isSatisfy )
4177     myIds.Add( theElemPtr->GetID() );
4178 }
4179
4180 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
4181 {
4182   if ( mySurf.IsNull() )
4183     return false;
4184
4185   gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
4186   //  double aToler2 = myToler * myToler;
4187 //   if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
4188 //   {
4189 //     gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
4190 //     if ( aPln.SquareDistance( aPnt ) > aToler2 )
4191 //       return false;
4192 //   }
4193 //   else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
4194 //   {
4195 //     gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
4196 //     double aRad = aCyl.Radius();
4197 //     gp_Ax3 anAxis = aCyl.Position();
4198 //     gp_XYZ aLoc = aCyl.Location().XYZ();
4199 //     double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4200 //     double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4201 //     if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
4202 //       return false;
4203 //   }
4204 //   else
4205 //     return false;
4206   myProjector.Perform( aPnt );
4207   bool isOn = ( myProjector.IsDone() && myProjector.LowerDistance() <= myToler );
4208
4209   return isOn;
4210 }
4211
4212
4213 //================================================================================
4214 //  ElementsOnShape
4215 //================================================================================
4216
4217 namespace {
4218   const int theIsCheckedFlag = 0x0000100;
4219 }
4220
4221 struct ElementsOnShape::Classifier
4222 {
4223   Classifier() { mySolidClfr = 0; myFlags = 0; }
4224   ~Classifier();
4225   void Init(const TopoDS_Shape& s, double tol, const Bnd_B3d* box = 0 );
4226   bool IsOut(const gp_Pnt& p)        { return SetChecked( true ), (this->*myIsOutFun)( p ); }
4227   TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); }
4228   const TopoDS_Shape& Shape() const  { return myShape; }
4229   const Bnd_B3d* GetBndBox() const   { return & myBox; }
4230   bool IsChecked()                   { return myFlags & theIsCheckedFlag; }
4231   bool IsSetFlag( int flag ) const   { return myFlags & flag; }
4232   void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); }
4233   void SetFlag  ( int flag ) { myFlags |= flag; }
4234   void UnsetFlag( int flag ) { myFlags &= ~flag; }
4235
4236 private:
4237   bool isOutOfSolid (const gp_Pnt& p);
4238   bool isOutOfBox   (const gp_Pnt& p);
4239   bool isOutOfFace  (const gp_Pnt& p);
4240   bool isOutOfEdge  (const gp_Pnt& p);
4241   bool isOutOfVertex(const gp_Pnt& p);
4242   bool isBox        (const TopoDS_Shape& s);
4243
4244   bool (Classifier::*          myIsOutFun)(const gp_Pnt& p);
4245   BRepClass3d_SolidClassifier* mySolidClfr; // ptr because of a run-time forbidden copy-constructor
4246   Bnd_B3d                      myBox;
4247   GeomAPI_ProjectPointOnSurf   myProjFace;
4248   GeomAPI_ProjectPointOnCurve  myProjEdge;
4249   gp_Pnt                       myVertexXYZ;
4250   TopoDS_Shape                 myShape;
4251   double                       myTol;
4252   int                          myFlags;
4253 };
4254
4255 struct ElementsOnShape::OctreeClassifier : public SMESH_Octree
4256 {
4257   OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers );
4258   OctreeClassifier( const OctreeClassifier*                           otherTree,
4259                     const std::vector< ElementsOnShape::Classifier >& clsOther,
4260                     std::vector< ElementsOnShape::Classifier >&       cls );
4261   void GetClassifiersAtPoint( const gp_XYZ& p,
4262                               std::vector< ElementsOnShape::Classifier* >& classifiers );
4263 protected:
4264   OctreeClassifier() {}
4265   SMESH_Octree* newChild() const { return new OctreeClassifier; }
4266   void          buildChildrenData();
4267   Bnd_B3d*      buildRootBox();
4268
4269   std::vector< ElementsOnShape::Classifier* > myClassifiers;
4270 };
4271
4272
4273 ElementsOnShape::ElementsOnShape():
4274   myOctree(0),
4275   myType(SMDSAbs_All),
4276   myToler(Precision::Confusion()),
4277   myAllNodesFlag(false)
4278 {
4279 }
4280
4281 ElementsOnShape::~ElementsOnShape()
4282 {
4283   clearClassifiers();
4284 }
4285
4286 Predicate* ElementsOnShape::clone() const
4287 {
4288   ElementsOnShape* cln = new ElementsOnShape();
4289   cln->SetAllNodes ( myAllNodesFlag );
4290   cln->SetTolerance( myToler );
4291   cln->SetMesh     ( myMeshModifTracer.GetMesh() );
4292   cln->myShape = myShape; // avoid creation of myClassifiers
4293   cln->SetShape    ( myShape, myType );
4294   cln->myClassifiers.resize( myClassifiers.size() );
4295   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4296     cln->myClassifiers[ i ].Init( BRepBuilderAPI_Copy( myClassifiers[ i ].Shape()),
4297                                   myToler, myClassifiers[ i ].GetBndBox() );
4298   if ( myOctree ) // copy myOctree
4299   {
4300     cln->myOctree = new OctreeClassifier( myOctree, myClassifiers, cln->myClassifiers );
4301   }
4302   return cln;
4303 }
4304
4305 SMDSAbs_ElementType ElementsOnShape::GetType() const
4306 {
4307   return myType;
4308 }
4309
4310 void ElementsOnShape::SetTolerance (const double theToler)
4311 {
4312   if (myToler != theToler) {
4313     myToler = theToler;
4314     SetShape(myShape, myType);
4315   }
4316 }
4317
4318 double ElementsOnShape::GetTolerance() const
4319 {
4320   return myToler;
4321 }
4322
4323 void ElementsOnShape::SetAllNodes (bool theAllNodes)
4324 {
4325   myAllNodesFlag = theAllNodes;
4326 }
4327
4328 void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh)
4329 {
4330   myMeshModifTracer.SetMesh( theMesh );
4331   if ( myMeshModifTracer.IsMeshModified())
4332   {
4333     size_t nbNodes = theMesh ? theMesh->NbNodes() : 0;
4334     if ( myNodeIsChecked.size() == nbNodes )
4335     {
4336       std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4337     }
4338     else
4339     {
4340       SMESHUtils::FreeVector( myNodeIsChecked );
4341       SMESHUtils::FreeVector( myNodeIsOut );
4342       myNodeIsChecked.resize( nbNodes, false );
4343       myNodeIsOut.resize( nbNodes );
4344     }
4345   }
4346 }
4347
4348 bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut )
4349 {
4350   if ( n->GetID() >= (int) myNodeIsChecked.size() ||
4351        !myNodeIsChecked[ n->GetID() ])
4352     return false;
4353
4354   isOut = myNodeIsOut[ n->GetID() ];
4355   return true;
4356 }
4357
4358 void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool  isOut )
4359 {
4360   if ( n->GetID() < (int) myNodeIsChecked.size() )
4361   {
4362     myNodeIsChecked[ n->GetID() ] = true;
4363     myNodeIsOut    [ n->GetID() ] = isOut;
4364   }
4365 }
4366
4367 void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
4368                                 const SMDSAbs_ElementType theType)
4369 {
4370   bool shapeChanges = ( myShape != theShape );
4371   myType  = theType;
4372   myShape = theShape;
4373   if ( myShape.IsNull() ) return;
4374
4375   if ( shapeChanges )
4376   {
4377     // find most complex shapes
4378     TopTools_IndexedMapOfShape shapesMap;
4379     TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
4380     TopExp_Explorer sub;
4381     for ( int i = 0; i < 4; ++i )
4382     {
4383       if ( shapesMap.IsEmpty() )
4384         for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() )
4385           shapesMap.Add( sub.Current() );
4386       if ( i > 0 )
4387         for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() )
4388           shapesMap.Add( sub.Current() );
4389     }
4390
4391     clearClassifiers();
4392     myClassifiers.resize( shapesMap.Extent() );
4393     for ( int i = 0; i < shapesMap.Extent(); ++i )
4394       myClassifiers[ i ].Init( shapesMap( i+1 ), myToler );
4395   }
4396
4397   if ( theType == SMDSAbs_Node )
4398   {
4399     SMESHUtils::FreeVector( myNodeIsChecked );
4400     SMESHUtils::FreeVector( myNodeIsOut );
4401   }
4402   else
4403   {
4404     std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4405   }
4406 }
4407
4408 void ElementsOnShape::clearClassifiers()
4409 {
4410   // for ( size_t i = 0; i < myClassifiers.size(); ++i )
4411   //   delete myClassifiers[ i ];
4412   myClassifiers.clear();
4413
4414   delete myOctree;
4415   myOctree = 0;
4416 }
4417
4418 bool ElementsOnShape::IsSatisfy( long elemId )
4419 {
4420   if ( myClassifiers.empty() )
4421     return false;
4422
4423   const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
4424   if ( myType == SMDSAbs_Node )
4425     return IsSatisfy( mesh->FindNode( elemId ));
4426   return IsSatisfy( mesh->FindElement( elemId ));
4427 }
4428
4429 bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
4430 {
4431   if ( !elem )
4432     return false;
4433
4434   bool isSatisfy = myAllNodesFlag, isNodeOut;
4435
4436   gp_XYZ centerXYZ (0, 0, 0);
4437
4438   if ( !myOctree && myClassifiers.size() > 5 )
4439   {
4440     myWorkClassifiers.resize( myClassifiers.size() );
4441     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4442       myWorkClassifiers[ i ] = & myClassifiers[ i ];
4443     myOctree = new OctreeClassifier( myWorkClassifiers );
4444   }
4445
4446   SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator();
4447   while (aNodeItr->more() && (isSatisfy == myAllNodesFlag))
4448   {
4449     SMESH_TNodeXYZ aPnt( aNodeItr->next() );
4450     centerXYZ += aPnt;
4451
4452     isNodeOut = true;
4453     if ( !getNodeIsOut( aPnt._node, isNodeOut ))
4454     {
4455       if ( myOctree )
4456       {
4457         myWorkClassifiers.clear();
4458         myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4459
4460         for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4461           myWorkClassifiers[i]->SetChecked( false );
4462
4463         for ( size_t i = 0; i < myWorkClassifiers.size() && isNodeOut; ++i )
4464           if ( !myWorkClassifiers[i]->IsChecked() )
4465             isNodeOut = myWorkClassifiers[i]->IsOut( aPnt );
4466       }
4467       else
4468       {
4469         for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i )
4470           isNodeOut = myClassifiers[i].IsOut( aPnt );
4471       }
4472       setNodeIsOut( aPnt._node, isNodeOut );
4473     }
4474     isSatisfy = !isNodeOut;
4475   }
4476
4477   // Check the center point for volumes MantisBug 0020168
4478   if ( isSatisfy &&
4479        myAllNodesFlag &&
4480        myClassifiers[0].ShapeType() == TopAbs_SOLID )
4481   {
4482     centerXYZ /= elem->NbNodes();
4483     isSatisfy = false;
4484     if ( myOctree )
4485       for ( size_t i = 0; i < myWorkClassifiers.size() && !isSatisfy; ++i )
4486         isSatisfy = ! myWorkClassifiers[i]->IsOut( centerXYZ );
4487     else
4488       for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i )
4489         isSatisfy = ! myClassifiers[i].IsOut( centerXYZ );
4490   }
4491
4492   return isSatisfy;
4493 }
4494
4495 bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
4496                                  TopoDS_Shape*        okShape)
4497 {
4498   if ( !node )
4499     return false;
4500
4501   if ( !myOctree && myClassifiers.size() > 5 )
4502   {
4503     myWorkClassifiers.resize( myClassifiers.size() );
4504     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4505       myWorkClassifiers[ i ] = & myClassifiers[ i ];
4506     myOctree = new OctreeClassifier( myWorkClassifiers );
4507   }
4508
4509   bool isNodeOut = true;
4510
4511   if ( okShape || !getNodeIsOut( node, isNodeOut ))
4512   {
4513     SMESH_NodeXYZ aPnt = node;
4514     if ( myOctree )
4515     {
4516       myWorkClassifiers.clear();
4517       myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4518
4519       for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4520         myWorkClassifiers[i]->SetChecked( false );
4521
4522       for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4523         if ( !myWorkClassifiers[i]->IsChecked() &&
4524              !myWorkClassifiers[i]->IsOut( aPnt ))
4525         {
4526           isNodeOut = false;
4527           if ( okShape )
4528             *okShape = myWorkClassifiers[i]->Shape();
4529           break;
4530         }
4531     }
4532     else
4533     {
4534       for ( size_t i = 0; i < myClassifiers.size(); ++i )
4535         if ( !myClassifiers[i].IsOut( aPnt ))
4536         {
4537           isNodeOut = false;
4538           if ( okShape )
4539             *okShape = myWorkClassifiers[i]->Shape();
4540           break;
4541         }
4542     }
4543     setNodeIsOut( node, isNodeOut );
4544   }
4545
4546   return !isNodeOut;
4547 }
4548
4549 void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
4550                                         double              theTol,
4551                                         const Bnd_B3d*      theBox )
4552 {
4553   myShape = theShape;
4554   myTol   = theTol;
4555   myFlags = 0;
4556
4557   bool isShapeBox = false;
4558   switch ( myShape.ShapeType() )
4559   {
4560   case TopAbs_SOLID:
4561   {
4562     if (( isShapeBox = isBox( theShape )))
4563     {
4564       myIsOutFun = & ElementsOnShape::Classifier::isOutOfBox;
4565     }
4566     else
4567     {
4568       mySolidClfr = new BRepClass3d_SolidClassifier(theShape);
4569       myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid;
4570     }
4571     break;
4572   }
4573   case TopAbs_FACE:
4574   {
4575     Standard_Real u1,u2,v1,v2;
4576     Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape ));
4577     surf->Bounds( u1,u2,v1,v2 );
4578     myProjFace.Init(surf, u1,u2, v1,v2, myTol );
4579     myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace;
4580     break;
4581   }
4582   case TopAbs_EDGE:
4583   {
4584     Standard_Real u1, u2;
4585     Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2);
4586     myProjEdge.Init(curve, u1, u2);
4587     myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge;
4588     break;
4589   }
4590   case TopAbs_VERTEX:
4591   {
4592     myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) );
4593     myIsOutFun = & ElementsOnShape::Classifier::isOutOfVertex;
4594     break;
4595   }
4596   default:
4597     throw SALOME_Exception("Programmer error in usage of ElementsOnShape::Classifier");
4598   }
4599
4600   if ( !isShapeBox )
4601   {
4602     if ( theBox )
4603     {
4604       myBox = *theBox;
4605     }
4606     else
4607     {
4608       Bnd_Box box;
4609       BRepBndLib::Add( myShape, box );
4610       myBox.Clear();
4611       myBox.Add( box.CornerMin() );
4612       myBox.Add( box.CornerMax() );
4613       gp_XYZ halfSize = 0.5 * ( box.CornerMax().XYZ() - box.CornerMin().XYZ() );
4614       for ( int iDim = 1; iDim <= 3; ++iDim )
4615       {
4616         double x = halfSize.Coord( iDim );
4617         halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x ));
4618       }
4619       myBox.SetHSize( halfSize );
4620     }
4621   }
4622 }
4623
4624 ElementsOnShape::Classifier::~Classifier()
4625 {
4626   delete mySolidClfr; mySolidClfr = 0;
4627 }
4628
4629 bool ElementsOnShape::Classifier::isOutOfSolid (const gp_Pnt& p)
4630 {
4631   mySolidClfr->Perform( p, myTol );
4632   return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON );
4633 }
4634
4635 bool ElementsOnShape::Classifier::isOutOfBox (const gp_Pnt& p)
4636 {
4637   return myBox.IsOut( p.XYZ() );
4638 }
4639
4640 bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& p)
4641 {
4642   myProjFace.Perform( p );
4643   if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol )
4644   {
4645     // check relatively to the face
4646     Standard_Real u, v;
4647     myProjFace.LowerDistanceParameters(u, v);
4648     gp_Pnt2d aProjPnt (u, v);
4649     BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
4650     if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON )
4651       return false;
4652   }
4653   return true;
4654 }
4655
4656 bool ElementsOnShape::Classifier::isOutOfEdge  (const gp_Pnt& p)
4657 {
4658   myProjEdge.Perform( p );
4659   return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol );
4660 }
4661
4662 bool ElementsOnShape::Classifier::isOutOfVertex(const gp_Pnt& p)
4663 {
4664   return ( myVertexXYZ.Distance( p ) > myTol );
4665 }
4666
4667 bool ElementsOnShape::Classifier::isBox (const TopoDS_Shape& theShape)
4668 {
4669   TopTools_IndexedMapOfShape vMap;
4670   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
4671   if ( vMap.Extent() != 8 )
4672     return false;
4673
4674   myBox.Clear();
4675   for ( int i = 1; i <= 8; ++i )
4676     myBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))).XYZ() );
4677
4678   gp_XYZ pMin = myBox.CornerMin(), pMax = myBox.CornerMax();
4679   for ( int i = 1; i <= 8; ++i )
4680   {
4681     gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vMap( i )));
4682     for ( int iC = 1; iC <= 3; ++ iC )
4683     {
4684       double d1 = Abs( pMin.Coord( iC ) - p.Coord( iC ));
4685       double d2 = Abs( pMax.Coord( iC ) - p.Coord( iC ));
4686       if ( Min( d1, d2 ) > myTol )
4687         return false;
4688     }
4689   }
4690   myBox.Enlarge( myTol );
4691   return true;
4692 }
4693
4694 ElementsOnShape::
4695 OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers )
4696   :SMESH_Octree( new SMESH_TreeLimit )
4697 {
4698   myClassifiers = classifiers;
4699   compute();
4700 }
4701
4702 ElementsOnShape::
4703 OctreeClassifier::OctreeClassifier( const OctreeClassifier*                           otherTree,
4704                                     const std::vector< ElementsOnShape::Classifier >& clsOther,
4705                                     std::vector< ElementsOnShape::Classifier >&       cls )
4706   :SMESH_Octree( new SMESH_TreeLimit )
4707 {
4708   myBox = new Bnd_B3d( *otherTree->getBox() );
4709
4710   if (( myIsLeaf = otherTree->isLeaf() ))
4711   {
4712     myClassifiers.resize( otherTree->myClassifiers.size() );
4713     for ( size_t i = 0; i < otherTree->myClassifiers.size(); ++i )
4714     {
4715       int ind = otherTree->myClassifiers[i] - & clsOther[0];
4716       myClassifiers[ i ] = & cls[ ind ];
4717     }
4718   }
4719   else if ( otherTree->myChildren )
4720   {
4721     myChildren = new SMESH_Tree< Bnd_B3d, 8 > * [ 8 ];
4722     for ( int i = 0; i < nbChildren(); i++ )
4723       myChildren[i] =
4724         new OctreeClassifier( static_cast<const OctreeClassifier*>( otherTree->myChildren[i]),
4725                               clsOther, cls );
4726   }
4727 }
4728
4729 void ElementsOnShape::
4730 OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
4731                                          std::vector< ElementsOnShape::Classifier* >& result )
4732 {
4733   if ( getBox()->IsOut( point ))
4734     return;
4735
4736   if ( isLeaf() )
4737   {
4738     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4739       if ( !myClassifiers[i]->GetBndBox()->IsOut( point ))
4740         result.push_back( myClassifiers[i] );
4741   }
4742   else
4743   {
4744     for (int i = 0; i < nbChildren(); i++)
4745       ((OctreeClassifier*) myChildren[i])->GetClassifiersAtPoint( point, result );
4746   }
4747 }
4748
4749 void ElementsOnShape::OctreeClassifier::buildChildrenData()
4750 {
4751   // distribute myClassifiers among myChildren
4752
4753   const int childFlag[8] = { 0x0000001,
4754                              0x0000002,
4755                              0x0000004,
4756                              0x0000008,
4757                              0x0000010,
4758                              0x0000020,
4759                              0x0000040,
4760                              0x0000080 };
4761   int nbInChild[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
4762
4763   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4764   {
4765     for ( int j = 0; j < nbChildren(); j++ )
4766     {
4767       if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() ))
4768       {
4769         myClassifiers[i]->SetFlag( childFlag[ j ]);
4770         ++nbInChild[ j ];
4771       }
4772     }
4773   }
4774
4775   for ( int j = 0; j < nbChildren(); j++ )
4776   {
4777     OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ j ]);
4778     child->myClassifiers.resize( nbInChild[ j ]);
4779     for ( size_t i = 0; nbInChild[ j ] && i < myClassifiers.size(); ++i )
4780     {
4781       if ( myClassifiers[ i ]->IsSetFlag( childFlag[ j ]))
4782       {
4783         --nbInChild[ j ];
4784         child->myClassifiers[ nbInChild[ j ]] = myClassifiers[ i ];
4785         myClassifiers[ i ]->UnsetFlag( childFlag[ j ]);
4786       }
4787     }
4788   }
4789   SMESHUtils::FreeVector( myClassifiers );
4790
4791   // define if a child isLeaf()
4792   for ( int i = 0; i < nbChildren(); i++ )
4793   {
4794     OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
4795     child->myIsLeaf = ( child->myClassifiers.size() <= 5  );
4796   }
4797 }
4798
4799 Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox()
4800 {
4801   Bnd_B3d* box = new Bnd_B3d;
4802   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4803     box->Add( *myClassifiers[i]->GetBndBox() );
4804   return box;
4805 }
4806
4807 /*
4808   Class       : BelongToGeom
4809   Description : Predicate for verifying whether entity belongs to
4810                 specified geometrical support
4811 */
4812
4813 BelongToGeom::BelongToGeom()
4814   : myMeshDS(NULL),
4815     myType(SMDSAbs_NbElementTypes),
4816     myIsSubshape(false),
4817     myTolerance(Precision::Confusion())
4818 {}
4819
4820 Predicate* BelongToGeom::clone() const
4821 {
4822   BelongToGeom* cln = new BelongToGeom( *this );
4823   cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
4824   return cln;
4825 }
4826
4827 void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh )
4828 {
4829   if ( myMeshDS != theMesh )
4830   {
4831     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
4832     init();
4833   }
4834 }
4835
4836 void BelongToGeom::SetGeom( const TopoDS_Shape& theShape )
4837 {
4838   if ( myShape != theShape )
4839   {
4840     myShape = theShape;
4841     init();
4842   }
4843 }
4844
4845 static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap,
4846                         const TopoDS_Shape&               theShape)
4847 {
4848   if (theMap.Contains(theShape)) return true;
4849
4850   if (theShape.ShapeType() == TopAbs_COMPOUND ||
4851       theShape.ShapeType() == TopAbs_COMPSOLID)
4852   {
4853     TopoDS_Iterator anIt (theShape, Standard_True, Standard_True);
4854     for (; anIt.More(); anIt.Next())
4855     {
4856       if (!IsSubShape(theMap, anIt.Value())) {
4857         return false;
4858       }
4859     }
4860     return true;
4861   }
4862
4863   return false;
4864 }
4865
4866 void BelongToGeom::init()
4867 {
4868   if ( !myMeshDS || myShape.IsNull() ) return;
4869
4870   // is sub-shape of main shape?
4871   TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
4872   if (aMainShape.IsNull()) {
4873     myIsSubshape = false;
4874   }
4875   else {
4876     TopTools_IndexedMapOfShape aMap;
4877     TopExp::MapShapes( aMainShape, aMap );
4878     myIsSubshape = IsSubShape( aMap, myShape );
4879     if ( myIsSubshape )
4880     {
4881       aMap.Clear();
4882       TopExp::MapShapes( myShape, aMap );
4883       mySubShapesIDs.Clear();
4884       for ( int i = 1; i <= aMap.Extent(); ++i )
4885       {
4886         int subID = myMeshDS->ShapeToIndex( aMap( i ));
4887         if ( subID > 0 )
4888           mySubShapesIDs.Add( subID );
4889       }
4890     }
4891   }
4892
4893   //if (!myIsSubshape) // to be always ready to check an element not bound to geometry
4894   {
4895     if ( !myElementsOnShapePtr )
4896       myElementsOnShapePtr.reset( new ElementsOnShape() );
4897     myElementsOnShapePtr->SetTolerance( myTolerance );
4898     myElementsOnShapePtr->SetAllNodes( true ); // "belong", while false means "lays on"
4899     myElementsOnShapePtr->SetMesh( myMeshDS );
4900     myElementsOnShapePtr->SetShape( myShape, myType );
4901   }
4902 }
4903
4904 bool BelongToGeom::IsSatisfy (long theId)
4905 {
4906   if (myMeshDS == 0 || myShape.IsNull())
4907     return false;
4908
4909   if (!myIsSubshape)
4910   {
4911     return myElementsOnShapePtr->IsSatisfy(theId);
4912   }
4913
4914   // Case of sub-mesh
4915
4916   if (myType == SMDSAbs_Node)
4917   {
4918     if ( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ))
4919     {
4920       if ( aNode->getshapeId() < 1 )
4921         return myElementsOnShapePtr->IsSatisfy(theId);
4922       else
4923         return mySubShapesIDs.Contains( aNode->getshapeId() );
4924     }
4925   }
4926   else
4927   {
4928     if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId ))
4929     {
4930       if ( anElem->GetType() == myType )
4931       {
4932         if ( anElem->getshapeId() < 1 )
4933           return myElementsOnShapePtr->IsSatisfy(theId);
4934         else
4935           return mySubShapesIDs.Contains( anElem->getshapeId() );
4936       }
4937     }
4938   }
4939
4940   return false;
4941 }
4942
4943 void BelongToGeom::SetType (SMDSAbs_ElementType theType)
4944 {
4945   if ( myType != theType )
4946   {
4947     myType = theType;
4948     init();
4949   }
4950 }
4951
4952 SMDSAbs_ElementType BelongToGeom::GetType() const
4953 {
4954   return myType;
4955 }
4956
4957 TopoDS_Shape BelongToGeom::GetShape()
4958 {
4959   return myShape;
4960 }
4961
4962 const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const
4963 {
4964   return myMeshDS;
4965 }
4966
4967 void BelongToGeom::SetTolerance (double theTolerance)
4968 {
4969   myTolerance = theTolerance;
4970   init();
4971 }
4972
4973 double BelongToGeom::GetTolerance()
4974 {
4975   return myTolerance;
4976 }
4977
4978 /*
4979   Class       : LyingOnGeom
4980   Description : Predicate for verifying whether entiy lying or partially lying on
4981   specified geometrical support
4982 */
4983
4984 LyingOnGeom::LyingOnGeom()
4985   : myMeshDS(NULL),
4986     myType(SMDSAbs_NbElementTypes),
4987     myIsSubshape(false),
4988     myTolerance(Precision::Confusion())
4989 {}
4990
4991 Predicate* LyingOnGeom::clone() const
4992 {
4993   LyingOnGeom* cln = new LyingOnGeom( *this );
4994   cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
4995   return cln;
4996 }
4997
4998 void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh )
4999 {
5000   if ( myMeshDS != theMesh )
5001   {
5002     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
5003     init();
5004   }
5005 }
5006
5007 void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape )
5008 {
5009   if ( myShape != theShape )
5010   {
5011     myShape = theShape;
5012     init();
5013   }
5014 }
5015
5016 void LyingOnGeom::init()
5017 {
5018   if (!myMeshDS || myShape.IsNull()) return;
5019
5020   // is sub-shape of main shape?
5021   TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
5022   if (aMainShape.IsNull()) {
5023     myIsSubshape = false;
5024   }
5025   else {
5026     myIsSubshape = myMeshDS->IsGroupOfSubShapes( myShape );
5027   }
5028
5029   if (myIsSubshape)
5030   {
5031     TopTools_IndexedMapOfShape shapes;
5032     TopExp::MapShapes( myShape, shapes );
5033     mySubShapesIDs.Clear();
5034     for ( int i = 1; i <= shapes.Extent(); ++i )
5035     {
5036       int subID = myMeshDS->ShapeToIndex( shapes( i ));
5037       if ( subID > 0 )
5038         mySubShapesIDs.Add( subID );
5039     }
5040   }
5041   // else // to be always ready to check an element not bound to geometry
5042   {
5043     if ( !myElementsOnShapePtr )
5044       myElementsOnShapePtr.reset( new ElementsOnShape() );
5045     myElementsOnShapePtr->SetTolerance( myTolerance );
5046     myElementsOnShapePtr->SetAllNodes( false ); // lays on, while true means "belong"
5047     myElementsOnShapePtr->SetMesh( myMeshDS );
5048     myElementsOnShapePtr->SetShape( myShape, myType );
5049   }
5050 }
5051
5052 bool LyingOnGeom::IsSatisfy( long theId )
5053 {
5054   if ( myMeshDS == 0 || myShape.IsNull() )
5055     return false;
5056
5057   if (!myIsSubshape)
5058   {
5059     return myElementsOnShapePtr->IsSatisfy(theId);
5060   }
5061
5062   // Case of sub-mesh
5063
5064   const SMDS_MeshElement* elem =
5065     ( myType == SMDSAbs_Node ) ? myMeshDS->FindNode( theId ) : myMeshDS->FindElement( theId );
5066
5067   if ( mySubShapesIDs.Contains( elem->getshapeId() ))
5068     return true;
5069
5070   if ( elem->GetType() != SMDSAbs_Node && elem->GetType() == myType )
5071   {
5072     SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator();
5073     while ( nodeItr->more() )
5074     {
5075       const SMDS_MeshElement* aNode = nodeItr->next();
5076       if ( mySubShapesIDs.Contains( aNode->getshapeId() ))
5077         return true;
5078     }
5079   }
5080
5081   return false;
5082 }
5083
5084 void LyingOnGeom::SetType( SMDSAbs_ElementType theType )
5085 {
5086   if ( myType != theType )
5087   {
5088     myType = theType;
5089     init();
5090   }
5091 }
5092
5093 SMDSAbs_ElementType LyingOnGeom::GetType() const
5094 {
5095   return myType;
5096 }
5097
5098 TopoDS_Shape LyingOnGeom::GetShape()
5099 {
5100   return myShape;
5101 }
5102
5103 const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const
5104 {
5105   return myMeshDS;
5106 }
5107
5108 void LyingOnGeom::SetTolerance (double theTolerance)
5109 {
5110   myTolerance = theTolerance;
5111   init();
5112 }
5113
5114 double LyingOnGeom::GetTolerance()
5115 {
5116   return myTolerance;
5117 }
5118
5119 TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0)
5120 {}
5121
5122 TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n), myElem(0)
5123 {}
5124
5125 TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t), myElem(0)
5126 {}
5127
5128 TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray), myElem(theSequenceOfXYZ.myElem)
5129 {}
5130
5131 template <class InputIterator>
5132 TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd), myElem(0)
5133 {}
5134
5135 TSequenceOfXYZ::~TSequenceOfXYZ()
5136 {}
5137
5138 TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ)
5139 {
5140   myArray = theSequenceOfXYZ.myArray;
5141   myElem  = theSequenceOfXYZ.myElem;
5142   return *this;
5143 }
5144
5145 gp_XYZ& TSequenceOfXYZ::operator()(size_type n)
5146 {
5147   return myArray[n-1];
5148 }
5149
5150 const gp_XYZ& TSequenceOfXYZ::operator()(size_type n) const
5151 {
5152   return myArray[n-1];
5153 }
5154
5155 void TSequenceOfXYZ::clear()
5156 {
5157   myArray.clear();
5158 }
5159
5160 void TSequenceOfXYZ::reserve(size_type n)
5161 {
5162   myArray.reserve(n);
5163 }
5164
5165 void TSequenceOfXYZ::push_back(const gp_XYZ& v)
5166 {
5167   myArray.push_back(v);
5168 }
5169
5170 TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const
5171 {
5172   return myArray.size();
5173 }
5174
5175 SMDSAbs_EntityType TSequenceOfXYZ::getElementEntity() const
5176 {
5177   return myElem ? myElem->GetEntityType() : SMDSEntity_Last;
5178 }
5179
5180 TMeshModifTracer::TMeshModifTracer():
5181   myMeshModifTime(0), myMesh(0)
5182 {
5183 }
5184 void TMeshModifTracer::SetMesh( const SMDS_Mesh* theMesh )
5185 {
5186   if ( theMesh != myMesh )
5187     myMeshModifTime = 0;
5188   myMesh = theMesh;
5189 }
5190 bool TMeshModifTracer::IsMeshModified()
5191 {
5192   bool modified = false;
5193   if ( myMesh )
5194   {
5195     modified = ( myMeshModifTime != myMesh->GetMTime() );
5196     myMeshModifTime = myMesh->GetMTime();
5197   }
5198   return modified;
5199 }