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