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