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