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