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