Salome HOME
indenting
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
1 // Copyright (C) 2007-2019  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, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "SMESH_ControlsDef.hxx"
24
25 #include "SMDS_BallElement.hxx"
26 #include "SMDS_FacePosition.hxx"
27 #include "SMDS_Iterator.hxx"
28 #include "SMDS_Mesh.hxx"
29 #include "SMDS_MeshElement.hxx"
30 #include "SMDS_MeshNode.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMESHDS_GroupBase.hxx"
33 #include "SMESHDS_GroupOnFilter.hxx"
34 #include "SMESHDS_Mesh.hxx"
35 #include "SMESH_MeshAlgos.hxx"
36 #include "SMESH_OctreeNode.hxx"
37
38 #include <Basics_Utils.hxx>
39
40 #include <BRepAdaptor_Surface.hxx>
41 #include <BRepBndLib.hxx>
42 #include <BRepBuilderAPI_Copy.hxx>
43 #include <BRepClass3d_SolidClassifier.hxx>
44 #include <BRepClass_FaceClassifier.hxx>
45 #include <BRep_Tool.hxx>
46 #include <GeomLib_IsPlanarSurface.hxx>
47 #include <Geom_CylindricalSurface.hxx>
48 #include <Geom_Plane.hxx>
49 #include <Geom_Surface.hxx>
50 #include <NCollection_Map.hxx>
51 #include <Precision.hxx>
52 #include <ShapeAnalysis_Surface.hxx>
53 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
54 #include <TColStd_MapOfInteger.hxx>
55 #include <TColStd_SequenceOfAsciiString.hxx>
56 #include <TColgp_Array1OfXYZ.hxx>
57 #include <TopAbs.hxx>
58 #include <TopExp.hxx>
59 #include <TopoDS.hxx>
60 #include <TopoDS_Edge.hxx>
61 #include <TopoDS_Face.hxx>
62 #include <TopoDS_Iterator.hxx>
63 #include <TopoDS_Shape.hxx>
64 #include <TopoDS_Vertex.hxx>
65 #include <gp_Ax3.hxx>
66 #include <gp_Cylinder.hxx>
67 #include <gp_Dir.hxx>
68 #include <gp_Pln.hxx>
69 #include <gp_Pnt.hxx>
70 #include <gp_Vec.hxx>
71 #include <gp_XYZ.hxx>
72
73 #include <vtkMeshQuality.h>
74
75 #include <set>
76 #include <limits>
77
78 /*
79                             AUXILIARY METHODS
80 */
81
82 namespace {
83
84   const double theEps = 1e-100;
85   const double theInf = 1e+100;
86
87   inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode )
88   {
89     return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() );
90   }
91
92   inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
93   {
94     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
95
96     return v1.Magnitude() < gp::Resolution() ||
97       v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
98   }
99
100   inline double getCos2( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
101   {
102     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
103     double dot = v1 * v2, len1 = v1.SquareMagnitude(), len2 = v2.SquareMagnitude();
104
105     return ( dot < 0 || len1 < gp::Resolution() || len2 < gp::Resolution() ? -1 :
106              dot * dot / len1 / len2 );
107   }
108
109   inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
110   {
111     gp_Vec aVec1( P2 - P1 );
112     gp_Vec aVec2( P3 - P1 );
113     return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
114   }
115
116   inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
117   {
118     return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
119   }
120
121
122
123   inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
124   {
125     double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
126     return aDist;
127   }
128
129   int getNbMultiConnection( const SMDS_Mesh* theMesh, const int theId )
130   {
131     if ( theMesh == 0 )
132       return 0;
133
134     const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
135     if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */)
136       return 0;
137
138     // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge)
139     // count elements containing both nodes of the pair.
140     // Note that there may be such cases for a quadratic edge (a horizontal line):
141     //
142     //  Case 1          Case 2
143     //  |     |      |        |      |
144     //  |     |      |        |      |
145     //  +-----+------+  +-----+------+
146     //  |            |  |            |
147     //  |            |  |            |
148     // result should be 2 in both cases
149     //
150     int aResult0 = 0, aResult1 = 0;
151     // last node, it is a medium one in a quadratic edge
152     const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 );
153     const SMDS_MeshNode*    aNode0 = anEdge->GetNode( 0 );
154     const SMDS_MeshNode*    aNode1 = anEdge->GetNode( 1 );
155     if ( aNode1 == aLastNode ) aNode1 = 0;
156
157     SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator();
158     while( anElemIter->more() ) {
159       const SMDS_MeshElement* anElem = anElemIter->next();
160       if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
161         SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
162         while ( anIter->more() ) {
163           if ( const SMDS_MeshElement* anElemNode = anIter->next() ) {
164             if ( anElemNode == aNode0 ) {
165               aResult0++;
166               if ( !aNode1 ) break; // not a quadratic edge
167             }
168             else if ( anElemNode == aNode1 )
169               aResult1++;
170           }
171         }
172       }
173     }
174     int aResult = std::max ( aResult0, aResult1 );
175
176     return aResult;
177   }
178
179   gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 )
180   {
181     int aNbNode = theFace->NbNodes();
182
183     gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0));
184     gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0));
185     gp_XYZ n  = q1 ^ q2;
186     if ( aNbNode > 3 ) {
187       gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0));
188       n += q2 ^ q3;
189     }
190     double len = n.Modulus();
191     bool zeroLen = ( len <= std::numeric_limits<double>::min());
192     if ( !zeroLen )
193       n /= len;
194
195     if (ok) *ok = !zeroLen;
196
197     return n;
198   }
199 }
200
201
202
203 using namespace SMESH::Controls;
204
205 /*
206  *                               FUNCTORS
207  */
208
209 //================================================================================
210 /*
211   Class       : NumericalFunctor
212   Description : Base class for numerical functors
213 */
214 //================================================================================
215
216 NumericalFunctor::NumericalFunctor():
217   myMesh(NULL)
218 {
219   myPrecision = -1;
220 }
221
222 void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh )
223 {
224   myMesh = theMesh;
225 }
226
227 bool NumericalFunctor::GetPoints(const int       theId,
228                                  TSequenceOfXYZ& theRes ) const
229 {
230   theRes.clear();
231
232   if ( myMesh == 0 )
233     return false;
234
235   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
236   if ( !IsApplicable( anElem ))
237     return false;
238
239   return GetPoints( anElem, theRes );
240 }
241
242 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
243                                  TSequenceOfXYZ&         theRes )
244 {
245   theRes.clear();
246
247   if ( anElem == 0 )
248     return false;
249
250   theRes.reserve( anElem->NbNodes() );
251   theRes.setElement( anElem );
252
253   // Get nodes of the element
254   SMDS_NodeIteratorPtr anIter= anElem->interlacedNodesIterator();
255   if ( anIter ) {
256     SMESH_NodeXYZ p;
257     while( anIter->more() ) {
258       if ( p.Set( anIter->next() ))
259         theRes.push_back( p );
260     }
261   }
262
263   return true;
264 }
265
266 long  NumericalFunctor::GetPrecision() const
267 {
268   return myPrecision;
269 }
270
271 void  NumericalFunctor::SetPrecision( const long thePrecision )
272 {
273   myPrecision = thePrecision;
274   myPrecisionValue = pow( 10., (double)( myPrecision ) );
275 }
276
277 double NumericalFunctor::GetValue( long theId )
278 {
279   double aVal = 0;
280
281   myCurrElement = myMesh->FindElement( theId );
282
283   TSequenceOfXYZ P;
284   if ( GetPoints( theId, P )) // elem type is checked here
285     aVal = Round( GetValue( P ));
286
287   return aVal;
288 }
289
290 double NumericalFunctor::Round( const double & aVal )
291 {
292   return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
293 }
294
295 //================================================================================
296 /*!
297  * \brief Return true if a value can be computed for a given element.
298  *        Some NumericalFunctor's are meaningful for elements of a certain
299  *        geometry only.
300  */
301 //================================================================================
302
303 bool NumericalFunctor::IsApplicable( const SMDS_MeshElement* element ) const
304 {
305   return element && element->GetType() == this->GetType();
306 }
307
308 bool NumericalFunctor::IsApplicable( long theElementId ) const
309 {
310   return IsApplicable( myMesh->FindElement( theElementId ));
311 }
312
313 //================================================================================
314 /*!
315  * \brief Return histogram of functor values
316  *  \param nbIntervals - number of intervals
317  *  \param nbEvents - number of mesh elements having values within i-th interval
318  *  \param funValues - boundaries of intervals
319  *  \param elements - elements to check vulue of; empty list means "of all"
320  *  \param minmax - boundaries of diapason of values to divide into intervals
321  */
322 //================================================================================
323
324 void NumericalFunctor::GetHistogram(int                     nbIntervals,
325                                     std::vector<int>&       nbEvents,
326                                     std::vector<double>&    funValues,
327                                     const std::vector<int>& elements,
328                                     const double*           minmax,
329                                     const bool              isLogarithmic)
330 {
331   if ( nbIntervals < 1 ||
332        !myMesh ||
333        !myMesh->GetMeshInfo().NbElements( GetType() ))
334     return;
335   nbEvents.resize( nbIntervals, 0 );
336   funValues.resize( nbIntervals+1 );
337
338   // get all values sorted
339   std::multiset< double > values;
340   if ( elements.empty() )
341   {
342     SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() );
343     while ( elemIt->more() )
344       values.insert( GetValue( elemIt->next()->GetID() ));
345   }
346   else
347   {
348     std::vector<int>::const_iterator id = elements.begin();
349     for ( ; id != elements.end(); ++id )
350       values.insert( GetValue( *id ));
351   }
352
353   if ( minmax )
354   {
355     funValues[0] = minmax[0];
356     funValues[nbIntervals] = minmax[1];
357   }
358   else
359   {
360     funValues[0] = *values.begin();
361     funValues[nbIntervals] = *values.rbegin();
362   }
363   // case nbIntervals == 1
364   if ( nbIntervals == 1 )
365   {
366     nbEvents[0] = values.size();
367     return;
368   }
369   // case of 1 value
370   if (funValues.front() == funValues.back())
371   {
372     nbEvents.resize( 1 );
373     nbEvents[0] = values.size();
374     funValues[1] = funValues.back();
375     funValues.resize( 2 );
376   }
377   // generic case
378   std::multiset< double >::iterator min = values.begin(), max;
379   for ( int i = 0; i < nbIntervals; ++i )
380   {
381     // find end value of i-th interval
382     double r = (i+1) / double(nbIntervals);
383     if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) {
384       double logmin = log10(funValues.front());
385       double lval = logmin + r * (log10(funValues.back()) - logmin);
386       funValues[i+1] = pow(10.0, lval);
387     }
388     else {
389       funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r;
390     }
391
392     // count values in the i-th interval if there are any
393     if ( min != values.end() && *min <= funValues[i+1] )
394     {
395       // find the first value out of the interval
396       max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end()
397       nbEvents[i] = std::distance( min, max );
398       min = max;
399     }
400   }
401   // add values larger than minmax[1]
402   nbEvents.back() += std::distance( min, values.end() );
403 }
404
405 //=======================================================================
406 /*
407   Class       : Volume
408   Description : Functor calculating volume of a 3D element
409 */
410 //================================================================================
411
412 double Volume::GetValue( long theElementId )
413 {
414   if ( theElementId && myMesh ) {
415     SMDS_VolumeTool aVolumeTool;
416     if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
417       return aVolumeTool.GetSize();
418   }
419   return 0;
420 }
421
422 double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const
423 {
424   return Value;
425 }
426
427 SMDSAbs_ElementType Volume::GetType() const
428 {
429   return SMDSAbs_Volume;
430 }
431
432 //=======================================================================
433 /*
434   Class       : MaxElementLength2D
435   Description : Functor calculating maximum length of 2D element
436 */
437 //================================================================================
438
439 double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P )
440 {
441   if(P.size() == 0)
442     return 0.;
443   double aVal = 0;
444   int len = P.size();
445   if( len == 3 ) { // triangles
446     double L1 = getDistance(P( 1 ),P( 2 ));
447     double L2 = getDistance(P( 2 ),P( 3 ));
448     double L3 = getDistance(P( 3 ),P( 1 ));
449     aVal = Max(L1,Max(L2,L3));
450   }
451   else if( len == 4 ) { // quadrangles
452     double L1 = getDistance(P( 1 ),P( 2 ));
453     double L2 = getDistance(P( 2 ),P( 3 ));
454     double L3 = getDistance(P( 3 ),P( 4 ));
455     double L4 = getDistance(P( 4 ),P( 1 ));
456     double D1 = getDistance(P( 1 ),P( 3 ));
457     double D2 = getDistance(P( 2 ),P( 4 ));
458     aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
459   }
460   else if( len == 6 ) { // quadratic triangles
461     double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
462     double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
463     double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
464     aVal = Max(L1,Max(L2,L3));
465   }
466   else if( len == 8 || len == 9 ) { // quadratic quadrangles
467     double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
468     double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
469     double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
470     double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
471     double D1 = getDistance(P( 1 ),P( 5 ));
472     double D2 = getDistance(P( 3 ),P( 7 ));
473     aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
474   }
475   // Diagonals are undefined for concave polygons
476   // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon
477   // {
478   //   // sides
479   //   aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 ));
480   //   for ( size_t i = 1; i < P.size()-1; i += 2 )
481   //   {
482   //     double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 ));
483   //     aVal = Max( aVal, L );
484   //   }
485   //   // diagonals
486   //   for ( int i = P.size()-5; i > 0; i -= 2 )
487   //     for ( int j = i + 4; j < P.size() + i - 2; i += 2 )
488   //     {
489   //       double D = getDistance( P( i ), P( j ));
490   //       aVal = Max( aVal, D );
491   //     }
492   // }
493   // { // polygons
494
495   // }
496
497   if( myPrecision >= 0 )
498   {
499     double prec = pow( 10., (double)myPrecision );
500     aVal = floor( aVal * prec + 0.5 ) / prec;
501   }
502   return aVal;
503 }
504
505 double MaxElementLength2D::GetValue( long theElementId )
506 {
507   TSequenceOfXYZ P;
508   return GetPoints( theElementId, P ) ? GetValue(P) : 0.0;
509 }
510
511 double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const
512 {
513   return Value;
514 }
515
516 SMDSAbs_ElementType MaxElementLength2D::GetType() const
517 {
518   return SMDSAbs_Face;
519 }
520
521 //=======================================================================
522 /*
523   Class       : MaxElementLength3D
524   Description : Functor calculating maximum length of 3D element
525 */
526 //================================================================================
527
528 double MaxElementLength3D::GetValue( long theElementId )
529 {
530   TSequenceOfXYZ P;
531   if( GetPoints( theElementId, P ) ) {
532     double aVal = 0;
533     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
534     SMDSAbs_EntityType      aType = aElem->GetEntityType();
535     int len = P.size();
536     switch ( aType ) {
537     case SMDSEntity_Tetra: { // tetras
538       double L1 = getDistance(P( 1 ),P( 2 ));
539       double L2 = getDistance(P( 2 ),P( 3 ));
540       double L3 = getDistance(P( 3 ),P( 1 ));
541       double L4 = getDistance(P( 1 ),P( 4 ));
542       double L5 = getDistance(P( 2 ),P( 4 ));
543       double L6 = getDistance(P( 3 ),P( 4 ));
544       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
545       break;
546     }
547     case SMDSEntity_Pyramid: { // pyramids
548       double L1 = getDistance(P( 1 ),P( 2 ));
549       double L2 = getDistance(P( 2 ),P( 3 ));
550       double L3 = getDistance(P( 3 ),P( 4 ));
551       double L4 = getDistance(P( 4 ),P( 1 ));
552       double L5 = getDistance(P( 1 ),P( 5 ));
553       double L6 = getDistance(P( 2 ),P( 5 ));
554       double L7 = getDistance(P( 3 ),P( 5 ));
555       double L8 = getDistance(P( 4 ),P( 5 ));
556       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
557       aVal = Max(aVal,Max(L7,L8));
558       break;
559     }
560     case SMDSEntity_Penta: { // pentas
561       double L1 = getDistance(P( 1 ),P( 2 ));
562       double L2 = getDistance(P( 2 ),P( 3 ));
563       double L3 = getDistance(P( 3 ),P( 1 ));
564       double L4 = getDistance(P( 4 ),P( 5 ));
565       double L5 = getDistance(P( 5 ),P( 6 ));
566       double L6 = getDistance(P( 6 ),P( 4 ));
567       double L7 = getDistance(P( 1 ),P( 4 ));
568       double L8 = getDistance(P( 2 ),P( 5 ));
569       double L9 = getDistance(P( 3 ),P( 6 ));
570       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
571       aVal = Max(aVal,Max(Max(L7,L8),L9));
572       break;
573     }
574     case SMDSEntity_Hexa: { // hexas
575       double L1 = getDistance(P( 1 ),P( 2 ));
576       double L2 = getDistance(P( 2 ),P( 3 ));
577       double L3 = getDistance(P( 3 ),P( 4 ));
578       double L4 = getDistance(P( 4 ),P( 1 ));
579       double L5 = getDistance(P( 5 ),P( 6 ));
580       double L6 = getDistance(P( 6 ),P( 7 ));
581       double L7 = getDistance(P( 7 ),P( 8 ));
582       double L8 = getDistance(P( 8 ),P( 5 ));
583       double L9 = getDistance(P( 1 ),P( 5 ));
584       double L10= getDistance(P( 2 ),P( 6 ));
585       double L11= getDistance(P( 3 ),P( 7 ));
586       double L12= getDistance(P( 4 ),P( 8 ));
587       double D1 = getDistance(P( 1 ),P( 7 ));
588       double D2 = getDistance(P( 2 ),P( 8 ));
589       double D3 = getDistance(P( 3 ),P( 5 ));
590       double D4 = getDistance(P( 4 ),P( 6 ));
591       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
592       aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
593       aVal = Max(aVal,Max(L11,L12));
594       aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
595       break;
596     }
597     case SMDSEntity_Hexagonal_Prism: { // hexagonal prism
598       for ( int i1 = 1; i1 < 12; ++i1 )
599         for ( int i2 = i1+1; i1 <= 12; ++i1 )
600           aVal = Max( aVal, getDistance(P( i1 ),P( i2 )));
601       break;
602     }
603     case SMDSEntity_Quad_Tetra: { // quadratic tetras
604       double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
605       double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
606       double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
607       double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
608       double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
609       double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
610       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
611       break;
612     }
613     case SMDSEntity_Quad_Pyramid: { // quadratic pyramids
614       double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
615       double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
616       double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
617       double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
618       double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
619       double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
620       double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
621       double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
622       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
623       aVal = Max(aVal,Max(L7,L8));
624       break;
625     }
626     case SMDSEntity_Quad_Penta:
627     case SMDSEntity_BiQuad_Penta: { // quadratic pentas
628       double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
629       double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
630       double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
631       double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
632       double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
633       double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
634       double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
635       double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
636       double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
637       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
638       aVal = Max(aVal,Max(Max(L7,L8),L9));
639       break;
640     }
641     case SMDSEntity_Quad_Hexa:
642     case SMDSEntity_TriQuad_Hexa: { // quadratic hexas
643       double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
644       double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
645       double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
646       double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
647       double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
648       double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
649       double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
650       double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
651       double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
652       double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
653       double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
654       double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
655       double D1 = getDistance(P( 1 ),P( 7 ));
656       double D2 = getDistance(P( 2 ),P( 8 ));
657       double D3 = getDistance(P( 3 ),P( 5 ));
658       double D4 = getDistance(P( 4 ),P( 6 ));
659       aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
660       aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
661       aVal = Max(aVal,Max(L11,L12));
662       aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
663       break;
664     }
665     case SMDSEntity_Quad_Polyhedra:
666     case SMDSEntity_Polyhedra: { // polys
667       // get the maximum distance between all pairs of nodes
668       for( int i = 1; i <= len; i++ ) {
669         for( int j = 1; j <= len; j++ ) {
670           if( j > i ) { // optimization of the loop
671             double D = getDistance( P(i), P(j) );
672             aVal = Max( aVal, D );
673           }
674         }
675       }
676       break;
677     }
678     case SMDSEntity_Node:
679     case SMDSEntity_0D:
680     case SMDSEntity_Edge:
681     case SMDSEntity_Quad_Edge:
682     case SMDSEntity_Triangle:
683     case SMDSEntity_Quad_Triangle:
684     case SMDSEntity_BiQuad_Triangle:
685     case SMDSEntity_Quadrangle:
686     case SMDSEntity_Quad_Quadrangle:
687     case SMDSEntity_BiQuad_Quadrangle:
688     case SMDSEntity_Polygon:
689     case SMDSEntity_Quad_Polygon:
690     case SMDSEntity_Ball:
691     case SMDSEntity_Last: return 0;
692     } // switch ( aType )
693
694     if( myPrecision >= 0 )
695     {
696       double prec = pow( 10., (double)myPrecision );
697       aVal = floor( aVal * prec + 0.5 ) / prec;
698     }
699     return aVal;
700   }
701   return 0.;
702 }
703
704 double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const
705 {
706   return Value;
707 }
708
709 SMDSAbs_ElementType MaxElementLength3D::GetType() const
710 {
711   return SMDSAbs_Volume;
712 }
713
714 //=======================================================================
715 /*
716   Class       : MinimumAngle
717   Description : Functor for calculation of minimum angle
718 */
719 //================================================================================
720
721 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
722 {
723   if ( P.size() < 3 )
724     return 0.;
725
726   double aMaxCos2;
727
728   aMaxCos2 = getCos2( P( P.size() ), P( 1 ), P( 2 ));
729   aMaxCos2 = Max( aMaxCos2, getCos2( P( P.size()-1 ), P( P.size() ), P( 1 )));
730
731   for ( size_t i = 2; i < P.size(); i++ )
732   {
733     double A0 = getCos2( P( i-1 ), P( i ), P( i+1 ) );
734     aMaxCos2 = Max( aMaxCos2, A0 );
735   }
736   if ( aMaxCos2 < 0 )
737     return 0; // all nodes coincide
738
739   double cos = sqrt( aMaxCos2 );
740   if ( cos >=  1 ) return 0;
741   return acos( cos ) * 180.0 / M_PI;
742 }
743
744 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
745 {
746   //const double aBestAngle = PI / nbNodes;
747   const double aBestAngle = 180.0 - ( 360.0 / double(nbNodes) );
748   return ( fabs( aBestAngle - Value ));
749 }
750
751 SMDSAbs_ElementType MinimumAngle::GetType() const
752 {
753   return SMDSAbs_Face;
754 }
755
756
757 //================================================================================
758 /*
759   Class       : AspectRatio
760   Description : Functor for calculating aspect ratio
761 */
762 //================================================================================
763
764 double AspectRatio::GetValue( long theId )
765 {
766   double aVal = 0;
767   myCurrElement = myMesh->FindElement( theId );
768   TSequenceOfXYZ P;
769   if ( GetPoints( myCurrElement, P ))
770     aVal = Round( GetValue( P ));
771   return aVal;
772 }
773
774 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
775 {
776   // According to "Mesh quality control" by Nadir Bouhamau referring to
777   // Pascal Jean Frey and Paul-Louis George. Maillages, applications aux elements finis.
778   // Hermes Science publications, Paris 1999 ISBN 2-7462-0024-4
779   // PAL10872
780
781   int nbNodes = P.size();
782
783   if ( nbNodes < 3 )
784     return 0;
785
786   // Compute aspect ratio
787
788   if ( nbNodes == 3 ) {
789     // Compute lengths of the sides
790     double aLen1 = getDistance( P( 1 ), P( 2 ));
791     double aLen2 = getDistance( P( 2 ), P( 3 ));
792     double aLen3 = getDistance( P( 3 ), P( 1 ));
793     // Q = alfa * h * p / S, where
794     //
795     // alfa = sqrt( 3 ) / 6
796     // h - length of the longest edge
797     // p - half perimeter
798     // S - triangle surface
799     const double     alfa = sqrt( 3. ) / 6.;
800     double         maxLen = Max( aLen1, Max( aLen2, aLen3 ));
801     double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.;
802     double         anArea = getArea( P( 1 ), P( 2 ), P( 3 ));
803     if ( anArea <= theEps  )
804       return theInf;
805     return alfa * maxLen * half_perimeter / anArea;
806   }
807   else if ( nbNodes == 6 ) { // quadratic triangles
808     // Compute lengths of the sides
809     double aLen1 = getDistance( P( 1 ), P( 3 ));
810     double aLen2 = getDistance( P( 3 ), P( 5 ));
811     double aLen3 = getDistance( P( 5 ), P( 1 ));
812     // algo same as for the linear triangle
813     const double     alfa = sqrt( 3. ) / 6.;
814     double         maxLen = Max( aLen1, Max( aLen2, aLen3 ));
815     double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.;
816     double         anArea = getArea( P( 1 ), P( 3 ), P( 5 ));
817     if ( anArea <= theEps )
818       return theInf;
819     return alfa * maxLen * half_perimeter / anArea;
820   }
821   else if( nbNodes == 4 ) { // quadrangle
822     // Compute lengths of the sides
823     double aLen[4];
824     aLen[0] = getDistance( P(1), P(2) );
825     aLen[1] = getDistance( P(2), P(3) );
826     aLen[2] = getDistance( P(3), P(4) );
827     aLen[3] = getDistance( P(4), P(1) );
828     // Compute lengths of the diagonals
829     double aDia[2];
830     aDia[0] = getDistance( P(1), P(3) );
831     aDia[1] = getDistance( P(2), P(4) );
832     // Compute areas of all triangles which can be built
833     // taking three nodes of the quadrangle
834     double anArea[4];
835     anArea[0] = getArea( P(1), P(2), P(3) );
836     anArea[1] = getArea( P(1), P(2), P(4) );
837     anArea[2] = getArea( P(1), P(3), P(4) );
838     anArea[3] = getArea( P(2), P(3), P(4) );
839     // Q = alpha * L * C1 / C2, where
840     //
841     // alpha = sqrt( 1/32 )
842     // L = max( L1, L2, L3, L4, D1, D2 )
843     // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 )
844     // C2 = min( S1, S2, S3, S4 )
845     // Li - lengths of the edges
846     // Di - lengths of the diagonals
847     // Si - areas of the triangles
848     const double alpha = sqrt( 1 / 32. );
849     double L = Max( aLen[ 0 ],
850                     Max( aLen[ 1 ],
851                          Max( aLen[ 2 ],
852                               Max( aLen[ 3 ],
853                                    Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
854     double C1 = sqrt( aLen[0] * aLen[0] +
855                       aLen[1] * aLen[1] +
856                       aLen[2] * aLen[2] +
857                       aLen[3] * aLen[3] );
858     double C2 = Min( anArea[ 0 ],
859                      Min( anArea[ 1 ],
860                           Min( anArea[ 2 ], anArea[ 3 ] ) ) );
861     if ( C2 <= theEps )
862       return theInf;
863     return alpha * L * C1 / C2;
864   }
865   else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle
866     // Compute lengths of the sides
867     double aLen[4];
868     aLen[0] = getDistance( P(1), P(3) );
869     aLen[1] = getDistance( P(3), P(5) );
870     aLen[2] = getDistance( P(5), P(7) );
871     aLen[3] = getDistance( P(7), P(1) );
872     // Compute lengths of the diagonals
873     double aDia[2];
874     aDia[0] = getDistance( P(1), P(5) );
875     aDia[1] = getDistance( P(3), P(7) );
876     // Compute areas of all triangles which can be built
877     // taking three nodes of the quadrangle
878     double anArea[4];
879     anArea[0] = getArea( P(1), P(3), P(5) );
880     anArea[1] = getArea( P(1), P(3), P(7) );
881     anArea[2] = getArea( P(1), P(5), P(7) );
882     anArea[3] = getArea( P(3), P(5), P(7) );
883     // Q = alpha * L * C1 / C2, where
884     //
885     // alpha = sqrt( 1/32 )
886     // L = max( L1, L2, L3, L4, D1, D2 )
887     // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 )
888     // C2 = min( S1, S2, S3, S4 )
889     // Li - lengths of the edges
890     // Di - lengths of the diagonals
891     // Si - areas of the triangles
892     const double alpha = sqrt( 1 / 32. );
893     double L = Max( aLen[ 0 ],
894                     Max( aLen[ 1 ],
895                          Max( aLen[ 2 ],
896                               Max( aLen[ 3 ],
897                                    Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
898     double C1 = sqrt( aLen[0] * aLen[0] +
899                       aLen[1] * aLen[1] +
900                       aLen[2] * aLen[2] +
901                       aLen[3] * aLen[3] );
902     double C2 = Min( anArea[ 0 ],
903                      Min( anArea[ 1 ],
904                           Min( anArea[ 2 ], anArea[ 3 ] ) ) );
905     if ( C2 <= theEps )
906       return theInf;
907     return alpha * L * C1 / C2;
908   }
909   return 0;
910 }
911
912 bool AspectRatio::IsApplicable( const SMDS_MeshElement* element ) const
913 {
914   return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
915 }
916
917 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
918 {
919   // the aspect ratio is in the range [1.0,infinity]
920   // < 1.0 = very bad, zero area
921   // 1.0 = good
922   // infinity = bad
923   return ( Value < 0.9 ) ? 1000 : Value / 1000.;
924 }
925
926 SMDSAbs_ElementType AspectRatio::GetType() const
927 {
928   return SMDSAbs_Face;
929 }
930
931
932 //================================================================================
933 /*
934   Class       : AspectRatio3D
935   Description : Functor for calculating aspect ratio
936 */
937 //================================================================================
938
939 namespace{
940
941   inline double getHalfPerimeter(double theTria[3]){
942     return (theTria[0] + theTria[1] + theTria[2])/2.0;
943   }
944
945   inline double getArea(double theHalfPerim, double theTria[3]){
946     return sqrt(theHalfPerim*
947                 (theHalfPerim-theTria[0])*
948                 (theHalfPerim-theTria[1])*
949                 (theHalfPerim-theTria[2]));
950   }
951
952   inline double getVolume(double theLen[6]){
953     double a2 = theLen[0]*theLen[0];
954     double b2 = theLen[1]*theLen[1];
955     double c2 = theLen[2]*theLen[2];
956     double d2 = theLen[3]*theLen[3];
957     double e2 = theLen[4]*theLen[4];
958     double f2 = theLen[5]*theLen[5];
959     double P = 4.0*a2*b2*d2;
960     double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
961     double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
962     return sqrt(P-Q+R)/12.0;
963   }
964
965   inline double getVolume2(double theLen[6]){
966     double a2 = theLen[0]*theLen[0];
967     double b2 = theLen[1]*theLen[1];
968     double c2 = theLen[2]*theLen[2];
969     double d2 = theLen[3]*theLen[3];
970     double e2 = theLen[4]*theLen[4];
971     double f2 = theLen[5]*theLen[5];
972
973     double P = a2*e2*(b2+c2+d2+f2-a2-e2);
974     double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
975     double R = c2*d2*(a2+b2+e2+f2-c2-d2);
976     double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
977
978     return sqrt(P+Q+R-S)/12.0;
979   }
980
981   inline double getVolume(const TSequenceOfXYZ& P){
982     gp_Vec aVec1( P( 2 ) - P( 1 ) );
983     gp_Vec aVec2( P( 3 ) - P( 1 ) );
984     gp_Vec aVec3( P( 4 ) - P( 1 ) );
985     gp_Vec anAreaVec( aVec1 ^ aVec2 );
986     return fabs(aVec3 * anAreaVec) / 6.0;
987   }
988
989   inline double getMaxHeight(double theLen[6])
990   {
991     double aHeight = std::max(theLen[0],theLen[1]);
992     aHeight = std::max(aHeight,theLen[2]);
993     aHeight = std::max(aHeight,theLen[3]);
994     aHeight = std::max(aHeight,theLen[4]);
995     aHeight = std::max(aHeight,theLen[5]);
996     return aHeight;
997   }
998
999 }
1000
1001 double AspectRatio3D::GetValue( long theId )
1002 {
1003   double aVal = 0;
1004   myCurrElement = myMesh->FindElement( theId );
1005   if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA )
1006   {
1007     // Action from CoTech | ACTION 31.3:
1008     // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with
1009     // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH.
1010     vtkUnstructuredGrid* grid = const_cast<SMDS_Mesh*>( myMesh )->GetGrid();
1011     if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() ))
1012       aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell ));
1013   }
1014   else
1015   {
1016     TSequenceOfXYZ P;
1017     if ( GetPoints( myCurrElement, P ))
1018       aVal = Round( GetValue( P ));
1019   }
1020   return aVal;
1021 }
1022
1023 bool AspectRatio3D::IsApplicable( const SMDS_MeshElement* element ) const
1024 {
1025   return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
1026 }
1027
1028 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
1029 {
1030   double aQuality = 0.0;
1031   if(myCurrElement->IsPoly()) return aQuality;
1032
1033   int nbNodes = P.size();
1034
1035   if( myCurrElement->IsQuadratic() ) {
1036     if     (nbNodes==10) nbNodes=4; // quadratic tetrahedron
1037     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
1038     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
1039     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
1040     else if(nbNodes==27) nbNodes=8; // tri-quadratic hexahedron
1041     else return aQuality;
1042   }
1043
1044   switch(nbNodes) {
1045   case 4:{
1046     double aLen[6] = {
1047       getDistance(P( 1 ),P( 2 )), // a
1048       getDistance(P( 2 ),P( 3 )), // b
1049       getDistance(P( 3 ),P( 1 )), // c
1050       getDistance(P( 2 ),P( 4 )), // d
1051       getDistance(P( 3 ),P( 4 )), // e
1052       getDistance(P( 1 ),P( 4 ))  // f
1053     };
1054     double aTria[4][3] = {
1055       {aLen[0],aLen[1],aLen[2]}, // abc
1056       {aLen[0],aLen[3],aLen[5]}, // adf
1057       {aLen[1],aLen[3],aLen[4]}, // bde
1058       {aLen[2],aLen[4],aLen[5]}  // cef
1059     };
1060     double aSumArea = 0.0;
1061     double aHalfPerimeter = getHalfPerimeter(aTria[0]);
1062     double anArea = getArea(aHalfPerimeter,aTria[0]);
1063     aSumArea += anArea;
1064     aHalfPerimeter = getHalfPerimeter(aTria[1]);
1065     anArea = getArea(aHalfPerimeter,aTria[1]);
1066     aSumArea += anArea;
1067     aHalfPerimeter = getHalfPerimeter(aTria[2]);
1068     anArea = getArea(aHalfPerimeter,aTria[2]);
1069     aSumArea += anArea;
1070     aHalfPerimeter = getHalfPerimeter(aTria[3]);
1071     anArea = getArea(aHalfPerimeter,aTria[3]);
1072     aSumArea += anArea;
1073     double aVolume = getVolume(P);
1074     //double aVolume = getVolume(aLen);
1075     double aHeight = getMaxHeight(aLen);
1076     static double aCoeff = sqrt(2.0)/12.0;
1077     if ( aVolume > DBL_MIN )
1078       aQuality = aCoeff*aHeight*aSumArea/aVolume;
1079     break;
1080   }
1081   case 5:{
1082     {
1083       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
1084       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1085     }
1086     {
1087       gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
1088       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1089     }
1090     {
1091       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
1092       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1093     }
1094     {
1095       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
1096       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1097     }
1098     break;
1099   }
1100   case 6:{
1101     {
1102       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
1103       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1104     }
1105     {
1106       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
1107       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1108     }
1109     {
1110       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
1111       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1112     }
1113     {
1114       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1115       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1116     }
1117     {
1118       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
1119       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1120     }
1121     {
1122       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
1123       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1124     }
1125     break;
1126   }
1127   case 8:{
1128     {
1129       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1130       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1131     }
1132     {
1133       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
1134       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1135     }
1136     {
1137       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
1138       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1139     }
1140     {
1141       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
1142       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1143     }
1144     {
1145       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
1146       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1147     }
1148     {
1149       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
1150       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1151     }
1152     {
1153       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
1154       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1155     }
1156     {
1157       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
1158       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1159     }
1160     {
1161       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
1162       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1163     }
1164     {
1165       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
1166       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1167     }
1168     {
1169       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
1170       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1171     }
1172     {
1173       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
1174       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1175     }
1176     {
1177       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
1178       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1179     }
1180     {
1181       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
1182       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1183     }
1184     {
1185       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
1186       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1187     }
1188     {
1189       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
1190       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1191     }
1192     {
1193       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
1194       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1195     }
1196     {
1197       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
1198       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1199     }
1200     {
1201       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
1202       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1203     }
1204     {
1205       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
1206       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1207     }
1208     {
1209       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
1210       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1211     }
1212     {
1213       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1214       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1215     }
1216     {
1217       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
1218       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1219     }
1220     {
1221       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
1222       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1223     }
1224     {
1225       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1226       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1227     }
1228     {
1229       gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
1230       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1231     }
1232     {
1233       gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
1234       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1235     }
1236     {
1237       gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
1238       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1239     }
1240     {
1241       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
1242       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1243     }
1244     {
1245       gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
1246       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1247     }
1248     {
1249       gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
1250       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1251     }
1252     {
1253       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
1254       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1255     }
1256     {
1257       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
1258       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1259     }
1260     break;
1261   }
1262   case 12:
1263     {
1264       gp_XYZ aXYZ[8] = {P( 1 ),P( 2 ),P( 4 ),P( 5 ),P( 7 ),P( 8 ),P( 10 ),P( 11 )};
1265       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1266     }
1267     {
1268       gp_XYZ aXYZ[8] = {P( 2 ),P( 3 ),P( 5 ),P( 6 ),P( 8 ),P( 9 ),P( 11 ),P( 12 )};
1269       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1270     }
1271     {
1272       gp_XYZ aXYZ[8] = {P( 3 ),P( 4 ),P( 6 ),P( 1 ),P( 9 ),P( 10 ),P( 12 ),P( 7 )};
1273       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1274     }
1275     break;
1276   } // switch(nbNodes)
1277
1278   if ( nbNodes > 4 ) {
1279     // evaluate aspect ratio of quadrangle faces
1280     AspectRatio aspect2D;
1281     SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes );
1282     int nbFaces = SMDS_VolumeTool::NbFaces( type );
1283     TSequenceOfXYZ points(4);
1284     for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume
1285       if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 )
1286         continue;
1287       const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true );
1288       for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadrangle face
1289         points( p + 1 ) = P( pInd[ p ] + 1 );
1290       aQuality = std::max( aQuality, aspect2D.GetValue( points ));
1291     }
1292   }
1293   return aQuality;
1294 }
1295
1296 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
1297 {
1298   // the aspect ratio is in the range [1.0,infinity]
1299   // 1.0 = good
1300   // infinity = bad
1301   return Value / 1000.;
1302 }
1303
1304 SMDSAbs_ElementType AspectRatio3D::GetType() const
1305 {
1306   return SMDSAbs_Volume;
1307 }
1308
1309
1310 //================================================================================
1311 /*
1312   Class       : Warping
1313   Description : Functor for calculating warping
1314 */
1315 //================================================================================
1316
1317 bool Warping::IsApplicable( const SMDS_MeshElement* element ) const
1318 {
1319   return NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4;
1320 }
1321
1322 double Warping::GetValue( const TSequenceOfXYZ& P )
1323 {
1324   if ( P.size() != 4 )
1325     return 0;
1326
1327   gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4.;
1328
1329   double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G );
1330   double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G );
1331   double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G );
1332   double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G );
1333
1334   double val = Max( Max( A1, A2 ), Max( A3, A4 ) );
1335
1336   const double eps = 0.1; // val is in degrees
1337
1338   return val < eps ? 0. : val;
1339 }
1340
1341 double Warping::ComputeA( const gp_XYZ& thePnt1,
1342                           const gp_XYZ& thePnt2,
1343                           const gp_XYZ& thePnt3,
1344                           const gp_XYZ& theG ) const
1345 {
1346   double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
1347   double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
1348   double L = Min( aLen1, aLen2 ) * 0.5;
1349   if ( L < theEps )
1350     return theInf;
1351
1352   gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG;
1353   gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG;
1354   gp_XYZ N  = GI.Crossed( GJ );
1355
1356   if ( N.Modulus() < gp::Resolution() )
1357     return M_PI / 2;
1358
1359   N.Normalize();
1360
1361   double H = ( thePnt2 - theG ).Dot( N );
1362   return asin( fabs( H / L ) ) * 180. / M_PI;
1363 }
1364
1365 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
1366 {
1367   // the warp is in the range [0.0,PI/2]
1368   // 0.0 = good (no warp)
1369   // PI/2 = bad  (face pliee)
1370   return Value;
1371 }
1372
1373 SMDSAbs_ElementType Warping::GetType() const
1374 {
1375   return SMDSAbs_Face;
1376 }
1377
1378
1379 //================================================================================
1380 /*
1381   Class       : Taper
1382   Description : Functor for calculating taper
1383 */
1384 //================================================================================
1385
1386 bool Taper::IsApplicable( const SMDS_MeshElement* element ) const
1387 {
1388   return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4 );
1389 }
1390
1391 double Taper::GetValue( const TSequenceOfXYZ& P )
1392 {
1393   if ( P.size() != 4 )
1394     return 0.;
1395
1396   // Compute taper
1397   double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) );
1398   double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) );
1399   double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) );
1400   double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) );
1401
1402   double JA = 0.25 * ( J1 + J2 + J3 + J4 );
1403   if ( JA <= theEps )
1404     return theInf;
1405
1406   double T1 = fabs( ( J1 - JA ) / JA );
1407   double T2 = fabs( ( J2 - JA ) / JA );
1408   double T3 = fabs( ( J3 - JA ) / JA );
1409   double T4 = fabs( ( J4 - JA ) / JA );
1410
1411   double val = Max( Max( T1, T2 ), Max( T3, T4 ) );
1412
1413   const double eps = 0.01;
1414
1415   return val < eps ? 0. : val;
1416 }
1417
1418 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
1419 {
1420   // the taper is in the range [0.0,1.0]
1421   // 0.0 = good (no taper)
1422   // 1.0 = bad  (les cotes opposes sont allignes)
1423   return Value;
1424 }
1425
1426 SMDSAbs_ElementType Taper::GetType() const
1427 {
1428   return SMDSAbs_Face;
1429 }
1430
1431 //================================================================================
1432 /*
1433   Class       : Skew
1434   Description : Functor for calculating skew in degrees
1435 */
1436 //================================================================================
1437
1438 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
1439 {
1440   gp_XYZ p12 = ( p2 + p1 ) / 2.;
1441   gp_XYZ p23 = ( p3 + p2 ) / 2.;
1442   gp_XYZ p31 = ( p3 + p1 ) / 2.;
1443
1444   gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
1445
1446   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
1447 }
1448
1449 bool Skew::IsApplicable( const SMDS_MeshElement* element ) const
1450 {
1451   return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() <= 4 );
1452 }
1453
1454 double Skew::GetValue( const TSequenceOfXYZ& P )
1455 {
1456   if ( P.size() != 3 && P.size() != 4 )
1457     return 0.;
1458
1459   // Compute skew
1460   const double PI2 = M_PI / 2.;
1461   if ( P.size() == 3 )
1462   {
1463     double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
1464     double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
1465     double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
1466
1467     return Max( A0, Max( A1, A2 ) ) * 180. / M_PI;
1468   }
1469   else
1470   {
1471     gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2.;
1472     gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2.;
1473     gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2.;
1474     gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2.;
1475
1476     gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
1477     double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
1478       ? 0. : fabs( PI2 - v1.Angle( v2 ) );
1479
1480     double val = A * 180. / M_PI;
1481
1482     const double eps = 0.1; // val is in degrees
1483
1484     return val < eps ? 0. : val;
1485   }
1486 }
1487
1488 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
1489 {
1490   // the skew is in the range [0.0,PI/2].
1491   // 0.0 = good
1492   // PI/2 = bad
1493   return Value;
1494 }
1495
1496 SMDSAbs_ElementType Skew::GetType() const
1497 {
1498   return SMDSAbs_Face;
1499 }
1500
1501
1502 //================================================================================
1503 /*
1504   Class       : Area
1505   Description : Functor for calculating area
1506 */
1507 //================================================================================
1508
1509 double Area::GetValue( const TSequenceOfXYZ& P )
1510 {
1511   double val = 0.0;
1512   if ( P.size() > 2 )
1513   {
1514     gp_Vec aVec1( P(2) - P(1) );
1515     gp_Vec aVec2( P(3) - P(1) );
1516     gp_Vec SumVec = aVec1 ^ aVec2;
1517
1518     for (size_t i=4; i<=P.size(); i++)
1519     {
1520       gp_Vec aVec1( P(i-1) - P(1) );
1521       gp_Vec aVec2( P(i  ) - P(1) );
1522       gp_Vec tmp = aVec1 ^ aVec2;
1523       SumVec.Add(tmp);
1524     }
1525     val = SumVec.Magnitude() * 0.5;
1526   }
1527   return val;
1528 }
1529
1530 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
1531 {
1532   // meaningless as it is not a quality control functor
1533   return Value;
1534 }
1535
1536 SMDSAbs_ElementType Area::GetType() const
1537 {
1538   return SMDSAbs_Face;
1539 }
1540
1541 //================================================================================
1542 /*
1543   Class       : Length
1544   Description : Functor for calculating length of edge
1545 */
1546 //================================================================================
1547
1548 double Length::GetValue( const TSequenceOfXYZ& P )
1549 {
1550   switch ( P.size() ) {
1551   case 2:  return getDistance( P( 1 ), P( 2 ) );
1552   case 3:  return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) );
1553   default: return 0.;
1554   }
1555 }
1556
1557 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
1558 {
1559   // meaningless as it is not quality control functor
1560   return Value;
1561 }
1562
1563 SMDSAbs_ElementType Length::GetType() const
1564 {
1565   return SMDSAbs_Edge;
1566 }
1567
1568 //================================================================================
1569 /*
1570   Class       : Length3D
1571   Description : Functor for calculating minimal length of element edge
1572 */
1573 //================================================================================
1574
1575 Length3D::Length3D():
1576   Length2D ( SMDSAbs_Volume )
1577 {
1578 }
1579
1580 //================================================================================
1581 /*
1582   Class       : Length2D
1583   Description : Functor for calculating minimal length of element edge
1584 */
1585 //================================================================================
1586
1587 Length2D::Length2D( SMDSAbs_ElementType type ):
1588   myType ( type )
1589 {
1590 }
1591
1592 bool Length2D::IsApplicable( const SMDS_MeshElement* element ) const
1593 {
1594   return ( NumericalFunctor::IsApplicable( element ) &&
1595            element->GetEntityType() != SMDSEntity_Polyhedra );
1596 }
1597
1598 double Length2D::GetValue( const TSequenceOfXYZ& P )
1599 {
1600   double aVal = 0;
1601   int len = P.size();
1602   SMDSAbs_EntityType aType = P.getElementEntity();
1603
1604   switch (aType) {
1605   case SMDSEntity_Edge:
1606     if (len == 2)
1607       aVal = getDistance( P( 1 ), P( 2 ) );
1608     break;
1609   case SMDSEntity_Quad_Edge:
1610     if (len == 3) // quadratic edge
1611       aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
1612     break;
1613   case SMDSEntity_Triangle:
1614     if (len == 3){ // triangles
1615       double L1 = getDistance(P( 1 ),P( 2 ));
1616       double L2 = getDistance(P( 2 ),P( 3 ));
1617       double L3 = getDistance(P( 3 ),P( 1 ));
1618       aVal = Min(L1,Min(L2,L3));
1619     }
1620     break;
1621   case SMDSEntity_Quadrangle:
1622     if (len == 4){ // quadrangles
1623       double L1 = getDistance(P( 1 ),P( 2 ));
1624       double L2 = getDistance(P( 2 ),P( 3 ));
1625       double L3 = getDistance(P( 3 ),P( 4 ));
1626       double L4 = getDistance(P( 4 ),P( 1 ));
1627       aVal = Min(Min(L1,L2),Min(L3,L4));
1628     }
1629     break;
1630   case SMDSEntity_Quad_Triangle:
1631   case SMDSEntity_BiQuad_Triangle:
1632     if (len >= 6){ // quadratic triangles
1633       double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1634       double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1635       double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
1636       aVal = Min(L1,Min(L2,L3));
1637     }
1638     break;
1639   case SMDSEntity_Quad_Quadrangle:
1640   case SMDSEntity_BiQuad_Quadrangle:
1641     if (len >= 8){ // quadratic quadrangles
1642       double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1643       double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1644       double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
1645       double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
1646       aVal = Min(Min(L1,L2),Min(L3,L4));
1647     }
1648     break;
1649   case SMDSEntity_Tetra:
1650     if (len == 4){ // tetrahedra
1651       double L1 = getDistance(P( 1 ),P( 2 ));
1652       double L2 = getDistance(P( 2 ),P( 3 ));
1653       double L3 = getDistance(P( 3 ),P( 1 ));
1654       double L4 = getDistance(P( 1 ),P( 4 ));
1655       double L5 = getDistance(P( 2 ),P( 4 ));
1656       double L6 = getDistance(P( 3 ),P( 4 ));
1657       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1658     }
1659     break;
1660   case SMDSEntity_Pyramid:
1661     if (len == 5){ // pyramid
1662       double L1 = getDistance(P( 1 ),P( 2 ));
1663       double L2 = getDistance(P( 2 ),P( 3 ));
1664       double L3 = getDistance(P( 3 ),P( 4 ));
1665       double L4 = getDistance(P( 4 ),P( 1 ));
1666       double L5 = getDistance(P( 1 ),P( 5 ));
1667       double L6 = getDistance(P( 2 ),P( 5 ));
1668       double L7 = getDistance(P( 3 ),P( 5 ));
1669       double L8 = getDistance(P( 4 ),P( 5 ));
1670
1671       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1672       aVal = Min(aVal,Min(L7,L8));
1673     }
1674     break;
1675   case SMDSEntity_Penta:
1676     if (len == 6) { // pentahedron
1677       double L1 = getDistance(P( 1 ),P( 2 ));
1678       double L2 = getDistance(P( 2 ),P( 3 ));
1679       double L3 = getDistance(P( 3 ),P( 1 ));
1680       double L4 = getDistance(P( 4 ),P( 5 ));
1681       double L5 = getDistance(P( 5 ),P( 6 ));
1682       double L6 = getDistance(P( 6 ),P( 4 ));
1683       double L7 = getDistance(P( 1 ),P( 4 ));
1684       double L8 = getDistance(P( 2 ),P( 5 ));
1685       double L9 = getDistance(P( 3 ),P( 6 ));
1686
1687       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1688       aVal = Min(aVal,Min(Min(L7,L8),L9));
1689     }
1690     break;
1691   case SMDSEntity_Hexa:
1692     if (len == 8){ // hexahedron
1693       double L1 = getDistance(P( 1 ),P( 2 ));
1694       double L2 = getDistance(P( 2 ),P( 3 ));
1695       double L3 = getDistance(P( 3 ),P( 4 ));
1696       double L4 = getDistance(P( 4 ),P( 1 ));
1697       double L5 = getDistance(P( 5 ),P( 6 ));
1698       double L6 = getDistance(P( 6 ),P( 7 ));
1699       double L7 = getDistance(P( 7 ),P( 8 ));
1700       double L8 = getDistance(P( 8 ),P( 5 ));
1701       double L9 = getDistance(P( 1 ),P( 5 ));
1702       double L10= getDistance(P( 2 ),P( 6 ));
1703       double L11= getDistance(P( 3 ),P( 7 ));
1704       double L12= getDistance(P( 4 ),P( 8 ));
1705
1706       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1707       aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1708       aVal = Min(aVal,Min(L11,L12));
1709     }
1710     break;
1711   case SMDSEntity_Quad_Tetra:
1712     if (len == 10){ // quadratic tetrahedron
1713       double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
1714       double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
1715       double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
1716       double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1717       double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
1718       double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
1719       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1720     }
1721     break;
1722   case SMDSEntity_Quad_Pyramid:
1723     if (len == 13){ // quadratic pyramid
1724       double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
1725       double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
1726       double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1727       double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1728       double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1729       double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
1730       double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
1731       double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
1732       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1733       aVal = Min(aVal,Min(L7,L8));
1734     }
1735     break;
1736   case SMDSEntity_Quad_Penta:
1737   case SMDSEntity_BiQuad_Penta:
1738     if (len >= 15){ // quadratic pentahedron
1739       double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
1740       double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
1741       double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1742       double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1743       double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
1744       double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
1745       double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
1746       double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
1747       double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
1748       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1749       aVal = Min(aVal,Min(Min(L7,L8),L9));
1750     }
1751     break;
1752   case SMDSEntity_Quad_Hexa:
1753   case SMDSEntity_TriQuad_Hexa:
1754     if (len >= 20) { // quadratic hexahedron
1755       double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
1756       double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
1757       double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
1758       double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
1759       double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
1760       double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
1761       double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
1762       double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
1763       double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
1764       double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
1765       double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
1766       double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
1767       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1768       aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1769       aVal = Min(aVal,Min(L11,L12));
1770     }
1771     break;
1772   case SMDSEntity_Polygon:
1773     if ( len > 1 ) {
1774       aVal = getDistance( P(1), P( P.size() ));
1775       for ( size_t i = 1; i < P.size(); ++i )
1776         aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
1777     }
1778     break;
1779   case SMDSEntity_Quad_Polygon:
1780     if ( len > 2 ) {
1781       aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
1782       for ( size_t i = 1; i < P.size()-1; i += 2 )
1783         aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
1784     }
1785     break;
1786   case SMDSEntity_Hexagonal_Prism:
1787     if (len == 12) { // hexagonal prism
1788       double L1 = getDistance(P( 1 ),P( 2 ));
1789       double L2 = getDistance(P( 2 ),P( 3 ));
1790       double L3 = getDistance(P( 3 ),P( 4 ));
1791       double L4 = getDistance(P( 4 ),P( 5 ));
1792       double L5 = getDistance(P( 5 ),P( 6 ));
1793       double L6 = getDistance(P( 6 ),P( 1 ));
1794
1795       double L7 = getDistance(P( 7 ), P( 8 ));
1796       double L8 = getDistance(P( 8 ), P( 9 ));
1797       double L9 = getDistance(P( 9 ), P( 10 ));
1798       double L10= getDistance(P( 10 ),P( 11 ));
1799       double L11= getDistance(P( 11 ),P( 12 ));
1800       double L12= getDistance(P( 12 ),P( 7 ));
1801
1802       double L13 = getDistance(P( 1 ),P( 7 ));
1803       double L14 = getDistance(P( 2 ),P( 8 ));
1804       double L15 = getDistance(P( 3 ),P( 9 ));
1805       double L16 = getDistance(P( 4 ),P( 10 ));
1806       double L17 = getDistance(P( 5 ),P( 11 ));
1807       double L18 = getDistance(P( 6 ),P( 12 ));
1808       aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1809       aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
1810       aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
1811     }
1812     break;
1813   case SMDSEntity_Polyhedra:
1814   {
1815   }
1816   break;
1817   default:
1818     return 0;
1819   }
1820
1821   if (aVal < 0 ) {
1822     return 0.;
1823   }
1824
1825   if ( myPrecision >= 0 )
1826   {
1827     double prec = pow( 10., (double)( myPrecision ) );
1828     aVal = floor( aVal * prec + 0.5 ) / prec;
1829   }
1830
1831   return aVal;
1832 }
1833
1834 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1835 {
1836   // meaningless as it is not a quality control functor
1837   return Value;
1838 }
1839
1840 SMDSAbs_ElementType Length2D::GetType() const
1841 {
1842   return myType;
1843 }
1844
1845 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
1846   myLength(theLength)
1847 {
1848   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1849   if(thePntId1 > thePntId2){
1850     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1851   }
1852 }
1853
1854 bool Length2D::Value::operator<(const Length2D::Value& x) const
1855 {
1856   if(myPntId[0] < x.myPntId[0]) return true;
1857   if(myPntId[0] == x.myPntId[0])
1858     if(myPntId[1] < x.myPntId[1]) return true;
1859   return false;
1860 }
1861
1862 void Length2D::GetValues(TValues& theValues)
1863 {
1864   if ( myType == SMDSAbs_Face )
1865   {
1866     for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
1867     {
1868       const SMDS_MeshFace* anElem = anIter->next();
1869       if ( anElem->IsQuadratic() )
1870       {
1871         // use special nodes iterator
1872         SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
1873         long aNodeId[4] = { 0,0,0,0 };
1874         gp_Pnt P[4];
1875
1876         double aLength = 0;
1877         if ( anIter->more() )
1878         {
1879           const SMDS_MeshNode* aNode = anIter->next();
1880           P[0] = P[1] = SMESH_NodeXYZ( aNode );
1881           aNodeId[0] = aNodeId[1] = aNode->GetID();
1882           aLength = 0;
1883         }
1884         for ( ; anIter->more(); )
1885         {
1886           const SMDS_MeshNode* N1 = anIter->next();
1887           P[2] = SMESH_NodeXYZ( N1 );
1888           aNodeId[2] = N1->GetID();
1889           aLength = P[1].Distance(P[2]);
1890           if(!anIter->more()) break;
1891           const SMDS_MeshNode* N2 = anIter->next();
1892           P[3] = SMESH_NodeXYZ( N2 );
1893           aNodeId[3] = N2->GetID();
1894           aLength += P[2].Distance(P[3]);
1895           Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1896           Value aValue2(aLength,aNodeId[2],aNodeId[3]);
1897           P[1] = P[3];
1898           aNodeId[1] = aNodeId[3];
1899           theValues.insert(aValue1);
1900           theValues.insert(aValue2);
1901         }
1902         aLength += P[2].Distance(P[0]);
1903         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
1904         Value aValue2(aLength,aNodeId[2],aNodeId[0]);
1905         theValues.insert(aValue1);
1906         theValues.insert(aValue2);
1907       }
1908       else {
1909         SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
1910         long aNodeId[2] = {0,0};
1911         gp_Pnt P[3];
1912
1913         double aLength;
1914         const SMDS_MeshElement* aNode;
1915         if ( aNodesIter->more())
1916         {
1917           aNode = aNodesIter->next();
1918           P[0] = P[1] = SMESH_NodeXYZ( aNode );
1919           aNodeId[0] = aNodeId[1] = aNode->GetID();
1920           aLength = 0;
1921         }
1922         for( ; aNodesIter->more(); )
1923         {
1924           aNode = aNodesIter->next();
1925           long anId = aNode->GetID();
1926
1927           P[2] = SMESH_NodeXYZ( aNode );
1928
1929           aLength = P[1].Distance(P[2]);
1930
1931           Value aValue(aLength,aNodeId[1],anId);
1932           aNodeId[1] = anId;
1933           P[1] = P[2];
1934           theValues.insert(aValue);
1935         }
1936
1937         aLength = P[0].Distance(P[1]);
1938
1939         Value aValue(aLength,aNodeId[0],aNodeId[1]);
1940         theValues.insert(aValue);
1941       }
1942     }
1943   }
1944   else
1945   {
1946     // not implemented
1947   }
1948 }
1949
1950 //================================================================================
1951 /*
1952   Class       : Deflection2D
1953   Description : computes distance between a face center and an underlying surface
1954 */
1955 //================================================================================
1956
1957 double Deflection2D::GetValue( const TSequenceOfXYZ& P )
1958 {
1959   if ( myMesh && P.getElement() )
1960   {
1961     // get underlying surface
1962     if ( myShapeIndex != P.getElement()->getshapeId() )
1963     {
1964       mySurface.Nullify();
1965       myShapeIndex = P.getElement()->getshapeId();
1966       const TopoDS_Shape& S =
1967         static_cast< const SMESHDS_Mesh* >( myMesh )->IndexToShape( myShapeIndex );
1968       if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
1969       {
1970         mySurface = new ShapeAnalysis_Surface( BRep_Tool::Surface( TopoDS::Face( S )));
1971
1972         GeomLib_IsPlanarSurface isPlaneCheck( mySurface->Surface() );
1973         if ( isPlaneCheck.IsPlanar() )
1974           myPlane.reset( new gp_Pln( isPlaneCheck.Plan() ));
1975         else
1976           myPlane.reset();
1977       }
1978     }
1979     // project gravity center to the surface
1980     if ( !mySurface.IsNull() )
1981     {
1982       gp_XYZ gc(0,0,0);
1983       gp_XY  uv(0,0);
1984       int nbUV = 0;
1985       for ( size_t i = 0; i < P.size(); ++i )
1986       {
1987         gc += P(i+1);
1988
1989         if ( SMDS_FacePositionPtr fPos = P.getElement()->GetNode( i )->GetPosition() )
1990         {
1991           uv.ChangeCoord(1) += fPos->GetUParameter();
1992           uv.ChangeCoord(2) += fPos->GetVParameter();
1993           ++nbUV;
1994         }
1995       }
1996       gc /= P.size();
1997       if ( nbUV ) uv /= nbUV;
1998
1999       double maxLen = MaxElementLength2D().GetValue( P );
2000       double    tol = 1e-3 * maxLen;
2001       double dist;
2002       if ( myPlane )
2003       {
2004         dist = myPlane->Distance( gc );
2005         if ( dist < tol )
2006           dist = 0;
2007       }
2008       else
2009       {
2010         if ( uv.X() != 0 && uv.Y() != 0 ) // faster way
2011           mySurface->NextValueOfUV( uv, gc, tol, 0.5 * maxLen );
2012         else
2013           mySurface->ValueOfUV( gc, tol );
2014         dist = mySurface->Gap();
2015       }
2016       return Round( dist );
2017     }
2018   }
2019   return 0;
2020 }
2021
2022 void Deflection2D::SetMesh( const SMDS_Mesh* theMesh )
2023 {
2024   NumericalFunctor::SetMesh( dynamic_cast<const SMESHDS_Mesh* >( theMesh ));
2025   myShapeIndex = -100;
2026   myPlane.reset();
2027 }
2028
2029 SMDSAbs_ElementType Deflection2D::GetType() const
2030 {
2031   return SMDSAbs_Face;
2032 }
2033
2034 double Deflection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2035 {
2036   // meaningless as it is not quality control functor
2037   return Value;
2038 }
2039
2040 //================================================================================
2041 /*
2042   Class       : MultiConnection
2043   Description : Functor for calculating number of faces conneted to the edge
2044 */
2045 //================================================================================
2046
2047 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
2048 {
2049   return 0;
2050 }
2051 double MultiConnection::GetValue( long theId )
2052 {
2053   return getNbMultiConnection( myMesh, theId );
2054 }
2055
2056 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
2057 {
2058   // meaningless as it is not quality control functor
2059   return Value;
2060 }
2061
2062 SMDSAbs_ElementType MultiConnection::GetType() const
2063 {
2064   return SMDSAbs_Edge;
2065 }
2066
2067 //================================================================================
2068 /*
2069   Class       : MultiConnection2D
2070   Description : Functor for calculating number of faces conneted to the edge
2071 */
2072 //================================================================================
2073
2074 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
2075 {
2076   return 0;
2077 }
2078
2079 double MultiConnection2D::GetValue( long theElementId )
2080 {
2081   int aResult = 0;
2082
2083   const SMDS_MeshElement* aFaceElem = myMesh->FindElement(theElementId);
2084   SMDSAbs_ElementType aType = aFaceElem->GetType();
2085
2086   switch (aType) {
2087   case SMDSAbs_Face:
2088     {
2089       int i = 0, len = aFaceElem->NbNodes();
2090       SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
2091       if (!anIter) break;
2092
2093       const SMDS_MeshNode *aNode, *aNode0 = 0;
2094       TColStd_MapOfInteger aMap, aMapPrev;
2095
2096       for (i = 0; i <= len; i++) {
2097         aMapPrev = aMap;
2098         aMap.Clear();
2099
2100         int aNb = 0;
2101         if (anIter->more()) {
2102           aNode = (SMDS_MeshNode*)anIter->next();
2103         } else {
2104           if (i == len)
2105             aNode = aNode0;
2106           else
2107             break;
2108         }
2109         if (!aNode) break;
2110         if (i == 0) aNode0 = aNode;
2111
2112         SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
2113         while (anElemIter->more()) {
2114           const SMDS_MeshElement* anElem = anElemIter->next();
2115           if (anElem != 0 && anElem->GetType() == SMDSAbs_Face) {
2116             int anId = anElem->GetID();
2117
2118             aMap.Add(anId);
2119             if (aMapPrev.Contains(anId)) {
2120               aNb++;
2121             }
2122           }
2123         }
2124         aResult = Max(aResult, aNb);
2125       }
2126     }
2127     break;
2128   default:
2129     aResult = 0;
2130   }
2131
2132   return aResult;
2133 }
2134
2135 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2136 {
2137   // meaningless as it is not quality control functor
2138   return Value;
2139 }
2140
2141 SMDSAbs_ElementType MultiConnection2D::GetType() const
2142 {
2143   return SMDSAbs_Face;
2144 }
2145
2146 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
2147 {
2148   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
2149   if(thePntId1 > thePntId2){
2150     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
2151   }
2152 }
2153
2154 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const
2155 {
2156   if(myPntId[0] < x.myPntId[0]) return true;
2157   if(myPntId[0] == x.myPntId[0])
2158     if(myPntId[1] < x.myPntId[1]) return true;
2159   return false;
2160 }
2161
2162 void MultiConnection2D::GetValues(MValues& theValues)
2163 {
2164   if ( !myMesh ) return;
2165   for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
2166   {
2167     const SMDS_MeshFace*     anElem = anIter->next();
2168     SMDS_NodeIteratorPtr aNodesIter = anElem->interlacedNodesIterator();
2169
2170     const SMDS_MeshNode* aNode1 = anElem->GetNode( anElem->NbNodes() - 1 );
2171     const SMDS_MeshNode* aNode2;
2172     for ( ; aNodesIter->more(); )
2173     {
2174       aNode2 = aNodesIter->next();
2175
2176       Value aValue ( aNode1->GetID(), aNode2->GetID() );
2177       MValues::iterator aItr = theValues.insert( std::make_pair( aValue, 0 )).first;
2178       aItr->second++;
2179       aNode1 = aNode2;
2180     }
2181   }
2182   return;
2183 }
2184
2185 //================================================================================
2186 /*
2187   Class       : BallDiameter
2188   Description : Functor returning diameter of a ball element
2189 */
2190 //================================================================================
2191
2192 double BallDiameter::GetValue( long theId )
2193 {
2194   double diameter = 0;
2195
2196   if ( const SMDS_BallElement* ball =
2197        myMesh->DownCast< SMDS_BallElement >( myMesh->FindElement( theId )))
2198   {
2199     diameter = ball->GetDiameter();
2200   }
2201   return diameter;
2202 }
2203
2204 double BallDiameter::GetBadRate( double Value, int /*nbNodes*/ ) const
2205 {
2206   // meaningless as it is not a quality control functor
2207   return Value;
2208 }
2209
2210 SMDSAbs_ElementType BallDiameter::GetType() const
2211 {
2212   return SMDSAbs_Ball;
2213 }
2214
2215 //================================================================================
2216 /*
2217   Class       : NodeConnectivityNumber
2218   Description : Functor returning number of elements connected to a node
2219 */
2220 //================================================================================
2221
2222 double NodeConnectivityNumber::GetValue( long theId )
2223 {
2224   double nb = 0;
2225
2226   if ( const SMDS_MeshNode* node = myMesh->FindNode( theId ))
2227   {
2228     SMDSAbs_ElementType type;
2229     if ( myMesh->NbVolumes() > 0 )
2230       type = SMDSAbs_Volume;
2231     else if ( myMesh->NbFaces() > 0 )
2232       type = SMDSAbs_Face;
2233     else if ( myMesh->NbEdges() > 0 )
2234       type = SMDSAbs_Edge;
2235     else
2236       return 0;
2237     nb = node->NbInverseElements( type );
2238   }
2239   return nb;
2240 }
2241
2242 double NodeConnectivityNumber::GetBadRate( double Value, int /*nbNodes*/ ) const
2243 {
2244   return Value;
2245 }
2246
2247 SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
2248 {
2249   return SMDSAbs_Node;
2250 }
2251
2252 /*
2253                             PREDICATES
2254 */
2255
2256 //================================================================================
2257 /*
2258   Class       : BadOrientedVolume
2259   Description : Predicate bad oriented volumes
2260 */
2261 //================================================================================
2262
2263 BadOrientedVolume::BadOrientedVolume()
2264 {
2265   myMesh = 0;
2266 }
2267
2268 void BadOrientedVolume::SetMesh( const SMDS_Mesh* theMesh )
2269 {
2270   myMesh = theMesh;
2271 }
2272
2273 bool BadOrientedVolume::IsSatisfy( long theId )
2274 {
2275   if ( myMesh == 0 )
2276     return false;
2277
2278   SMDS_VolumeTool vTool( myMesh->FindElement( theId ));
2279
2280   bool isOk = true;
2281   if ( vTool.IsPoly() )
2282   {
2283     isOk = true;
2284     for ( int i = 0; i < vTool.NbFaces() && isOk; ++i )
2285       isOk = vTool.IsFaceExternal( i );
2286   }
2287   else
2288   {
2289     isOk = vTool.IsForward();
2290   }
2291   return !isOk;
2292 }
2293
2294 SMDSAbs_ElementType BadOrientedVolume::GetType() const
2295 {
2296   return SMDSAbs_Volume;
2297 }
2298
2299 /*
2300   Class       : BareBorderVolume
2301 */
2302
2303 bool BareBorderVolume::IsSatisfy(long theElementId )
2304 {
2305   SMDS_VolumeTool  myTool;
2306   if ( myTool.Set( myMesh->FindElement(theElementId)))
2307   {
2308     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
2309       if ( myTool.IsFreeFace( iF ))
2310       {
2311         const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
2312         std::vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF));
2313         if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
2314           return true;
2315       }
2316   }
2317   return false;
2318 }
2319
2320 //================================================================================
2321 /*
2322   Class       : BareBorderFace
2323 */
2324 //================================================================================
2325
2326 bool BareBorderFace::IsSatisfy(long theElementId )
2327 {
2328   bool ok = false;
2329   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
2330   {
2331     if ( face->GetType() == SMDSAbs_Face )
2332     {
2333       int nbN = face->NbCornerNodes();
2334       for ( int i = 0; i < nbN && !ok; ++i )
2335       {
2336         // check if a link is shared by another face
2337         const SMDS_MeshNode* n1 = face->GetNode( i );
2338         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
2339         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
2340         bool isShared = false;
2341         while ( !isShared && fIt->more() )
2342         {
2343           const SMDS_MeshElement* f = fIt->next();
2344           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
2345         }
2346         if ( !isShared )
2347         {
2348           const int iQuad = face->IsQuadratic();
2349           myLinkNodes.resize( 2 + iQuad);
2350           myLinkNodes[0] = n1;
2351           myLinkNodes[1] = n2;
2352           if ( iQuad )
2353             myLinkNodes[2] = face->GetNode( i+nbN );
2354           ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false);
2355         }
2356       }
2357     }
2358   }
2359   return ok;
2360 }
2361
2362 //================================================================================
2363 /*
2364   Class       : OverConstrainedVolume
2365 */
2366 //================================================================================
2367
2368 bool OverConstrainedVolume::IsSatisfy(long theElementId )
2369 {
2370   // An element is over-constrained if it has N-1 free borders where
2371   // N is the number of edges/faces for a 2D/3D element.
2372   SMDS_VolumeTool  myTool;
2373   if ( myTool.Set( myMesh->FindElement(theElementId)))
2374   {
2375     int nbSharedFaces = 0;
2376     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
2377       if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 )
2378         break;
2379     return ( nbSharedFaces == 1 );
2380   }
2381   return false;
2382 }
2383
2384 //================================================================================
2385 /*
2386   Class       : OverConstrainedFace
2387 */
2388 //================================================================================
2389
2390 bool OverConstrainedFace::IsSatisfy(long theElementId )
2391 {
2392   // An element is over-constrained if it has N-1 free borders where
2393   // N is the number of edges/faces for a 2D/3D element.
2394   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
2395     if ( face->GetType() == SMDSAbs_Face )
2396     {
2397       int nbSharedBorders = 0;
2398       int nbN = face->NbCornerNodes();
2399       for ( int i = 0; i < nbN; ++i )
2400       {
2401         // check if a link is shared by another face
2402         const SMDS_MeshNode* n1 = face->GetNode( i );
2403         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
2404         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
2405         bool isShared = false;
2406         while ( !isShared && fIt->more() )
2407         {
2408           const SMDS_MeshElement* f = fIt->next();
2409           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
2410         }
2411         if ( isShared && ++nbSharedBorders > 1 )
2412           break;
2413       }
2414       return ( nbSharedBorders == 1 );
2415     }
2416   return false;
2417 }
2418
2419 //================================================================================
2420 /*
2421   Class       : CoincidentNodes
2422   Description : Predicate of Coincident nodes
2423 */
2424 //================================================================================
2425
2426 CoincidentNodes::CoincidentNodes()
2427 {
2428   myToler = 1e-5;
2429 }
2430
2431 bool CoincidentNodes::IsSatisfy( long theElementId )
2432 {
2433   return myCoincidentIDs.Contains( theElementId );
2434 }
2435
2436 SMDSAbs_ElementType CoincidentNodes::GetType() const
2437 {
2438   return SMDSAbs_Node;
2439 }
2440
2441 void CoincidentNodes::SetTolerance( const double theToler )
2442 {
2443   if ( myToler != theToler )
2444   {
2445     SetMesh(0);
2446     myToler = theToler;
2447   }
2448 }
2449
2450 void CoincidentNodes::SetMesh( const SMDS_Mesh* theMesh )
2451 {
2452   myMeshModifTracer.SetMesh( theMesh );
2453   if ( myMeshModifTracer.IsMeshModified() )
2454   {
2455     TIDSortedNodeSet nodesToCheck;
2456     SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
2457     while ( nIt->more() )
2458       nodesToCheck.insert( nodesToCheck.end(), nIt->next() );
2459
2460     std::list< std::list< const SMDS_MeshNode*> > nodeGroups;
2461     SMESH_OctreeNode::FindCoincidentNodes ( nodesToCheck, &nodeGroups, myToler );
2462
2463     myCoincidentIDs.Clear();
2464     std::list< std::list< const SMDS_MeshNode*> >::iterator groupIt = nodeGroups.begin();
2465     for ( ; groupIt != nodeGroups.end(); ++groupIt )
2466     {
2467       std::list< const SMDS_MeshNode*>& coincNodes = *groupIt;
2468       std::list< const SMDS_MeshNode*>::iterator n = coincNodes.begin();
2469       for ( ; n != coincNodes.end(); ++n )
2470         myCoincidentIDs.Add( (*n)->GetID() );
2471     }
2472   }
2473 }
2474
2475 //================================================================================
2476 /*
2477   Class       : CoincidentElements
2478   Description : Predicate of Coincident Elements
2479   Note        : This class is suitable only for visualization of Coincident Elements
2480 */
2481 //================================================================================
2482
2483 CoincidentElements::CoincidentElements()
2484 {
2485   myMesh = 0;
2486 }
2487
2488 void CoincidentElements::SetMesh( const SMDS_Mesh* theMesh )
2489 {
2490   myMesh = theMesh;
2491 }
2492
2493 bool CoincidentElements::IsSatisfy( long theElementId )
2494 {
2495   if ( !myMesh ) return false;
2496
2497   if ( const SMDS_MeshElement* e = myMesh->FindElement( theElementId ))
2498   {
2499     if ( e->GetType() != GetType() ) return false;
2500     std::set< const SMDS_MeshNode* > elemNodes( e->begin_nodes(), e->end_nodes() );
2501     const int nbNodes = e->NbNodes();
2502     SMDS_ElemIteratorPtr invIt = (*elemNodes.begin())->GetInverseElementIterator( GetType() );
2503     while ( invIt->more() )
2504     {
2505       const SMDS_MeshElement* e2 = invIt->next();
2506       if ( e2 == e || e2->NbNodes() != nbNodes ) continue;
2507
2508       bool sameNodes = true;
2509       for ( size_t i = 0; i < elemNodes.size() && sameNodes; ++i )
2510         sameNodes = ( elemNodes.count( e2->GetNode( i )));
2511       if ( sameNodes )
2512         return true;
2513     }
2514   }
2515   return false;
2516 }
2517
2518 SMDSAbs_ElementType CoincidentElements1D::GetType() const
2519 {
2520   return SMDSAbs_Edge;
2521 }
2522 SMDSAbs_ElementType CoincidentElements2D::GetType() const
2523 {
2524   return SMDSAbs_Face;
2525 }
2526 SMDSAbs_ElementType CoincidentElements3D::GetType() const
2527 {
2528   return SMDSAbs_Volume;
2529 }
2530
2531
2532 //================================================================================
2533 /*
2534   Class       : FreeBorders
2535   Description : Predicate for free borders
2536 */
2537 //================================================================================
2538
2539 FreeBorders::FreeBorders()
2540 {
2541   myMesh = 0;
2542 }
2543
2544 void FreeBorders::SetMesh( const SMDS_Mesh* theMesh )
2545 {
2546   myMesh = theMesh;
2547 }
2548
2549 bool FreeBorders::IsSatisfy( long theId )
2550 {
2551   return getNbMultiConnection( myMesh, theId ) == 1;
2552 }
2553
2554 SMDSAbs_ElementType FreeBorders::GetType() const
2555 {
2556   return SMDSAbs_Edge;
2557 }
2558
2559
2560 //================================================================================
2561 /*
2562   Class       : FreeEdges
2563   Description : Predicate for free Edges
2564 */
2565 //================================================================================
2566
2567 FreeEdges::FreeEdges()
2568 {
2569   myMesh = 0;
2570 }
2571
2572 void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
2573 {
2574   myMesh = theMesh;
2575 }
2576
2577 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
2578 {
2579   SMDS_ElemIteratorPtr anElemIter = theNodes[ 0 ]->GetInverseElementIterator(SMDSAbs_Face);
2580   while( anElemIter->more() )
2581   {
2582     if ( const SMDS_MeshElement* anElem = anElemIter->next())
2583     {
2584       const int anId = anElem->GetID();
2585       if ( anId != theFaceId && anElem->GetNodeIndex( theNodes[1] ) >= 0 )
2586         return false;
2587     }
2588   }
2589   return true;
2590 }
2591
2592 bool FreeEdges::IsSatisfy( long theId )
2593 {
2594   if ( myMesh == 0 )
2595     return false;
2596
2597   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2598   if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
2599     return false;
2600
2601   SMDS_NodeIteratorPtr anIter = aFace->interlacedNodesIterator();
2602   if ( !anIter )
2603     return false;
2604
2605   int i = 0, nbNodes = aFace->NbNodes();
2606   std::vector <const SMDS_MeshNode*> aNodes( nbNodes+1 );
2607   while( anIter->more() )
2608     if ( ! ( aNodes[ i++ ] = anIter->next() ))
2609       return false;
2610   aNodes[ nbNodes ] = aNodes[ 0 ];
2611
2612   for ( i = 0; i < nbNodes; i++ )
2613     if ( IsFreeEdge( &aNodes[ i ], theId ) )
2614       return true;
2615
2616   return false;
2617 }
2618
2619 SMDSAbs_ElementType FreeEdges::GetType() const
2620 {
2621   return SMDSAbs_Face;
2622 }
2623
2624 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
2625   myElemId(theElemId)
2626 {
2627   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
2628   if(thePntId1 > thePntId2){
2629     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
2630   }
2631 }
2632
2633 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
2634   if(myPntId[0] < x.myPntId[0]) return true;
2635   if(myPntId[0] == x.myPntId[0])
2636     if(myPntId[1] < x.myPntId[1]) return true;
2637   return false;
2638 }
2639
2640 inline void UpdateBorders(const FreeEdges::Border& theBorder,
2641                           FreeEdges::TBorders& theRegistry,
2642                           FreeEdges::TBorders& theContainer)
2643 {
2644   if(theRegistry.find(theBorder) == theRegistry.end()){
2645     theRegistry.insert(theBorder);
2646     theContainer.insert(theBorder);
2647   }else{
2648     theContainer.erase(theBorder);
2649   }
2650 }
2651
2652 void FreeEdges::GetBoreders(TBorders& theBorders)
2653 {
2654   TBorders aRegistry;
2655   for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
2656   {
2657     const SMDS_MeshFace* anElem = anIter->next();
2658     long anElemId = anElem->GetID();
2659     SMDS_NodeIteratorPtr aNodesIter = anElem->interlacedNodesIterator();
2660     if ( !aNodesIter->more() ) continue;
2661     long aNodeId[2] = {0,0};
2662     aNodeId[0] = anElem->GetNode( anElem->NbNodes()-1 )->GetID();
2663     for ( ; aNodesIter->more(); )
2664     {
2665       aNodeId[1] = aNodesIter->next()->GetID();
2666       Border aBorder( anElemId, aNodeId[0], aNodeId[1] );
2667       UpdateBorders( aBorder, aRegistry, theBorders );
2668       aNodeId[0] = aNodeId[1];
2669     }
2670   }
2671 }
2672
2673 //================================================================================
2674 /*
2675   Class       : FreeNodes
2676   Description : Predicate for free nodes
2677 */
2678 //================================================================================
2679
2680 FreeNodes::FreeNodes()
2681 {
2682   myMesh = 0;
2683 }
2684
2685 void FreeNodes::SetMesh( const SMDS_Mesh* theMesh )
2686 {
2687   myMesh = theMesh;
2688 }
2689
2690 bool FreeNodes::IsSatisfy( long theNodeId )
2691 {
2692   const SMDS_MeshNode* aNode = myMesh->FindNode( theNodeId );
2693   if (!aNode)
2694     return false;
2695
2696   return (aNode->NbInverseElements() < 1);
2697 }
2698
2699 SMDSAbs_ElementType FreeNodes::GetType() const
2700 {
2701   return SMDSAbs_Node;
2702 }
2703
2704
2705 //================================================================================
2706 /*
2707   Class       : FreeFaces
2708   Description : Predicate for free faces
2709 */
2710 //================================================================================
2711
2712 FreeFaces::FreeFaces()
2713 {
2714   myMesh = 0;
2715 }
2716
2717 void FreeFaces::SetMesh( const SMDS_Mesh* theMesh )
2718 {
2719   myMesh = theMesh;
2720 }
2721
2722 bool FreeFaces::IsSatisfy( long theId )
2723 {
2724   if (!myMesh) return false;
2725   // check that faces nodes refers to less than two common volumes
2726   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2727   if ( !aFace || aFace->GetType() != SMDSAbs_Face )
2728     return false;
2729
2730   int nbNode = aFace->NbNodes();
2731
2732   // collect volumes to check that number of volumes with count equal nbNode not less than 2
2733   typedef std::map< SMDS_MeshElement*, int > TMapOfVolume; // map of volume counters
2734   typedef std::map< SMDS_MeshElement*, int >::iterator TItrMapOfVolume; // iterator
2735   TMapOfVolume mapOfVol;
2736
2737   SMDS_ElemIteratorPtr nodeItr = aFace->nodesIterator();
2738   while ( nodeItr->more() )
2739   {
2740     const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
2741     if ( !aNode ) continue;
2742     SMDS_ElemIteratorPtr volItr = aNode->GetInverseElementIterator(SMDSAbs_Volume);
2743     while ( volItr->more() )
2744     {
2745       SMDS_MeshElement* aVol = (SMDS_MeshElement*)volItr->next();
2746       TItrMapOfVolume    itr = mapOfVol.insert( std::make_pair( aVol, 0 )).first;
2747       (*itr).second++;
2748     }
2749   }
2750   int nbVol = 0;
2751   TItrMapOfVolume volItr = mapOfVol.begin();
2752   TItrMapOfVolume volEnd = mapOfVol.end();
2753   for ( ; volItr != volEnd; ++volItr )
2754     if ( (*volItr).second >= nbNode )
2755       nbVol++;
2756   // face is not free if number of volumes constructed on their nodes more than one
2757   return (nbVol < 2);
2758 }
2759
2760 SMDSAbs_ElementType FreeFaces::GetType() const
2761 {
2762   return SMDSAbs_Face;
2763 }
2764
2765 //================================================================================
2766 /*
2767   Class       : LinearOrQuadratic
2768   Description : Predicate to verify whether a mesh element is linear
2769 */
2770 //================================================================================
2771
2772 LinearOrQuadratic::LinearOrQuadratic()
2773 {
2774   myMesh = 0;
2775 }
2776
2777 void LinearOrQuadratic::SetMesh( const SMDS_Mesh* theMesh )
2778 {
2779   myMesh = theMesh;
2780 }
2781
2782 bool LinearOrQuadratic::IsSatisfy( long theId )
2783 {
2784   if (!myMesh) return false;
2785   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2786   if ( !anElem || (myType != SMDSAbs_All && anElem->GetType() != myType) )
2787     return false;
2788   return (!anElem->IsQuadratic());
2789 }
2790
2791 void LinearOrQuadratic::SetType( SMDSAbs_ElementType theType )
2792 {
2793   myType = theType;
2794 }
2795
2796 SMDSAbs_ElementType LinearOrQuadratic::GetType() const
2797 {
2798   return myType;
2799 }
2800
2801 //================================================================================
2802 /*
2803   Class       : GroupColor
2804   Description : Functor for check color of group to which mesh element belongs to
2805 */
2806 //================================================================================
2807
2808 GroupColor::GroupColor()
2809 {
2810 }
2811
2812 bool GroupColor::IsSatisfy( long theId )
2813 {
2814   return myIDs.count( theId );
2815 }
2816
2817 void GroupColor::SetType( SMDSAbs_ElementType theType )
2818 {
2819   myType = theType;
2820 }
2821
2822 SMDSAbs_ElementType GroupColor::GetType() const
2823 {
2824   return myType;
2825 }
2826
2827 static bool isEqual( const Quantity_Color& theColor1,
2828                      const Quantity_Color& theColor2 )
2829 {
2830   // tolerance to compare colors
2831   const double tol = 5*1e-3;
2832   return ( fabs( theColor1.Red()   - theColor2.Red() )   < tol &&
2833            fabs( theColor1.Green() - theColor2.Green() ) < tol &&
2834            fabs( theColor1.Blue()  - theColor2.Blue() )  < tol );
2835 }
2836
2837 void GroupColor::SetMesh( const SMDS_Mesh* theMesh )
2838 {
2839   myIDs.clear();
2840
2841   const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
2842   if ( !aMesh )
2843     return;
2844
2845   int nbGrp = aMesh->GetNbGroups();
2846   if ( !nbGrp )
2847     return;
2848
2849   // iterates on groups and find necessary elements ids
2850   const std::set<SMESHDS_GroupBase*>&       aGroups = aMesh->GetGroups();
2851   std::set<SMESHDS_GroupBase*>::const_iterator GrIt = aGroups.begin();
2852   for (; GrIt != aGroups.end(); GrIt++)
2853   {
2854     SMESHDS_GroupBase* aGrp = (*GrIt);
2855     if ( !aGrp )
2856       continue;
2857     // check type and color of group
2858     if ( !isEqual( myColor, aGrp->GetColor() ))
2859       continue;
2860
2861     // IPAL52867 (prevent infinite recursion via GroupOnFilter)
2862     if ( SMESHDS_GroupOnFilter * gof = dynamic_cast< SMESHDS_GroupOnFilter* >( aGrp ))
2863       if ( gof->GetPredicate().get() == this )
2864         continue;
2865
2866     SMDSAbs_ElementType aGrpElType = (SMDSAbs_ElementType)aGrp->GetType();
2867     if ( myType == aGrpElType || (myType == SMDSAbs_All && aGrpElType != SMDSAbs_Node) ) {
2868       // add elements IDS into control
2869       int aSize = aGrp->Extent();
2870       for (int i = 0; i < aSize; i++)
2871         myIDs.insert( aGrp->GetID(i+1) );
2872     }
2873   }
2874 }
2875
2876 void GroupColor::SetColorStr( const TCollection_AsciiString& theStr )
2877 {
2878   Kernel_Utils::Localizer loc;
2879   TCollection_AsciiString aStr = theStr;
2880   aStr.RemoveAll( ' ' );
2881   aStr.RemoveAll( '\t' );
2882   for ( int aPos = aStr.Search( ";;" ); aPos != -1; aPos = aStr.Search( ";;" ) )
2883     aStr.Remove( aPos, 2 );
2884   Standard_Real clr[3];
2885   clr[0] = clr[1] = clr[2] = 0.;
2886   for ( int i = 0; i < 3; i++ ) {
2887     TCollection_AsciiString tmpStr = aStr.Token( ";", i+1 );
2888     if ( !tmpStr.IsEmpty() && tmpStr.IsRealValue() )
2889       clr[i] = tmpStr.RealValue();
2890   }
2891   myColor = Quantity_Color( clr[0], clr[1], clr[2], Quantity_TOC_RGB );
2892 }
2893
2894 //=======================================================================
2895 // name    : GetRangeStr
2896 // Purpose : Get range as a string.
2897 //           Example: "1,2,3,50-60,63,67,70-"
2898 //=======================================================================
2899
2900 void GroupColor::GetColorStr( TCollection_AsciiString& theResStr ) const
2901 {
2902   theResStr.Clear();
2903   theResStr += TCollection_AsciiString( myColor.Red() );
2904   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Green() );
2905   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Blue() );
2906 }
2907
2908 //================================================================================
2909 /*
2910   Class       : ElemGeomType
2911   Description : Predicate to check element geometry type
2912 */
2913 //================================================================================
2914
2915 ElemGeomType::ElemGeomType()
2916 {
2917   myMesh = 0;
2918   myType = SMDSAbs_All;
2919   myGeomType = SMDSGeom_TRIANGLE;
2920 }
2921
2922 void ElemGeomType::SetMesh( const SMDS_Mesh* theMesh )
2923 {
2924   myMesh = theMesh;
2925 }
2926
2927 bool ElemGeomType::IsSatisfy( long theId )
2928 {
2929   if (!myMesh) return false;
2930   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2931   if ( !anElem )
2932     return false;
2933   const SMDSAbs_ElementType anElemType = anElem->GetType();
2934   if ( myType != SMDSAbs_All && anElemType != myType )
2935     return false;
2936   bool isOk = ( anElem->GetGeomType() == myGeomType );
2937   return isOk;
2938 }
2939
2940 void ElemGeomType::SetType( SMDSAbs_ElementType theType )
2941 {
2942   myType = theType;
2943 }
2944
2945 SMDSAbs_ElementType ElemGeomType::GetType() const
2946 {
2947   return myType;
2948 }
2949
2950 void ElemGeomType::SetGeomType( SMDSAbs_GeometryType theType )
2951 {
2952   myGeomType = theType;
2953 }
2954
2955 SMDSAbs_GeometryType ElemGeomType::GetGeomType() const
2956 {
2957   return myGeomType;
2958 }
2959
2960 //================================================================================
2961 /*
2962   Class       : ElemEntityType
2963   Description : Predicate to check element entity type
2964 */
2965 //================================================================================
2966
2967 ElemEntityType::ElemEntityType():
2968   myMesh( 0 ),
2969   myType( SMDSAbs_All ),
2970   myEntityType( SMDSEntity_0D )
2971 {
2972 }
2973
2974 void ElemEntityType::SetMesh( const SMDS_Mesh* theMesh )
2975 {
2976   myMesh = theMesh;
2977 }
2978
2979 bool ElemEntityType::IsSatisfy( long theId )
2980 {
2981   if ( !myMesh ) return false;
2982   if ( myType == SMDSAbs_Node )
2983     return myMesh->FindNode( theId );
2984   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
2985   return ( anElem &&
2986            myEntityType == anElem->GetEntityType() );
2987 }
2988
2989 void ElemEntityType::SetType( SMDSAbs_ElementType theType )
2990 {
2991   myType = theType;
2992 }
2993
2994 SMDSAbs_ElementType ElemEntityType::GetType() const
2995 {
2996   return myType;
2997 }
2998
2999 void ElemEntityType::SetElemEntityType( SMDSAbs_EntityType theEntityType )
3000 {
3001   myEntityType = theEntityType;
3002 }
3003
3004 SMDSAbs_EntityType ElemEntityType::GetElemEntityType() const
3005 {
3006   return myEntityType;
3007 }
3008
3009 //================================================================================
3010 /*!
3011  * \brief Class ConnectedElements
3012  */
3013 //================================================================================
3014
3015 ConnectedElements::ConnectedElements():
3016   myNodeID(0), myType( SMDSAbs_All ), myOkIDsReady( false ) {}
3017
3018 SMDSAbs_ElementType ConnectedElements::GetType() const
3019 { return myType; }
3020
3021 int ConnectedElements::GetNode() const
3022 { return myXYZ.empty() ? myNodeID : 0; } // myNodeID can be found by myXYZ
3023
3024 std::vector<double> ConnectedElements::GetPoint() const
3025 { return myXYZ; }
3026
3027 void ConnectedElements::clearOkIDs()
3028 { myOkIDsReady = false; myOkIDs.clear(); }
3029
3030 void ConnectedElements::SetType( SMDSAbs_ElementType theType )
3031 {
3032   if ( myType != theType || myMeshModifTracer.IsMeshModified() )
3033     clearOkIDs();
3034   myType = theType;
3035 }
3036
3037 void ConnectedElements::SetMesh( const SMDS_Mesh* theMesh )
3038 {
3039   myMeshModifTracer.SetMesh( theMesh );
3040   if ( myMeshModifTracer.IsMeshModified() )
3041   {
3042     clearOkIDs();
3043     if ( !myXYZ.empty() )
3044       SetPoint( myXYZ[0], myXYZ[1], myXYZ[2] ); // find a node near myXYZ it in a new mesh
3045   }
3046 }
3047
3048 void ConnectedElements::SetNode( int nodeID )
3049 {
3050   myNodeID = nodeID;
3051   myXYZ.clear();
3052
3053   bool isSameDomain = false;
3054   if ( myOkIDsReady && myMeshModifTracer.GetMesh() && !myMeshModifTracer.IsMeshModified() )
3055     if ( const SMDS_MeshNode* n = myMeshModifTracer.GetMesh()->FindNode( myNodeID ))
3056     {
3057       SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( myType );
3058       while ( !isSameDomain && eIt->more() )
3059         isSameDomain = IsSatisfy( eIt->next()->GetID() );
3060     }
3061   if ( !isSameDomain )
3062     clearOkIDs();
3063 }
3064
3065 void ConnectedElements::SetPoint( double x, double y, double z )
3066 {
3067   myXYZ.resize(3);
3068   myXYZ[0] = x;
3069   myXYZ[1] = y;
3070   myXYZ[2] = z;
3071   myNodeID = 0;
3072
3073   bool isSameDomain = false;
3074
3075   // find myNodeID by myXYZ if possible
3076   if ( myMeshModifTracer.GetMesh() )
3077   {
3078     SMESHUtils::Deleter<SMESH_ElementSearcher> searcher
3079       ( SMESH_MeshAlgos::GetElementSearcher( (SMDS_Mesh&) *myMeshModifTracer.GetMesh() ));
3080
3081     std::vector< const SMDS_MeshElement* > foundElems;
3082     searcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_All, foundElems );
3083
3084     if ( !foundElems.empty() )
3085     {
3086       myNodeID = foundElems[0]->GetNode(0)->GetID();
3087       if ( myOkIDsReady && !myMeshModifTracer.IsMeshModified() )
3088         isSameDomain = IsSatisfy( foundElems[0]->GetID() );
3089     }
3090   }
3091   if ( !isSameDomain )
3092     clearOkIDs();
3093 }
3094
3095 bool ConnectedElements::IsSatisfy( long theElementId )
3096 {
3097   // Here we do NOT check if the mesh has changed, we do it in Set...() only!!!
3098
3099   if ( !myOkIDsReady )
3100   {
3101     if ( !myMeshModifTracer.GetMesh() )
3102       return false;
3103     const SMDS_MeshNode* node0 = myMeshModifTracer.GetMesh()->FindNode( myNodeID );
3104     if ( !node0 )
3105       return false;
3106
3107     std::list< const SMDS_MeshNode* > nodeQueue( 1, node0 );
3108     std::set< int > checkedNodeIDs;
3109     // algo:
3110     // foreach node in nodeQueue:
3111     //   foreach element sharing a node:
3112     //     add ID of an element of myType to myOkIDs;
3113     //     push all element nodes absent from checkedNodeIDs to nodeQueue;
3114     while ( !nodeQueue.empty() )
3115     {
3116       const SMDS_MeshNode* node = nodeQueue.front();
3117       nodeQueue.pop_front();
3118
3119       // loop on elements sharing the node
3120       SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3121       while ( eIt->more() )
3122       {
3123         // keep elements of myType
3124         const SMDS_MeshElement* element = eIt->next();
3125         if ( myType == SMDSAbs_All || element->GetType() == myType )
3126           myOkIDs.insert( myOkIDs.end(), element->GetID() );
3127
3128         // enqueue nodes of the element
3129         SMDS_ElemIteratorPtr nIt = element->nodesIterator();
3130         while ( nIt->more() )
3131         {
3132           const SMDS_MeshNode* n = static_cast< const SMDS_MeshNode* >( nIt->next() );
3133           if ( checkedNodeIDs.insert( n->GetID() ).second )
3134             nodeQueue.push_back( n );
3135         }
3136       }
3137     }
3138     if ( myType == SMDSAbs_Node )
3139       std::swap( myOkIDs, checkedNodeIDs );
3140
3141     size_t totalNbElems = myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType );
3142     if ( myOkIDs.size() == totalNbElems )
3143       myOkIDs.clear();
3144
3145     myOkIDsReady = true;
3146   }
3147
3148   return myOkIDs.empty() ? true : myOkIDs.count( theElementId );
3149 }
3150
3151 //================================================================================
3152 /*!
3153  * \brief Class CoplanarFaces
3154  */
3155 //================================================================================
3156
3157 namespace
3158 {
3159   inline bool isLessAngle( const gp_Vec& v1, const gp_Vec& v2, const double cos )
3160   {
3161     double dot = v1 * v2; // cos * |v1| * |v2|
3162     double l1  = v1.SquareMagnitude();
3163     double l2  = v2.SquareMagnitude();
3164     return (( dot * cos >= 0 ) &&
3165             ( dot * dot ) / l1 / l2 >= ( cos * cos ));
3166   }
3167 }
3168 CoplanarFaces::CoplanarFaces()
3169   : myFaceID(0), myToler(0)
3170 {
3171 }
3172 void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh )
3173 {
3174   myMeshModifTracer.SetMesh( theMesh );
3175   if ( myMeshModifTracer.IsMeshModified() )
3176   {
3177     // Build a set of coplanar face ids
3178
3179     myCoplanarIDs.Clear();
3180
3181     if ( !myMeshModifTracer.GetMesh() || !myFaceID || !myToler )
3182       return;
3183
3184     const SMDS_MeshElement* face = myMeshModifTracer.GetMesh()->FindElement( myFaceID );
3185     if ( !face || face->GetType() != SMDSAbs_Face )
3186       return;
3187
3188     bool normOK;
3189     gp_Vec myNorm = getNormale( static_cast<const SMDS_MeshFace*>(face), &normOK );
3190     if (!normOK)
3191       return;
3192
3193     const double cosTol = Cos( myToler * M_PI / 180. );
3194     NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks;
3195
3196     std::list< std::pair< const SMDS_MeshElement*, gp_Vec > > faceQueue;
3197     faceQueue.push_back( std::make_pair( face, myNorm ));
3198     while ( !faceQueue.empty() )
3199     {
3200       face   = faceQueue.front().first;
3201       myNorm = faceQueue.front().second;
3202       faceQueue.pop_front();
3203
3204       for ( int i = 0, nbN = face->NbCornerNodes(); i < nbN; ++i )
3205       {
3206         const SMDS_MeshNode*  n1 = face->GetNode( i );
3207         const SMDS_MeshNode*  n2 = face->GetNode(( i+1 )%nbN);
3208         if ( !checkedLinks.Add( SMESH_TLink( n1, n2 )))
3209           continue;
3210         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator(SMDSAbs_Face);
3211         while ( fIt->more() )
3212         {
3213           const SMDS_MeshElement* f = fIt->next();
3214           if ( f->GetNodeIndex( n2 ) > -1 )
3215           {
3216             gp_Vec norm = getNormale( static_cast<const SMDS_MeshFace*>(f), &normOK );
3217             if (!normOK || isLessAngle( myNorm, norm, cosTol))
3218             {
3219               myCoplanarIDs.Add( f->GetID() );
3220               faceQueue.push_back( std::make_pair( f, norm ));
3221             }
3222           }
3223         }
3224       }
3225     }
3226   }
3227 }
3228 bool CoplanarFaces::IsSatisfy( long theElementId )
3229 {
3230   return myCoplanarIDs.Contains( theElementId );
3231 }
3232
3233 /*
3234  *Class       : RangeOfIds
3235   *Description : Predicate for Range of Ids.
3236   *              Range may be specified with two ways.
3237   *              1. Using AddToRange method
3238   *              2. With SetRangeStr method. Parameter of this method is a string
3239   *                 like as "1,2,3,50-60,63,67,70-"
3240 */
3241
3242 //=======================================================================
3243 // name    : RangeOfIds
3244 // Purpose : Constructor
3245 //=======================================================================
3246 RangeOfIds::RangeOfIds()
3247 {
3248   myMesh = 0;
3249   myType = SMDSAbs_All;
3250 }
3251
3252 //=======================================================================
3253 // name    : SetMesh
3254 // Purpose : Set mesh
3255 //=======================================================================
3256 void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
3257 {
3258   myMesh = theMesh;
3259 }
3260
3261 //=======================================================================
3262 // name    : AddToRange
3263 // Purpose : Add ID to the range
3264 //=======================================================================
3265 bool RangeOfIds::AddToRange( long theEntityId )
3266 {
3267   myIds.Add( theEntityId );
3268   return true;
3269 }
3270
3271 //=======================================================================
3272 // name    : GetRangeStr
3273 // Purpose : Get range as a string.
3274 //           Example: "1,2,3,50-60,63,67,70-"
3275 //=======================================================================
3276 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
3277 {
3278   theResStr.Clear();
3279
3280   TColStd_SequenceOfInteger     anIntSeq;
3281   TColStd_SequenceOfAsciiString aStrSeq;
3282
3283   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
3284   for ( ; anIter.More(); anIter.Next() )
3285   {
3286     int anId = anIter.Key();
3287     TCollection_AsciiString aStr( anId );
3288     anIntSeq.Append( anId );
3289     aStrSeq.Append( aStr );
3290   }
3291
3292   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
3293   {
3294     int aMinId = myMin( i );
3295     int aMaxId = myMax( i );
3296
3297     TCollection_AsciiString aStr;
3298     if ( aMinId != IntegerFirst() )
3299       aStr += aMinId;
3300
3301     aStr += "-";
3302
3303     if ( aMaxId != IntegerLast() )
3304       aStr += aMaxId;
3305
3306     // find position of the string in result sequence and insert string in it
3307     if ( anIntSeq.Length() == 0 )
3308     {
3309       anIntSeq.Append( aMinId );
3310       aStrSeq.Append( aStr );
3311     }
3312     else
3313     {
3314       if ( aMinId < anIntSeq.First() )
3315       {
3316         anIntSeq.Prepend( aMinId );
3317         aStrSeq.Prepend( aStr );
3318       }
3319       else if ( aMinId > anIntSeq.Last() )
3320       {
3321         anIntSeq.Append( aMinId );
3322         aStrSeq.Append( aStr );
3323       }
3324       else
3325         for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
3326           if ( aMinId < anIntSeq( j ) )
3327           {
3328             anIntSeq.InsertBefore( j, aMinId );
3329             aStrSeq.InsertBefore( j, aStr );
3330             break;
3331           }
3332     }
3333   }
3334
3335   if ( aStrSeq.Length() == 0 )
3336     return;
3337
3338   theResStr = aStrSeq( 1 );
3339   for ( int j = 2, k = aStrSeq.Length(); j <= k; j++  )
3340   {
3341     theResStr += ",";
3342     theResStr += aStrSeq( j );
3343   }
3344 }
3345
3346 //=======================================================================
3347 // name    : SetRangeStr
3348 // Purpose : Define range with string
3349 //           Example of entry string: "1,2,3,50-60,63,67,70-"
3350 //=======================================================================
3351 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
3352 {
3353   myMin.Clear();
3354   myMax.Clear();
3355   myIds.Clear();
3356
3357   TCollection_AsciiString aStr = theStr;
3358   for ( int i = 1; i <= aStr.Length(); ++i )
3359   {
3360     char c = aStr.Value( i );
3361     if ( !isdigit( c ) && c != ',' && c != '-' )
3362       aStr.SetValue( i, ',');
3363   }
3364   aStr.RemoveAll( ' ' );
3365
3366   TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
3367   int i = 1;
3368   while ( tmpStr != "" )
3369   {
3370     tmpStr = aStr.Token( ",", i++ );
3371     int aPos = tmpStr.Search( '-' );
3372
3373     if ( aPos == -1 )
3374     {
3375       if ( tmpStr.IsIntegerValue() )
3376         myIds.Add( tmpStr.IntegerValue() );
3377       else
3378         return false;
3379     }
3380     else
3381     {
3382       TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
3383       TCollection_AsciiString aMinStr = tmpStr;
3384
3385       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
3386       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
3387
3388       if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
3389            (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
3390         return false;
3391
3392       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
3393       myMax.Append( aMaxStr.IsEmpty() ? IntegerLast()  : aMaxStr.IntegerValue() );
3394     }
3395   }
3396
3397   return true;
3398 }
3399
3400 //=======================================================================
3401 // name    : GetType
3402 // Purpose : Get type of supported entities
3403 //=======================================================================
3404 SMDSAbs_ElementType RangeOfIds::GetType() const
3405 {
3406   return myType;
3407 }
3408
3409 //=======================================================================
3410 // name    : SetType
3411 // Purpose : Set type of supported entities
3412 //=======================================================================
3413 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
3414 {
3415   myType = theType;
3416 }
3417
3418 //=======================================================================
3419 // name    : IsSatisfy
3420 // Purpose : Verify whether entity satisfies to this rpedicate
3421 //=======================================================================
3422 bool RangeOfIds::IsSatisfy( long theId )
3423 {
3424   if ( !myMesh )
3425     return false;
3426
3427   if ( myType == SMDSAbs_Node )
3428   {
3429     if ( myMesh->FindNode( theId ) == 0 )
3430       return false;
3431   }
3432   else
3433   {
3434     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3435     if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
3436       return false;
3437   }
3438
3439   if ( myIds.Contains( theId ) )
3440     return true;
3441
3442   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
3443     if ( theId >= myMin( i ) && theId <= myMax( i ) )
3444       return true;
3445
3446   return false;
3447 }
3448
3449 /*
3450   Class       : Comparator
3451   Description : Base class for comparators
3452 */
3453 Comparator::Comparator():
3454   myMargin(0)
3455 {}
3456
3457 Comparator::~Comparator()
3458 {}
3459
3460 void Comparator::SetMesh( const SMDS_Mesh* theMesh )
3461 {
3462   if ( myFunctor )
3463     myFunctor->SetMesh( theMesh );
3464 }
3465
3466 void Comparator::SetMargin( double theValue )
3467 {
3468   myMargin = theValue;
3469 }
3470
3471 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
3472 {
3473   myFunctor = theFunct;
3474 }
3475
3476 SMDSAbs_ElementType Comparator::GetType() const
3477 {
3478   return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
3479 }
3480
3481 double Comparator::GetMargin()
3482 {
3483   return myMargin;
3484 }
3485
3486
3487 /*
3488   Class       : LessThan
3489   Description : Comparator "<"
3490 */
3491 bool LessThan::IsSatisfy( long theId )
3492 {
3493   return myFunctor && myFunctor->GetValue( theId ) < myMargin;
3494 }
3495
3496
3497 /*
3498   Class       : MoreThan
3499   Description : Comparator ">"
3500 */
3501 bool MoreThan::IsSatisfy( long theId )
3502 {
3503   return myFunctor && myFunctor->GetValue( theId ) > myMargin;
3504 }
3505
3506
3507 /*
3508   Class       : EqualTo
3509   Description : Comparator "="
3510 */
3511 EqualTo::EqualTo():
3512   myToler(Precision::Confusion())
3513 {}
3514
3515 bool EqualTo::IsSatisfy( long theId )
3516 {
3517   return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
3518 }
3519
3520 void EqualTo::SetTolerance( double theToler )
3521 {
3522   myToler = theToler;
3523 }
3524
3525 double EqualTo::GetTolerance()
3526 {
3527   return myToler;
3528 }
3529
3530 /*
3531   Class       : LogicalNOT
3532   Description : Logical NOT predicate
3533 */
3534 LogicalNOT::LogicalNOT()
3535 {}
3536
3537 LogicalNOT::~LogicalNOT()
3538 {}
3539
3540 bool LogicalNOT::IsSatisfy( long theId )
3541 {
3542   return myPredicate && !myPredicate->IsSatisfy( theId );
3543 }
3544
3545 void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
3546 {
3547   if ( myPredicate )
3548     myPredicate->SetMesh( theMesh );
3549 }
3550
3551 void LogicalNOT::SetPredicate( PredicatePtr thePred )
3552 {
3553   myPredicate = thePred;
3554 }
3555
3556 SMDSAbs_ElementType LogicalNOT::GetType() const
3557 {
3558   return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
3559 }
3560
3561
3562 /*
3563   Class       : LogicalBinary
3564   Description : Base class for binary logical predicate
3565 */
3566 LogicalBinary::LogicalBinary()
3567 {}
3568
3569 LogicalBinary::~LogicalBinary()
3570 {}
3571
3572 void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
3573 {
3574   if ( myPredicate1 )
3575     myPredicate1->SetMesh( theMesh );
3576
3577   if ( myPredicate2 )
3578     myPredicate2->SetMesh( theMesh );
3579 }
3580
3581 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
3582 {
3583   myPredicate1 = thePredicate;
3584 }
3585
3586 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
3587 {
3588   myPredicate2 = thePredicate;
3589 }
3590
3591 SMDSAbs_ElementType LogicalBinary::GetType() const
3592 {
3593   if ( !myPredicate1 || !myPredicate2 )
3594     return SMDSAbs_All;
3595
3596   SMDSAbs_ElementType aType1 = myPredicate1->GetType();
3597   SMDSAbs_ElementType aType2 = myPredicate2->GetType();
3598
3599   return aType1 == aType2 ? aType1 : SMDSAbs_All;
3600 }
3601
3602
3603 /*
3604   Class       : LogicalAND
3605   Description : Logical AND
3606 */
3607 bool LogicalAND::IsSatisfy( long theId )
3608 {
3609   return
3610     myPredicate1 &&
3611     myPredicate2 &&
3612     myPredicate1->IsSatisfy( theId ) &&
3613     myPredicate2->IsSatisfy( theId );
3614 }
3615
3616
3617 /*
3618   Class       : LogicalOR
3619   Description : Logical OR
3620 */
3621 bool LogicalOR::IsSatisfy( long theId )
3622 {
3623   return
3624     myPredicate1 &&
3625     myPredicate2 &&
3626     (myPredicate1->IsSatisfy( theId ) ||
3627     myPredicate2->IsSatisfy( theId ));
3628 }
3629
3630
3631 /*
3632                               FILTER
3633 */
3634
3635 // #ifdef WITH_TBB
3636 // #include <tbb/parallel_for.h>
3637 // #include <tbb/enumerable_thread_specific.h>
3638
3639 // namespace Parallel
3640 // {
3641 //   typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq;
3642
3643 //   struct Predicate
3644 //   {
3645 //     const SMDS_Mesh* myMesh;
3646 //     PredicatePtr     myPredicate;
3647 //     TIdSeq &         myOKIds;
3648 //     Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ):
3649 //       myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {}
3650 //     void operator() ( const tbb::blocked_range<size_t>& r ) const
3651 //     {
3652 //       for ( size_t i = r.begin(); i != r.end(); ++i )
3653 //         if ( myPredicate->IsSatisfy( i ))
3654 //           myOKIds.local().push_back();
3655 //     }
3656 //   }
3657 // }
3658 // #endif
3659
3660 Filter::Filter()
3661 {}
3662
3663 Filter::~Filter()
3664 {}
3665
3666 void Filter::SetPredicate( PredicatePtr thePredicate )
3667 {
3668   myPredicate = thePredicate;
3669 }
3670
3671 void Filter::GetElementsId( const SMDS_Mesh*     theMesh,
3672                             PredicatePtr         thePredicate,
3673                             TIdSequence&         theSequence,
3674                             SMDS_ElemIteratorPtr theElements )
3675 {
3676   theSequence.clear();
3677
3678   if ( !theMesh || !thePredicate )
3679     return;
3680
3681   thePredicate->SetMesh( theMesh );
3682
3683   if ( !theElements )
3684     theElements = theMesh->elementsIterator( thePredicate->GetType() );
3685
3686   if ( theElements ) {
3687     while ( theElements->more() ) {
3688       const SMDS_MeshElement* anElem = theElements->next();
3689       if ( thePredicate->GetType() == SMDSAbs_All ||
3690            thePredicate->GetType() == anElem->GetType() )
3691       {
3692         long anId = anElem->GetID();
3693         if ( thePredicate->IsSatisfy( anId ) )
3694           theSequence.push_back( anId );
3695       }
3696     }
3697   }
3698 }
3699
3700 void Filter::GetElementsId( const SMDS_Mesh*     theMesh,
3701                             Filter::TIdSequence& theSequence,
3702                             SMDS_ElemIteratorPtr theElements )
3703 {
3704   GetElementsId(theMesh,myPredicate,theSequence,theElements);
3705 }
3706
3707 /*
3708                               ManifoldPart
3709 */
3710
3711 typedef std::set<SMDS_MeshFace*>                    TMapOfFacePtr;
3712
3713 /*
3714    Internal class Link
3715 */
3716
3717 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
3718                           SMDS_MeshNode* theNode2 )
3719 {
3720   myNode1 = theNode1;
3721   myNode2 = theNode2;
3722 }
3723
3724 ManifoldPart::Link::~Link()
3725 {
3726   myNode1 = 0;
3727   myNode2 = 0;
3728 }
3729
3730 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
3731 {
3732   if ( myNode1 == theLink.myNode1 &&
3733        myNode2 == theLink.myNode2 )
3734     return true;
3735   else if ( myNode1 == theLink.myNode2 &&
3736             myNode2 == theLink.myNode1 )
3737     return true;
3738   else
3739     return false;
3740 }
3741
3742 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
3743 {
3744   if(myNode1 < x.myNode1) return true;
3745   if(myNode1 == x.myNode1)
3746     if(myNode2 < x.myNode2) return true;
3747   return false;
3748 }
3749
3750 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
3751                             const ManifoldPart::Link& theLink2 )
3752 {
3753   return theLink1.IsEqual( theLink2 );
3754 }
3755
3756 ManifoldPart::ManifoldPart()
3757 {
3758   myMesh = 0;
3759   myAngToler = Precision::Angular();
3760   myIsOnlyManifold = true;
3761 }
3762
3763 ManifoldPart::~ManifoldPart()
3764 {
3765   myMesh = 0;
3766 }
3767
3768 void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
3769 {
3770   myMesh = theMesh;
3771   process();
3772 }
3773
3774 SMDSAbs_ElementType ManifoldPart::GetType() const
3775 { return SMDSAbs_Face; }
3776
3777 bool ManifoldPart::IsSatisfy( long theElementId )
3778 {
3779   return myMapIds.Contains( theElementId );
3780 }
3781
3782 void ManifoldPart::SetAngleTolerance( const double theAngToler )
3783 { myAngToler = theAngToler; }
3784
3785 double ManifoldPart::GetAngleTolerance() const
3786 { return myAngToler; }
3787
3788 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
3789 { myIsOnlyManifold = theIsOnly; }
3790
3791 void ManifoldPart::SetStartElem( const long  theStartId )
3792 { myStartElemId = theStartId; }
3793
3794 bool ManifoldPart::process()
3795 {
3796   myMapIds.Clear();
3797   myMapBadGeomIds.Clear();
3798
3799   myAllFacePtr.clear();
3800   myAllFacePtrIntDMap.clear();
3801   if ( !myMesh )
3802     return false;
3803
3804   // collect all faces into own map
3805   SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
3806   for (; anFaceItr->more(); )
3807   {
3808     SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
3809     myAllFacePtr.push_back( aFacePtr );
3810     myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
3811   }
3812
3813   SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
3814   if ( !aStartFace )
3815     return false;
3816
3817   // the map of non manifold links and bad geometry
3818   TMapOfLink aMapOfNonManifold;
3819   TColStd_MapOfInteger aMapOfTreated;
3820
3821   // begin cycle on faces from start index and run on vector till the end
3822   //  and from begin to start index to cover whole vector
3823   const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
3824   bool isStartTreat = false;
3825   for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
3826   {
3827     if ( fi == aStartIndx )
3828       isStartTreat = true;
3829     // as result next time when fi will be equal to aStartIndx
3830
3831     SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
3832     if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
3833       continue;
3834
3835     aMapOfTreated.Add( aFacePtr->GetID() );
3836     TColStd_MapOfInteger aResFaces;
3837     if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
3838                          aMapOfNonManifold, aResFaces ) )
3839       continue;
3840     TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
3841     for ( ; anItr.More(); anItr.Next() )
3842     {
3843       int aFaceId = anItr.Key();
3844       aMapOfTreated.Add( aFaceId );
3845       myMapIds.Add( aFaceId );
3846     }
3847
3848     if ( fi == int( myAllFacePtr.size() - 1 ))
3849       fi = 0;
3850   } // end run on vector of faces
3851   return !myMapIds.IsEmpty();
3852 }
3853
3854 static void getLinks( const SMDS_MeshFace* theFace,
3855                       ManifoldPart::TVectorOfLink& theLinks )
3856 {
3857   int aNbNode = theFace->NbNodes();
3858   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
3859   int i = 1;
3860   SMDS_MeshNode* aNode = 0;
3861   for ( ; aNodeItr->more() && i <= aNbNode; )
3862   {
3863
3864     SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
3865     if ( i == 1 )
3866       aNode = aN1;
3867     i++;
3868     SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
3869     i++;
3870     ManifoldPart::Link aLink( aN1, aN2 );
3871     theLinks.push_back( aLink );
3872   }
3873 }
3874
3875 bool ManifoldPart::findConnected
3876                  ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
3877                   SMDS_MeshFace*                           theStartFace,
3878                   ManifoldPart::TMapOfLink&                theNonManifold,
3879                   TColStd_MapOfInteger&                    theResFaces )
3880 {
3881   theResFaces.Clear();
3882   if ( !theAllFacePtrInt.size() )
3883     return false;
3884
3885   if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
3886   {
3887     myMapBadGeomIds.Add( theStartFace->GetID() );
3888     return false;
3889   }
3890
3891   ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
3892   ManifoldPart::TVectorOfLink aSeqOfBoundary;
3893   theResFaces.Add( theStartFace->GetID() );
3894   ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
3895
3896   expandBoundary( aMapOfBoundary, aSeqOfBoundary,
3897                  aDMapLinkFace, theNonManifold, theStartFace );
3898
3899   bool isDone = false;
3900   while ( !isDone && aMapOfBoundary.size() != 0 )
3901   {
3902     bool isToReset = false;
3903     ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
3904     for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
3905     {
3906       ManifoldPart::Link aLink = *pLink;
3907       if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
3908         continue;
3909       // each link could be treated only once
3910       aMapToSkip.insert( aLink );
3911
3912       ManifoldPart::TVectorOfFacePtr aFaces;
3913       // find next
3914       if ( myIsOnlyManifold &&
3915            (theNonManifold.find( aLink ) != theNonManifold.end()) )
3916         continue;
3917       else
3918       {
3919         getFacesByLink( aLink, aFaces );
3920         // filter the element to keep only indicated elements
3921         ManifoldPart::TVectorOfFacePtr aFiltered;
3922         ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
3923         for ( ; pFace != aFaces.end(); ++pFace )
3924         {
3925           SMDS_MeshFace* aFace = *pFace;
3926           if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
3927             aFiltered.push_back( aFace );
3928         }
3929         aFaces = aFiltered;
3930         if ( aFaces.size() < 2 )  // no neihgbour faces
3931           continue;
3932         else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
3933         {
3934           theNonManifold.insert( aLink );
3935           continue;
3936         }
3937       }
3938
3939       // compare normal with normals of neighbor element
3940       SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
3941       ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
3942       for ( ; pFace != aFaces.end(); ++pFace )
3943       {
3944         SMDS_MeshFace* aNextFace = *pFace;
3945         if ( aPrevFace == aNextFace )
3946           continue;
3947         int anNextFaceID = aNextFace->GetID();
3948         if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
3949          // should not be with non manifold restriction. probably bad topology
3950           continue;
3951         // check if face was treated and skipped
3952         if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
3953              !isInPlane( aPrevFace, aNextFace ) )
3954           continue;
3955         // add new element to connected and extend the boundaries.
3956         theResFaces.Add( anNextFaceID );
3957         expandBoundary( aMapOfBoundary, aSeqOfBoundary,
3958                         aDMapLinkFace, theNonManifold, aNextFace );
3959         isToReset = true;
3960       }
3961     }
3962     isDone = !isToReset;
3963   }
3964
3965   return !theResFaces.IsEmpty();
3966 }
3967
3968 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
3969                               const SMDS_MeshFace* theFace2 )
3970 {
3971   gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
3972   gp_XYZ aNorm2XYZ = getNormale( theFace2 );
3973   if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
3974   {
3975     myMapBadGeomIds.Add( theFace2->GetID() );
3976     return false;
3977   }
3978   if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
3979     return true;
3980
3981   return false;
3982 }
3983
3984 void ManifoldPart::expandBoundary
3985                    ( ManifoldPart::TMapOfLink&            theMapOfBoundary,
3986                      ManifoldPart::TVectorOfLink&         theSeqOfBoundary,
3987                      ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
3988                      ManifoldPart::TMapOfLink&            theNonManifold,
3989                      SMDS_MeshFace*                       theNextFace ) const
3990 {
3991   ManifoldPart::TVectorOfLink aLinks;
3992   getLinks( theNextFace, aLinks );
3993   int aNbLink = (int)aLinks.size();
3994   for ( int i = 0; i < aNbLink; i++ )
3995   {
3996     ManifoldPart::Link aLink = aLinks[ i ];
3997     if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
3998       continue;
3999     if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
4000     {
4001       if ( myIsOnlyManifold )
4002       {
4003         // remove from boundary
4004         theMapOfBoundary.erase( aLink );
4005         ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
4006         for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
4007         {
4008           ManifoldPart::Link aBoundLink = *pLink;
4009           if ( aBoundLink.IsEqual( aLink ) )
4010           {
4011             theSeqOfBoundary.erase( pLink );
4012             break;
4013           }
4014         }
4015       }
4016     }
4017     else
4018     {
4019       theMapOfBoundary.insert( aLink );
4020       theSeqOfBoundary.push_back( aLink );
4021       theDMapLinkFacePtr[ aLink ] = theNextFace;
4022     }
4023   }
4024 }
4025
4026 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
4027                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
4028 {
4029
4030   // take all faces that shared first node
4031   SMDS_ElemIteratorPtr anItr = theLink.myNode1->GetInverseElementIterator( SMDSAbs_Face );
4032   SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > faces( anItr ), facesEnd;
4033   std::set<const SMDS_MeshElement *> aSetOfFaces( faces, facesEnd );
4034
4035   // take all faces that shared second node
4036   anItr = theLink.myNode2->GetInverseElementIterator( SMDSAbs_Face );
4037   // find the common part of two sets
4038   for ( ; anItr->more(); )
4039   {
4040     const SMDS_MeshElement* aFace = anItr->next();
4041     if ( aSetOfFaces.count( aFace ))
4042       theFaces.push_back( (SMDS_MeshFace*) aFace );
4043   }
4044 }
4045
4046 /*
4047   Class       : BelongToMeshGroup
4048   Description : Verify whether a mesh element is included into a mesh group
4049 */
4050 BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 )
4051 {
4052 }
4053
4054 void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g )
4055 {
4056   myGroup = g;
4057 }
4058
4059 void BelongToMeshGroup::SetStoreName( const std::string& sn )
4060 {
4061   myStoreName = sn;
4062 }
4063
4064 void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh )
4065 {
4066   if ( myGroup && myGroup->GetMesh() != theMesh )
4067   {
4068     myGroup = 0;
4069   }
4070   if ( !myGroup && !myStoreName.empty() )
4071   {
4072     if ( const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh))
4073     {
4074       const std::set<SMESHDS_GroupBase*>& grps = aMesh->GetGroups();
4075       std::set<SMESHDS_GroupBase*>::const_iterator g = grps.begin();
4076       for ( ; g != grps.end() && !myGroup; ++g )
4077         if ( *g && myStoreName == (*g)->GetStoreName() )
4078           myGroup = *g;
4079     }
4080   }
4081   if ( myGroup )
4082   {
4083     myGroup->IsEmpty(); // make GroupOnFilter update its predicate
4084   }
4085 }
4086
4087 bool BelongToMeshGroup::IsSatisfy( long theElementId )
4088 {
4089   return myGroup ? myGroup->Contains( theElementId ) : false;
4090 }
4091
4092 SMDSAbs_ElementType BelongToMeshGroup::GetType() const
4093 {
4094   return myGroup ? myGroup->GetType() : SMDSAbs_All;
4095 }
4096
4097 //================================================================================
4098 //  ElementsOnSurface
4099 //================================================================================
4100
4101 ElementsOnSurface::ElementsOnSurface()
4102 {
4103   myIds.Clear();
4104   myType = SMDSAbs_All;
4105   mySurf.Nullify();
4106   myToler = Precision::Confusion();
4107   myUseBoundaries = false;
4108 }
4109
4110 ElementsOnSurface::~ElementsOnSurface()
4111 {
4112 }
4113
4114 void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
4115 {
4116   myMeshModifTracer.SetMesh( theMesh );
4117   if ( myMeshModifTracer.IsMeshModified())
4118     process();
4119 }
4120
4121 bool ElementsOnSurface::IsSatisfy( long theElementId )
4122 {
4123   return myIds.Contains( theElementId );
4124 }
4125
4126 SMDSAbs_ElementType ElementsOnSurface::GetType() const
4127 { return myType; }
4128
4129 void ElementsOnSurface::SetTolerance( const double theToler )
4130 {
4131   if ( myToler != theToler )
4132   {
4133     myToler = theToler;
4134     process();
4135   }
4136 }
4137
4138 double ElementsOnSurface::GetTolerance() const
4139 { return myToler; }
4140
4141 void ElementsOnSurface::SetUseBoundaries( bool theUse )
4142 {
4143   if ( myUseBoundaries != theUse ) {
4144     myUseBoundaries = theUse;
4145     SetSurface( mySurf, myType );
4146   }
4147 }
4148
4149 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
4150                                     const SMDSAbs_ElementType theType )
4151 {
4152   myIds.Clear();
4153   myType = theType;
4154   mySurf.Nullify();
4155   if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
4156     return;
4157   mySurf = TopoDS::Face( theShape );
4158   BRepAdaptor_Surface SA( mySurf, myUseBoundaries );
4159   Standard_Real
4160     u1 = SA.FirstUParameter(),
4161     u2 = SA.LastUParameter(),
4162     v1 = SA.FirstVParameter(),
4163     v2 = SA.LastVParameter();
4164   Handle(Geom_Surface) surf = BRep_Tool::Surface( mySurf );
4165   myProjector.Init( surf, u1,u2, v1,v2 );
4166   process();
4167 }
4168
4169 void ElementsOnSurface::process()
4170 {
4171   myIds.Clear();
4172   if ( mySurf.IsNull() )
4173     return;
4174
4175   if ( !myMeshModifTracer.GetMesh() )
4176     return;
4177
4178   myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ));
4179
4180   SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType );
4181   for(; anIter->more(); )
4182     process( anIter->next() );
4183 }
4184
4185 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
4186 {
4187   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
4188   bool isSatisfy = true;
4189   for ( ; aNodeItr->more(); )
4190   {
4191     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
4192     if ( !isOnSurface( aNode ) )
4193     {
4194       isSatisfy = false;
4195       break;
4196     }
4197   }
4198   if ( isSatisfy )
4199     myIds.Add( theElemPtr->GetID() );
4200 }
4201
4202 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
4203 {
4204   if ( mySurf.IsNull() )
4205     return false;
4206
4207   gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
4208   //  double aToler2 = myToler * myToler;
4209 //   if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
4210 //   {
4211 //     gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
4212 //     if ( aPln.SquareDistance( aPnt ) > aToler2 )
4213 //       return false;
4214 //   }
4215 //   else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
4216 //   {
4217 //     gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
4218 //     double aRad = aCyl.Radius();
4219 //     gp_Ax3 anAxis = aCyl.Position();
4220 //     gp_XYZ aLoc = aCyl.Location().XYZ();
4221 //     double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4222 //     double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4223 //     if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
4224 //       return false;
4225 //   }
4226 //   else
4227 //     return false;
4228   myProjector.Perform( aPnt );
4229   bool isOn = ( myProjector.IsDone() && myProjector.LowerDistance() <= myToler );
4230
4231   return isOn;
4232 }
4233
4234
4235 //================================================================================
4236 //  ElementsOnShape
4237 //================================================================================
4238
4239 namespace {
4240   const int theIsCheckedFlag = 0x0000100;
4241 }
4242
4243 struct ElementsOnShape::Classifier
4244 {
4245   Classifier() { mySolidClfr = 0; myFlags = 0; }
4246   ~Classifier();
4247   void Init(const TopoDS_Shape& s, double tol, const Bnd_B3d* box = 0 );
4248   bool IsOut(const gp_Pnt& p)        { return SetChecked( true ), (this->*myIsOutFun)( p ); }
4249   TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); }
4250   const TopoDS_Shape& Shape() const  { return myShape; }
4251   const Bnd_B3d* GetBndBox() const   { return & myBox; }
4252   double Tolerance() const           { return myTol; }
4253   bool IsChecked()                   { return myFlags & theIsCheckedFlag; }
4254   bool IsSetFlag( int flag ) const   { return myFlags & flag; }
4255   void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); }
4256   void SetFlag  ( int flag ) { myFlags |= flag; }
4257   void UnsetFlag( int flag ) { myFlags &= ~flag; }
4258
4259 private:
4260   bool isOutOfSolid (const gp_Pnt& p);
4261   bool isOutOfBox   (const gp_Pnt& p);
4262   bool isOutOfFace  (const gp_Pnt& p);
4263   bool isOutOfEdge  (const gp_Pnt& p);
4264   bool isOutOfVertex(const gp_Pnt& p);
4265   bool isBox        (const TopoDS_Shape& s);
4266
4267   bool (Classifier::*          myIsOutFun)(const gp_Pnt& p);
4268   BRepClass3d_SolidClassifier* mySolidClfr; // ptr because of a run-time forbidden copy-constructor
4269   Bnd_B3d                      myBox;
4270   GeomAPI_ProjectPointOnSurf   myProjFace;
4271   GeomAPI_ProjectPointOnCurve  myProjEdge;
4272   gp_Pnt                       myVertexXYZ;
4273   TopoDS_Shape                 myShape;
4274   double                       myTol;
4275   int                          myFlags;
4276 };
4277
4278 struct ElementsOnShape::OctreeClassifier : public SMESH_Octree
4279 {
4280   OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers );
4281   OctreeClassifier( const OctreeClassifier*                           otherTree,
4282                     const std::vector< ElementsOnShape::Classifier >& clsOther,
4283                     std::vector< ElementsOnShape::Classifier >&       cls );
4284   void GetClassifiersAtPoint( const gp_XYZ& p,
4285                               std::vector< ElementsOnShape::Classifier* >& classifiers );
4286   size_t GetSize();
4287
4288 protected:
4289   OctreeClassifier() {}
4290   SMESH_Octree* newChild() const { return new OctreeClassifier; }
4291   void          buildChildrenData();
4292   Bnd_B3d*      buildRootBox();
4293
4294   std::vector< ElementsOnShape::Classifier* > myClassifiers;
4295 };
4296
4297
4298 ElementsOnShape::ElementsOnShape():
4299   myOctree(0),
4300   myType(SMDSAbs_All),
4301   myToler(Precision::Confusion()),
4302   myAllNodesFlag(false)
4303 {
4304 }
4305
4306 ElementsOnShape::~ElementsOnShape()
4307 {
4308   clearClassifiers();
4309 }
4310
4311 Predicate* ElementsOnShape::clone() const
4312 {
4313   size_t size = sizeof( *this );
4314   if ( myOctree )
4315     size += myOctree->GetSize();
4316   if ( !myClassifiers.empty() )
4317     size += sizeof( myClassifiers[0] ) * myClassifiers.size();
4318   if ( !myWorkClassifiers.empty() )
4319     size += sizeof( myWorkClassifiers[0] ) * myWorkClassifiers.size();
4320   if ( size > 1e+9 ) // 1G
4321   {
4322 #ifdef _DEBUG_
4323     std::cout << "Avoid ElementsOnShape::clone(), too large: " << size << " bytes " << std::endl;
4324 #endif
4325     return 0;
4326   }
4327
4328   ElementsOnShape* cln = new ElementsOnShape();
4329   cln->SetAllNodes ( myAllNodesFlag );
4330   cln->SetTolerance( myToler );
4331   cln->SetMesh     ( myMeshModifTracer.GetMesh() );
4332   cln->myShape = myShape; // avoid creation of myClassifiers
4333   cln->SetShape    ( myShape, myType );
4334   cln->myClassifiers.resize( myClassifiers.size() );
4335   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4336     cln->myClassifiers[ i ].Init( BRepBuilderAPI_Copy( myClassifiers[ i ].Shape()),
4337                                   myToler, myClassifiers[ i ].GetBndBox() );
4338   if ( myOctree ) // copy myOctree
4339   {
4340     cln->myOctree = new OctreeClassifier( myOctree, myClassifiers, cln->myClassifiers );
4341   }
4342   return cln;
4343 }
4344
4345 SMDSAbs_ElementType ElementsOnShape::GetType() const
4346 {
4347   return myType;
4348 }
4349
4350 void ElementsOnShape::SetTolerance (const double theToler)
4351 {
4352   if (myToler != theToler) {
4353     myToler = theToler;
4354     SetShape(myShape, myType);
4355   }
4356 }
4357
4358 double ElementsOnShape::GetTolerance() const
4359 {
4360   return myToler;
4361 }
4362
4363 void ElementsOnShape::SetAllNodes (bool theAllNodes)
4364 {
4365   myAllNodesFlag = theAllNodes;
4366 }
4367
4368 void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh)
4369 {
4370   myMeshModifTracer.SetMesh( theMesh );
4371   if ( myMeshModifTracer.IsMeshModified())
4372   {
4373     size_t nbNodes = theMesh ? theMesh->NbNodes() : 0;
4374     if ( myNodeIsChecked.size() == nbNodes )
4375     {
4376       std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4377     }
4378     else
4379     {
4380       SMESHUtils::FreeVector( myNodeIsChecked );
4381       SMESHUtils::FreeVector( myNodeIsOut );
4382       myNodeIsChecked.resize( nbNodes, false );
4383       myNodeIsOut.resize( nbNodes );
4384     }
4385   }
4386 }
4387
4388 bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut )
4389 {
4390   if ( n->GetID() >= (int) myNodeIsChecked.size() ||
4391        !myNodeIsChecked[ n->GetID() ])
4392     return false;
4393
4394   isOut = myNodeIsOut[ n->GetID() ];
4395   return true;
4396 }
4397
4398 void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool  isOut )
4399 {
4400   if ( n->GetID() < (int) myNodeIsChecked.size() )
4401   {
4402     myNodeIsChecked[ n->GetID() ] = true;
4403     myNodeIsOut    [ n->GetID() ] = isOut;
4404   }
4405 }
4406
4407 void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
4408                                 const SMDSAbs_ElementType theType)
4409 {
4410   bool shapeChanges = ( myShape != theShape );
4411   myType  = theType;
4412   myShape = theShape;
4413   if ( myShape.IsNull() ) return;
4414
4415   if ( shapeChanges )
4416   {
4417     // find most complex shapes
4418     TopTools_IndexedMapOfShape shapesMap;
4419     TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
4420     TopExp_Explorer sub;
4421     for ( int i = 0; i < 4; ++i )
4422     {
4423       if ( shapesMap.IsEmpty() )
4424         for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() )
4425           shapesMap.Add( sub.Current() );
4426       if ( i > 0 )
4427         for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() )
4428           shapesMap.Add( sub.Current() );
4429     }
4430
4431     clearClassifiers();
4432     myClassifiers.resize( shapesMap.Extent() );
4433     for ( int i = 0; i < shapesMap.Extent(); ++i )
4434       myClassifiers[ i ].Init( shapesMap( i+1 ), myToler );
4435   }
4436
4437   if ( theType == SMDSAbs_Node )
4438   {
4439     SMESHUtils::FreeVector( myNodeIsChecked );
4440     SMESHUtils::FreeVector( myNodeIsOut );
4441   }
4442   else
4443   {
4444     std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4445   }
4446 }
4447
4448 void ElementsOnShape::clearClassifiers()
4449 {
4450   // for ( size_t i = 0; i < myClassifiers.size(); ++i )
4451   //   delete myClassifiers[ i ];
4452   myClassifiers.clear();
4453
4454   delete myOctree;
4455   myOctree = 0;
4456 }
4457
4458 bool ElementsOnShape::IsSatisfy( long elemId )
4459 {
4460   if ( myClassifiers.empty() )
4461     return false;
4462
4463   const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
4464   if ( myType == SMDSAbs_Node )
4465     return IsSatisfy( mesh->FindNode( elemId ));
4466   return IsSatisfy( mesh->FindElement( elemId ));
4467 }
4468
4469 bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
4470 {
4471   if ( !elem )
4472     return false;
4473
4474   bool isSatisfy = myAllNodesFlag, isNodeOut;
4475
4476   gp_XYZ centerXYZ (0, 0, 0);
4477
4478   if ( !myOctree && myClassifiers.size() > 5 )
4479   {
4480     myWorkClassifiers.resize( myClassifiers.size() );
4481     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4482       myWorkClassifiers[ i ] = & myClassifiers[ i ];
4483     myOctree = new OctreeClassifier( myWorkClassifiers );
4484
4485     SMESHUtils::FreeVector( myWorkClassifiers );
4486   }
4487
4488   for ( int i = 0, nb = elem->NbNodes(); i < nb  && (isSatisfy == myAllNodesFlag); ++i )
4489   {
4490     SMESH_TNodeXYZ aPnt( elem->GetNode( i ));
4491     centerXYZ += aPnt;
4492
4493     isNodeOut = true;
4494     if ( !getNodeIsOut( aPnt._node, isNodeOut ))
4495     {
4496       if ( myOctree )
4497       {
4498         myWorkClassifiers.clear();
4499         myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4500
4501         for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4502           myWorkClassifiers[i]->SetChecked( false );
4503
4504         for ( size_t i = 0; i < myWorkClassifiers.size() && isNodeOut; ++i )
4505           if ( !myWorkClassifiers[i]->IsChecked() )
4506             isNodeOut = myWorkClassifiers[i]->IsOut( aPnt );
4507       }
4508       else
4509       {
4510         for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i )
4511           isNodeOut = myClassifiers[i].IsOut( aPnt );
4512       }
4513       setNodeIsOut( aPnt._node, isNodeOut );
4514     }
4515     isSatisfy = !isNodeOut;
4516   }
4517
4518   // Check the center point for volumes MantisBug 0020168
4519   if ( isSatisfy &&
4520        myAllNodesFlag &&
4521        myClassifiers[0].ShapeType() == TopAbs_SOLID )
4522   {
4523     centerXYZ /= elem->NbNodes();
4524     isSatisfy = false;
4525     if ( myOctree )
4526       for ( size_t i = 0; i < myWorkClassifiers.size() && !isSatisfy; ++i )
4527         isSatisfy = ! myWorkClassifiers[i]->IsOut( centerXYZ );
4528     else
4529       for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i )
4530         isSatisfy = ! myClassifiers[i].IsOut( centerXYZ );
4531   }
4532
4533   return isSatisfy;
4534 }
4535
4536 //================================================================================
4537 /*!
4538  * \brief Check and optionally return a satisfying shape
4539  */
4540 //================================================================================
4541
4542 bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
4543                                  TopoDS_Shape*        okShape)
4544 {
4545   if ( !node )
4546     return false;
4547
4548   if ( !myOctree && myClassifiers.size() > 5 )
4549   {
4550     myWorkClassifiers.resize( myClassifiers.size() );
4551     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4552       myWorkClassifiers[ i ] = & myClassifiers[ i ];
4553     myOctree = new OctreeClassifier( myWorkClassifiers );
4554   }
4555
4556   bool isNodeOut = true;
4557
4558   if ( okShape || !getNodeIsOut( node, isNodeOut ))
4559   {
4560     SMESH_NodeXYZ aPnt = node;
4561     if ( myOctree )
4562     {
4563       myWorkClassifiers.clear();
4564       myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4565
4566       for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4567         myWorkClassifiers[i]->SetChecked( false );
4568
4569       for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4570         if ( !myWorkClassifiers[i]->IsChecked() &&
4571              !myWorkClassifiers[i]->IsOut( aPnt ))
4572         {
4573           isNodeOut = false;
4574           if ( okShape )
4575             *okShape = myWorkClassifiers[i]->Shape();
4576           break;
4577         }
4578     }
4579     else
4580     {
4581       for ( size_t i = 0; i < myClassifiers.size(); ++i )
4582         if ( !myClassifiers[i].IsOut( aPnt ))
4583         {
4584           isNodeOut = false;
4585           if ( okShape )
4586             *okShape = myWorkClassifiers[i]->Shape();
4587           break;
4588         }
4589     }
4590     setNodeIsOut( node, isNodeOut );
4591   }
4592
4593   return !isNodeOut;
4594 }
4595
4596 void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
4597                                         double              theTol,
4598                                         const Bnd_B3d*      theBox )
4599 {
4600   myShape = theShape;
4601   myTol   = theTol;
4602   myFlags = 0;
4603
4604   bool isShapeBox = false;
4605   switch ( myShape.ShapeType() )
4606   {
4607   case TopAbs_SOLID:
4608   {
4609     if (( isShapeBox = isBox( theShape )))
4610     {
4611       myIsOutFun = & ElementsOnShape::Classifier::isOutOfBox;
4612     }
4613     else
4614     {
4615       mySolidClfr = new BRepClass3d_SolidClassifier(theShape);
4616       myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid;
4617     }
4618     break;
4619   }
4620   case TopAbs_FACE:
4621   {
4622     Standard_Real u1,u2,v1,v2;
4623     Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape ));
4624     surf->Bounds( u1,u2,v1,v2 );
4625     myProjFace.Init(surf, u1,u2, v1,v2, myTol );
4626     myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace;
4627     break;
4628   }
4629   case TopAbs_EDGE:
4630   {
4631     Standard_Real u1, u2;
4632     Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2);
4633     myProjEdge.Init(curve, u1, u2);
4634     myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge;
4635     break;
4636   }
4637   case TopAbs_VERTEX:
4638   {
4639     myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) );
4640     myIsOutFun = & ElementsOnShape::Classifier::isOutOfVertex;
4641     break;
4642   }
4643   default:
4644     throw SALOME_Exception("Programmer error in usage of ElementsOnShape::Classifier");
4645   }
4646
4647   if ( !isShapeBox )
4648   {
4649     if ( theBox )
4650     {
4651       myBox = *theBox;
4652     }
4653     else
4654     {
4655       Bnd_Box box;
4656       if ( myShape.ShapeType() == TopAbs_FACE )
4657       {
4658         BRepAdaptor_Surface SA( TopoDS::Face( myShape ), /*useBoundaries=*/false );
4659         if ( SA.GetType() == GeomAbs_BSplineSurface )
4660           BRepBndLib::AddOptimal( myShape, box,
4661                                   /*useTriangulation=*/true, /*useShapeTolerance=*/true );
4662       }
4663       if ( box.IsVoid() )
4664         BRepBndLib::Add( myShape, box );
4665       myBox.Clear();
4666       myBox.Add( box.CornerMin() );
4667       myBox.Add( box.CornerMax() );
4668       gp_XYZ halfSize = 0.5 * ( box.CornerMax().XYZ() - box.CornerMin().XYZ() );
4669       for ( int iDim = 1; iDim <= 3; ++iDim )
4670       {
4671         double x = halfSize.Coord( iDim );
4672         halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x ));
4673       }
4674       myBox.SetHSize( halfSize );
4675     }
4676   }
4677 }
4678
4679 ElementsOnShape::Classifier::~Classifier()
4680 {
4681   delete mySolidClfr; mySolidClfr = 0;
4682 }
4683
4684 bool ElementsOnShape::Classifier::isOutOfSolid( const gp_Pnt& p )
4685 {
4686   if ( isOutOfBox( p )) return true;
4687   mySolidClfr->Perform( p, myTol );
4688   return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON );
4689 }
4690
4691 bool ElementsOnShape::Classifier::isOutOfBox( const gp_Pnt& p )
4692 {
4693   return myBox.IsOut( p.XYZ() );
4694 }
4695
4696 bool ElementsOnShape::Classifier::isOutOfFace( const gp_Pnt& p )
4697 {
4698   if ( isOutOfBox( p )) return true;
4699   myProjFace.Perform( p );
4700   if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol )
4701   {
4702     // check relatively to the face
4703     Standard_Real u, v;
4704     myProjFace.LowerDistanceParameters(u, v);
4705     gp_Pnt2d aProjPnt (u, v);
4706     BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
4707     if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON )
4708       return false;
4709   }
4710   return true;
4711 }
4712
4713 bool ElementsOnShape::Classifier::isOutOfEdge( const gp_Pnt& p )
4714 {
4715   if ( isOutOfBox( p )) return true;
4716   myProjEdge.Perform( p );
4717   return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol );
4718 }
4719
4720 bool ElementsOnShape::Classifier::isOutOfVertex( const gp_Pnt& p )
4721 {
4722   return ( myVertexXYZ.Distance( p ) > myTol );
4723 }
4724
4725 bool ElementsOnShape::Classifier::isBox(const TopoDS_Shape& theShape )
4726 {
4727   TopTools_IndexedMapOfShape vMap;
4728   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
4729   if ( vMap.Extent() != 8 )
4730     return false;
4731
4732   myBox.Clear();
4733   for ( int i = 1; i <= 8; ++i )
4734     myBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))).XYZ() );
4735
4736   gp_XYZ pMin = myBox.CornerMin(), pMax = myBox.CornerMax();
4737   for ( int i = 1; i <= 8; ++i )
4738   {
4739     gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vMap( i )));
4740     for ( int iC = 1; iC <= 3; ++ iC )
4741     {
4742       double d1 = Abs( pMin.Coord( iC ) - p.Coord( iC ));
4743       double d2 = Abs( pMax.Coord( iC ) - p.Coord( iC ));
4744       if ( Min( d1, d2 ) > myTol )
4745         return false;
4746     }
4747   }
4748   myBox.Enlarge( myTol );
4749   return true;
4750 }
4751
4752 ElementsOnShape::
4753 OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers )
4754   :SMESH_Octree( new SMESH_TreeLimit )
4755 {
4756   myClassifiers = classifiers;
4757   compute();
4758 }
4759
4760 ElementsOnShape::
4761 OctreeClassifier::OctreeClassifier( const OctreeClassifier*                           otherTree,
4762                                     const std::vector< ElementsOnShape::Classifier >& clsOther,
4763                                     std::vector< ElementsOnShape::Classifier >&       cls )
4764   :SMESH_Octree( new SMESH_TreeLimit )
4765 {
4766   myBox = new Bnd_B3d( *otherTree->getBox() );
4767
4768   if (( myIsLeaf = otherTree->isLeaf() ))
4769   {
4770     myClassifiers.resize( otherTree->myClassifiers.size() );
4771     for ( size_t i = 0; i < otherTree->myClassifiers.size(); ++i )
4772     {
4773       int ind = otherTree->myClassifiers[i] - & clsOther[0];
4774       myClassifiers[ i ] = & cls[ ind ];
4775     }
4776   }
4777   else if ( otherTree->myChildren )
4778   {
4779     myChildren = new SMESH_Tree< Bnd_B3d, 8 > * [ 8 ];
4780     for ( int i = 0; i < nbChildren(); i++ )
4781       myChildren[i] =
4782         new OctreeClassifier( static_cast<const OctreeClassifier*>( otherTree->myChildren[i]),
4783                               clsOther, cls );
4784   }
4785 }
4786
4787 void ElementsOnShape::
4788 OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
4789                                          std::vector< ElementsOnShape::Classifier* >& result )
4790 {
4791   if ( getBox()->IsOut( point ))
4792     return;
4793
4794   if ( isLeaf() )
4795   {
4796     for ( size_t i = 0; i < myClassifiers.size(); ++i )
4797       if ( !myClassifiers[i]->GetBndBox()->IsOut( point ))
4798         result.push_back( myClassifiers[i] );
4799   }
4800   else
4801   {
4802     for (int i = 0; i < nbChildren(); i++)
4803       ((OctreeClassifier*) myChildren[i])->GetClassifiersAtPoint( point, result );
4804   }
4805 }
4806
4807 size_t ElementsOnShape::OctreeClassifier::GetSize()
4808 {
4809   size_t res = sizeof( *this );
4810   if ( !myClassifiers.empty() )
4811     res += sizeof( myClassifiers[0] ) * myClassifiers.size();
4812
4813   if ( !isLeaf() )
4814     for (int i = 0; i < nbChildren(); i++)
4815       res += ((OctreeClassifier*) myChildren[i])->GetSize();
4816
4817   return res;
4818 }
4819
4820 void ElementsOnShape::OctreeClassifier::buildChildrenData()
4821 {
4822   // distribute myClassifiers among myChildren
4823
4824   const int childFlag[8] = { 0x0000001,
4825                              0x0000002,
4826                              0x0000004,
4827                              0x0000008,
4828                              0x0000010,
4829                              0x0000020,
4830                              0x0000040,
4831                              0x0000080 };
4832   int nbInChild[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
4833
4834   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4835   {
4836     for ( int j = 0; j < nbChildren(); j++ )
4837     {
4838       if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() ))
4839       {
4840         myClassifiers[i]->SetFlag( childFlag[ j ]);
4841         ++nbInChild[ j ];
4842       }
4843     }
4844   }
4845
4846   for ( int j = 0; j < nbChildren(); j++ )
4847   {
4848     OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ j ]);
4849     child->myClassifiers.resize( nbInChild[ j ]);
4850     for ( size_t i = 0; nbInChild[ j ] && i < myClassifiers.size(); ++i )
4851     {
4852       if ( myClassifiers[ i ]->IsSetFlag( childFlag[ j ]))
4853       {
4854         --nbInChild[ j ];
4855         child->myClassifiers[ nbInChild[ j ]] = myClassifiers[ i ];
4856         myClassifiers[ i ]->UnsetFlag( childFlag[ j ]);
4857       }
4858     }
4859   }
4860   SMESHUtils::FreeVector( myClassifiers );
4861
4862   // define if a child isLeaf()
4863   for ( int i = 0; i < nbChildren(); i++ )
4864   {
4865     OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
4866     child->myIsLeaf = ( child->myClassifiers.size() <= 5  ||
4867                         child->maxSize() < child->myClassifiers[0]->Tolerance() );
4868   }
4869 }
4870
4871 Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox()
4872 {
4873   Bnd_B3d* box = new Bnd_B3d;
4874   for ( size_t i = 0; i < myClassifiers.size(); ++i )
4875     box->Add( *myClassifiers[i]->GetBndBox() );
4876   return box;
4877 }
4878
4879 /*
4880   Class       : BelongToGeom
4881   Description : Predicate for verifying whether entity belongs to
4882                 specified geometrical support
4883 */
4884
4885 BelongToGeom::BelongToGeom()
4886   : myMeshDS(NULL),
4887     myType(SMDSAbs_NbElementTypes),
4888     myIsSubshape(false),
4889     myTolerance(Precision::Confusion())
4890 {}
4891
4892 Predicate* BelongToGeom::clone() const
4893 {
4894   BelongToGeom* cln = 0;
4895   if ( myElementsOnShapePtr )
4896     if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
4897     {
4898       cln = new BelongToGeom( *this );
4899       cln->myElementsOnShapePtr.reset( eos );
4900     }
4901   return cln;
4902 }
4903
4904 void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh )
4905 {
4906   if ( myMeshDS != theMesh )
4907   {
4908     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
4909     init();
4910   }
4911   if ( myElementsOnShapePtr )
4912     myElementsOnShapePtr->SetMesh( myMeshDS );
4913 }
4914
4915 void BelongToGeom::SetGeom( const TopoDS_Shape& theShape )
4916 {
4917   if ( myShape != theShape )
4918   {
4919     myShape = theShape;
4920     init();
4921   }
4922 }
4923
4924 static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap,
4925                         const TopoDS_Shape&               theShape)
4926 {
4927   if (theMap.Contains(theShape)) return true;
4928
4929   if (theShape.ShapeType() == TopAbs_COMPOUND ||
4930       theShape.ShapeType() == TopAbs_COMPSOLID)
4931   {
4932     TopoDS_Iterator anIt (theShape, Standard_True, Standard_True);
4933     for (; anIt.More(); anIt.Next())
4934     {
4935       if (!IsSubShape(theMap, anIt.Value())) {
4936         return false;
4937       }
4938     }
4939     return true;
4940   }
4941
4942   return false;
4943 }
4944
4945 void BelongToGeom::init()
4946 {
4947   if ( !myMeshDS || myShape.IsNull() ) return;
4948
4949   // is sub-shape of main shape?
4950   TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
4951   if (aMainShape.IsNull()) {
4952     myIsSubshape = false;
4953   }
4954   else {
4955     TopTools_IndexedMapOfShape aMap;
4956     TopExp::MapShapes( aMainShape, aMap );
4957     myIsSubshape = IsSubShape( aMap, myShape );
4958     if ( myIsSubshape )
4959     {
4960       aMap.Clear();
4961       TopExp::MapShapes( myShape, aMap );
4962       mySubShapesIDs.Clear();
4963       for ( int i = 1; i <= aMap.Extent(); ++i )
4964       {
4965         int subID = myMeshDS->ShapeToIndex( aMap( i ));
4966         if ( subID > 0 )
4967           mySubShapesIDs.Add( subID );
4968       }
4969     }
4970   }
4971
4972   //if (!myIsSubshape) // to be always ready to check an element not bound to geometry
4973   {
4974     if ( !myElementsOnShapePtr )
4975       myElementsOnShapePtr.reset( new ElementsOnShape() );
4976     myElementsOnShapePtr->SetTolerance( myTolerance );
4977     myElementsOnShapePtr->SetAllNodes( true ); // "belong", while false means "lays on"
4978     myElementsOnShapePtr->SetMesh( myMeshDS );
4979     myElementsOnShapePtr->SetShape( myShape, myType );
4980   }
4981 }
4982
4983 bool BelongToGeom::IsSatisfy (long theId)
4984 {
4985   if (myMeshDS == 0 || myShape.IsNull())
4986     return false;
4987
4988   if (!myIsSubshape)
4989   {
4990     return myElementsOnShapePtr->IsSatisfy(theId);
4991   }
4992
4993   // Case of sub-mesh
4994
4995   if (myType == SMDSAbs_Node)
4996   {
4997     if ( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ))
4998     {
4999       if ( aNode->getshapeId() < 1 )
5000         return myElementsOnShapePtr->IsSatisfy(theId);
5001       else
5002         return mySubShapesIDs.Contains( aNode->getshapeId() );
5003     }
5004   }
5005   else
5006   {
5007     if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId ))
5008     {
5009       if ( myType == SMDSAbs_All || anElem->GetType() == myType )
5010       {
5011         if ( anElem->getshapeId() < 1 )
5012           return myElementsOnShapePtr->IsSatisfy(theId);
5013         else
5014           return mySubShapesIDs.Contains( anElem->getshapeId() );
5015       }
5016     }
5017   }
5018
5019   return false;
5020 }
5021
5022 void BelongToGeom::SetType (SMDSAbs_ElementType theType)
5023 {
5024   if ( myType != theType )
5025   {
5026     myType = theType;
5027     init();
5028   }
5029 }
5030
5031 SMDSAbs_ElementType BelongToGeom::GetType() const
5032 {
5033   return myType;
5034 }
5035
5036 TopoDS_Shape BelongToGeom::GetShape()
5037 {
5038   return myShape;
5039 }
5040
5041 const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const
5042 {
5043   return myMeshDS;
5044 }
5045
5046 void BelongToGeom::SetTolerance (double theTolerance)
5047 {
5048   myTolerance = theTolerance;
5049   init();
5050 }
5051
5052 double BelongToGeom::GetTolerance()
5053 {
5054   return myTolerance;
5055 }
5056
5057 /*
5058   Class       : LyingOnGeom
5059   Description : Predicate for verifying whether entiy lying or partially lying on
5060   specified geometrical support
5061 */
5062
5063 LyingOnGeom::LyingOnGeom()
5064   : myMeshDS(NULL),
5065     myType(SMDSAbs_NbElementTypes),
5066     myIsSubshape(false),
5067     myTolerance(Precision::Confusion())
5068 {}
5069
5070 Predicate* LyingOnGeom::clone() const
5071 {
5072   LyingOnGeom* cln = 0;
5073   if ( myElementsOnShapePtr )
5074     if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
5075     {
5076       cln = new LyingOnGeom( *this );
5077       cln->myElementsOnShapePtr.reset( eos );
5078     }
5079   return cln;
5080 }
5081
5082 void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh )
5083 {
5084   if ( myMeshDS != theMesh )
5085   {
5086     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
5087     init();
5088   }
5089   if ( myElementsOnShapePtr )
5090     myElementsOnShapePtr->SetMesh( myMeshDS );
5091 }
5092
5093 void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape )
5094 {
5095   if ( myShape != theShape )
5096   {
5097     myShape = theShape;
5098     init();
5099   }
5100 }
5101
5102 void LyingOnGeom::init()
5103 {
5104   if (!myMeshDS || myShape.IsNull()) return;
5105
5106   // is sub-shape of main shape?
5107   TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
5108   if (aMainShape.IsNull()) {
5109     myIsSubshape = false;
5110   }
5111   else {
5112     myIsSubshape = myMeshDS->IsGroupOfSubShapes( myShape );
5113   }
5114
5115   if (myIsSubshape)
5116   {
5117     TopTools_IndexedMapOfShape shapes;
5118     TopExp::MapShapes( myShape, shapes );
5119     mySubShapesIDs.Clear();
5120     for ( int i = 1; i <= shapes.Extent(); ++i )
5121     {
5122       int subID = myMeshDS->ShapeToIndex( shapes( i ));
5123       if ( subID > 0 )
5124         mySubShapesIDs.Add( subID );
5125     }
5126   }
5127   // else // to be always ready to check an element not bound to geometry
5128   {
5129     if ( !myElementsOnShapePtr )
5130       myElementsOnShapePtr.reset( new ElementsOnShape() );
5131     myElementsOnShapePtr->SetTolerance( myTolerance );
5132     myElementsOnShapePtr->SetAllNodes( false ); // lays on, while true means "belong"
5133     myElementsOnShapePtr->SetMesh( myMeshDS );
5134     myElementsOnShapePtr->SetShape( myShape, myType );
5135   }
5136 }
5137
5138 bool LyingOnGeom::IsSatisfy( long theId )
5139 {
5140   if ( myMeshDS == 0 || myShape.IsNull() )
5141     return false;
5142
5143   if (!myIsSubshape)
5144   {
5145     return myElementsOnShapePtr->IsSatisfy(theId);
5146   }
5147
5148   // Case of sub-mesh
5149
5150   const SMDS_MeshElement* elem =
5151     ( myType == SMDSAbs_Node ) ? myMeshDS->FindNode( theId ) : myMeshDS->FindElement( theId );
5152
5153   if ( mySubShapesIDs.Contains( elem->getshapeId() ))
5154     return true;
5155
5156   if (( elem->GetType() != SMDSAbs_Node ) &&
5157       ( myType == SMDSAbs_All || elem->GetType() == myType ))
5158   {
5159     SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator();
5160     while ( nodeItr->more() )
5161     {
5162       const SMDS_MeshElement* aNode = nodeItr->next();
5163       if ( mySubShapesIDs.Contains( aNode->getshapeId() ))
5164         return true;
5165     }
5166   }
5167
5168   return false;
5169 }
5170
5171 void LyingOnGeom::SetType( SMDSAbs_ElementType theType )
5172 {
5173   if ( myType != theType )
5174   {
5175     myType = theType;
5176     init();
5177   }
5178 }
5179
5180 SMDSAbs_ElementType LyingOnGeom::GetType() const
5181 {
5182   return myType;
5183 }
5184
5185 TopoDS_Shape LyingOnGeom::GetShape()
5186 {
5187   return myShape;
5188 }
5189
5190 const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const
5191 {
5192   return myMeshDS;
5193 }
5194
5195 void LyingOnGeom::SetTolerance (double theTolerance)
5196 {
5197   myTolerance = theTolerance;
5198   init();
5199 }
5200
5201 double LyingOnGeom::GetTolerance()
5202 {
5203   return myTolerance;
5204 }
5205
5206 TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0)
5207 {}
5208
5209 TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n), myElem(0)
5210 {}
5211
5212 TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t), myElem(0)
5213 {}
5214
5215 TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray), myElem(theSequenceOfXYZ.myElem)
5216 {}
5217
5218 template <class InputIterator>
5219 TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd), myElem(0)
5220 {}
5221
5222 TSequenceOfXYZ::~TSequenceOfXYZ()
5223 {}
5224
5225 TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ)
5226 {
5227   myArray = theSequenceOfXYZ.myArray;
5228   myElem  = theSequenceOfXYZ.myElem;
5229   return *this;
5230 }
5231
5232 gp_XYZ& TSequenceOfXYZ::operator()(size_type n)
5233 {
5234   return myArray[n-1];
5235 }
5236
5237 const gp_XYZ& TSequenceOfXYZ::operator()(size_type n) const
5238 {
5239   return myArray[n-1];
5240 }
5241
5242 void TSequenceOfXYZ::clear()
5243 {
5244   myArray.clear();
5245 }
5246
5247 void TSequenceOfXYZ::reserve(size_type n)
5248 {
5249   myArray.reserve(n);
5250 }
5251
5252 void TSequenceOfXYZ::push_back(const gp_XYZ& v)
5253 {
5254   myArray.push_back(v);
5255 }
5256
5257 TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const
5258 {
5259   return myArray.size();
5260 }
5261
5262 SMDSAbs_EntityType TSequenceOfXYZ::getElementEntity() const
5263 {
5264   return myElem ? myElem->GetEntityType() : SMDSEntity_Last;
5265 }
5266
5267 TMeshModifTracer::TMeshModifTracer():
5268   myMeshModifTime(0), myMesh(0)
5269 {
5270 }
5271 void TMeshModifTracer::SetMesh( const SMDS_Mesh* theMesh )
5272 {
5273   if ( theMesh != myMesh )
5274     myMeshModifTime = 0;
5275   myMesh = theMesh;
5276 }
5277 bool TMeshModifTracer::IsMeshModified()
5278 {
5279   bool modified = false;
5280   if ( myMesh )
5281   {
5282     modified = ( myMeshModifTime != myMesh->GetMTime() );
5283     myMeshModifTime = myMesh->GetMTime();
5284   }
5285   return modified;
5286 }