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