Salome HOME
2bf885a7a29a0d1500bc03e04f0818c4e2eda230
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
1 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3 // 
4 //  This library is free software; you can redistribute it and/or 
5 //  modify it under the terms of the GNU Lesser General Public 
6 //  License as published by the Free Software Foundation; either
7 //  version 2.1 of the License. 
8 // 
9 //  This library is distributed in the hope that it will be useful, 
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 //  Lesser General Public License for more details.
13 // 
14 //  You should have received a copy of the GNU Lesser General Public 
15 //  License along with this library; if not, write to the Free Software 
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17 // 
18 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
19
20 #include "SMESH_ControlsDef.hxx"
21
22 #include <set>
23
24 #include <BRep_Tool.hxx>
25 #include <gp_Ax3.hxx>
26 #include <gp_Cylinder.hxx>
27 #include <gp_Dir.hxx>
28 #include <gp_Pnt.hxx>
29 #include <gp_Pln.hxx>
30 #include <gp_Vec.hxx>
31 #include <gp_XYZ.hxx>
32 #include <Geom_Plane.hxx>
33 #include <Geom_CylindricalSurface.hxx>
34 #include <Precision.hxx>
35 #include <TColgp_Array1OfXYZ.hxx>
36 #include <TColStd_MapOfInteger.hxx>
37 #include <TColStd_SequenceOfAsciiString.hxx>
38 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
39 #include <TopAbs.hxx>
40 #include <TopoDS.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Shape.hxx>
43
44 #include "SMDS_Mesh.hxx"
45 #include "SMDS_Iterator.hxx"
46 #include "SMDS_MeshElement.hxx"
47 #include "SMDS_MeshNode.hxx"
48
49
50 /*
51                             AUXILIARY METHODS 
52 */
53
54 namespace{
55   inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
56   {
57     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
58     
59     return v1.Magnitude() < gp::Resolution() ||
60       v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
61   }
62
63   inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
64   {
65     gp_Vec aVec1( P2 - P1 );
66     gp_Vec aVec2( P3 - P1 );
67     return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
68   }
69
70   inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
71   {
72     return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
73   }
74
75
76
77   inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
78   {
79     double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
80     return aDist;
81   }
82
83   int getNbMultiConnection( SMDS_Mesh* theMesh, const int theId )
84   {
85     if ( theMesh == 0 )
86       return 0;
87     
88     const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
89     if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge || anEdge->NbNodes() != 2 )
90       return 0;
91     
92     TColStd_MapOfInteger aMap;
93     
94     int aResult = 0;
95     SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator();
96     if ( anIter != 0 ) {
97       while( anIter->more() ) {
98         const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
99         if ( aNode == 0 )
100           return 0;
101         SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
102         while( anElemIter->more() ) {
103           const SMDS_MeshElement* anElem = anElemIter->next();
104           if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
105             int anId = anElem->GetID();
106             
107             if ( anIter->more() )              // i.e. first node
108               aMap.Add( anId );
109             else if ( aMap.Contains( anId ) )
110               aResult++;
111           }
112         }
113       }
114     }
115     
116     return aResult;
117   }
118
119 }
120
121
122
123 using namespace SMESH::Controls;
124
125 /*
126                                 FUNCTORS
127 */
128
129 /*
130   Class       : NumericalFunctor
131   Description : Base class for numerical functors
132 */
133 NumericalFunctor::NumericalFunctor():
134   myMesh(NULL)
135 {
136   myPrecision = -1;
137 }
138
139 void NumericalFunctor::SetMesh( SMDS_Mesh* theMesh )
140 {
141   myMesh = theMesh;
142 }
143
144 bool NumericalFunctor::GetPoints(const int theId,
145                                  TSequenceOfXYZ& theRes ) const
146 {
147   theRes.clear();
148
149   if ( myMesh == 0 )
150     return false;
151
152   return GetPoints( myMesh->FindElement( theId ), theRes );
153 }
154
155 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
156                                  TSequenceOfXYZ& theRes )
157 {
158   theRes.clear();
159
160   if ( anElem == 0)
161     return false;
162
163   // Get nodes of the element
164   SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
165   if ( anIter != 0 )
166   {
167     while( anIter->more() )
168     {
169       const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
170       if ( aNode != 0 ){
171         theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
172       }
173     }
174   }
175
176   return true;
177 }
178
179 long  NumericalFunctor::GetPrecision() const
180 {
181   return myPrecision;
182 }
183
184 void  NumericalFunctor::SetPrecision( const long thePrecision )
185 {
186   myPrecision = thePrecision;
187 }
188
189 double NumericalFunctor::GetValue( long theId )
190 {
191   TSequenceOfXYZ P;
192   if ( GetPoints( theId, P ))
193   {
194     double aVal = GetValue( P );
195     if ( myPrecision >= 0 )
196     {
197       double prec = pow( 10., (double)( myPrecision ) );
198       aVal = floor( aVal * prec + 0.5 ) / prec;
199     }
200     return aVal;
201   }
202
203   return 0.;
204 }
205
206 /*
207   Class       : MinimumAngle
208   Description : Functor for calculation of minimum angle
209 */
210
211 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
212 {
213   double aMin;
214
215   if ( P.size() == 3 )
216   {
217     double A0 = getAngle( P( 3 ), P( 1 ), P( 2 ) );
218     double A1 = getAngle( P( 1 ), P( 2 ), P( 3 ) );
219     double A2 = getAngle( P( 2 ), P( 3 ), P( 1 ) );
220
221     aMin = Min( A0, Min( A1, A2 ) );
222   }
223   else if ( P.size() == 4 )
224   {
225     double A0 = getAngle( P( 4 ), P( 1 ), P( 2 ) );
226     double A1 = getAngle( P( 1 ), P( 2 ), P( 3 ) );
227     double A2 = getAngle( P( 2 ), P( 3 ), P( 4 ) );
228     double A3 = getAngle( P( 3 ), P( 4 ), P( 1 ) );
229     
230     aMin = Min( Min( A0, A1 ), Min( A2, A3 ) );
231   }
232   else
233     return 0.;
234   
235   return aMin * 180 / PI;
236 }
237
238 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
239 {
240   const double aBestAngle = PI / nbNodes;
241   return ( fabs( aBestAngle - Value ));
242 }
243
244 SMDSAbs_ElementType MinimumAngle::GetType() const
245 {
246   return SMDSAbs_Face;
247 }
248
249
250 /*
251   Class       : AspectRatio
252   Description : Functor for calculating aspect ratio
253 */
254 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
255 {
256   int nbNodes = P.size();
257
258   if ( nbNodes != 3 && nbNodes != 4 )
259     return 0;
260
261   // Compute lengths of the sides
262
263   double aLen[ nbNodes ];
264   for ( int i = 0; i < nbNodes - 1; i++ )
265     aLen[ i ] = getDistance( P( i + 1 ), P( i + 2 ) );
266   aLen[ nbNodes - 1 ] = getDistance( P( 1 ), P( nbNodes ) );
267
268   // Compute aspect ratio
269
270   if ( nbNodes == 3 ) 
271   {
272     double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) );
273     if ( anArea <= Precision::Confusion() )
274       return 0.;
275     double aMaxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
276     static double aCoef = sqrt( 3. ) / 4;
277
278     return aCoef * aMaxLen * aMaxLen / anArea;
279   }
280   else
281   {
282     double aMinLen = Min( Min( aLen[ 0 ], aLen[ 1 ] ), Min( aLen[ 2 ], aLen[ 3 ] ) );
283     if ( aMinLen <= Precision::Confusion() )
284       return 0.;
285     double aMaxLen = Max( Max( aLen[ 0 ], aLen[ 1 ] ), Max( aLen[ 2 ], aLen[ 3 ] ) );
286     
287     return aMaxLen / aMinLen;
288   }
289 }
290
291 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
292 {
293   // the aspect ratio is in the range [1.0,infinity]
294   // 1.0 = good
295   // infinity = bad
296   return Value / 1000.;
297 }
298
299 SMDSAbs_ElementType AspectRatio::GetType() const
300 {
301   return SMDSAbs_Face;
302 }
303
304
305 /*
306   Class       : AspectRatio3D
307   Description : Functor for calculating aspect ratio
308 */
309 namespace{
310
311   inline double getHalfPerimeter(double theTria[3]){
312     return (theTria[0] + theTria[1] + theTria[2])/2.0;
313   }
314
315   inline double getArea(double theHalfPerim, double theTria[3]){
316     return sqrt(theHalfPerim*
317                 (theHalfPerim-theTria[0])*
318                 (theHalfPerim-theTria[1])*
319                 (theHalfPerim-theTria[2]));
320   }
321
322   inline double getVolume(double theLen[6]){
323     double a2 = theLen[0]*theLen[0];
324     double b2 = theLen[1]*theLen[1];
325     double c2 = theLen[2]*theLen[2];
326     double d2 = theLen[3]*theLen[3];
327     double e2 = theLen[4]*theLen[4];
328     double f2 = theLen[5]*theLen[5];
329     double P = 4.0*a2*b2*d2;
330     double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
331     double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
332     return sqrt(P-Q+R)/12.0;
333   }
334
335   inline double getVolume2(double theLen[6]){
336     double a2 = theLen[0]*theLen[0];
337     double b2 = theLen[1]*theLen[1];
338     double c2 = theLen[2]*theLen[2];
339     double d2 = theLen[3]*theLen[3];
340     double e2 = theLen[4]*theLen[4];
341     double f2 = theLen[5]*theLen[5];
342
343     double P = a2*e2*(b2+c2+d2+f2-a2-e2);
344     double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
345     double R = c2*d2*(a2+b2+e2+f2-c2-d2);
346     double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
347     
348     return sqrt(P+Q+R-S)/12.0;
349   }
350
351   inline double getVolume(const TSequenceOfXYZ& P){
352     gp_Vec aVec1( P( 2 ) - P( 1 ) );
353     gp_Vec aVec2( P( 3 ) - P( 1 ) );
354     gp_Vec aVec3( P( 4 ) - P( 1 ) );
355     gp_Vec anAreaVec( aVec1 ^ aVec2 );
356     return abs(aVec3 * anAreaVec) / 6.0;
357   }
358
359   inline double getMaxHeight(double theLen[6])
360   {
361     double aHeight = max(theLen[0],theLen[1]);
362     aHeight = max(aHeight,theLen[2]);
363     aHeight = max(aHeight,theLen[3]);
364     aHeight = max(aHeight,theLen[4]);
365     aHeight = max(aHeight,theLen[5]);
366     return aHeight;
367   }
368
369 }
370
371 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
372 {
373   double aQuality = 0.0;
374   int nbNodes = P.size();
375   switch(nbNodes){
376   case 4:{
377     double aLen[6] = {
378       getDistance(P( 1 ),P( 2 )), // a
379       getDistance(P( 2 ),P( 3 )), // b
380       getDistance(P( 3 ),P( 1 )), // c
381       getDistance(P( 2 ),P( 4 )), // d
382       getDistance(P( 3 ),P( 4 )), // e
383       getDistance(P( 1 ),P( 4 ))  // f
384     };
385     double aTria[4][3] = {
386       {aLen[0],aLen[1],aLen[2]}, // abc
387       {aLen[0],aLen[3],aLen[5]}, // adf
388       {aLen[1],aLen[3],aLen[4]}, // bde
389       {aLen[2],aLen[4],aLen[5]}  // cef
390     };
391     double aSumArea = 0.0;
392     double aHalfPerimeter = getHalfPerimeter(aTria[0]);
393     double anArea = getArea(aHalfPerimeter,aTria[0]);
394     aSumArea += anArea;
395     aHalfPerimeter = getHalfPerimeter(aTria[1]);
396     anArea = getArea(aHalfPerimeter,aTria[1]);
397     aSumArea += anArea;
398     aHalfPerimeter = getHalfPerimeter(aTria[2]);
399     anArea = getArea(aHalfPerimeter,aTria[2]);
400     aSumArea += anArea;
401     aHalfPerimeter = getHalfPerimeter(aTria[3]);
402     anArea = getArea(aHalfPerimeter,aTria[3]);
403     aSumArea += anArea;
404     double aVolume = getVolume(P);
405     //double aVolume = getVolume(aLen);
406     double aHeight = getMaxHeight(aLen);
407     static double aCoeff = sqrt(6.0)/36.0;
408     aQuality = aCoeff*aHeight*aSumArea/aVolume;
409     break;
410   }
411   case 5:{
412     {
413       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
414       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
415     }
416     {
417       gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
418       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
419     }
420     {
421       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
422       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
423     }
424     {
425       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
426       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
427     }
428     break;
429   }
430   case 6:{
431     {
432       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
433       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
434     }
435     {
436       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
437       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
438     }
439     {
440       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
441       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
442     }
443     {
444       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
445       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
446     }
447     {
448       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
449       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
450     }
451     {
452       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
453       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
454     }
455     break;
456   }
457   case 8:{
458     {
459       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
460       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
461     }
462     {
463       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
464       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
465     }
466     {
467       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
468       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
469     }
470     {
471       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
472       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
473     }
474     {
475       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
476       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
477     }
478     {
479       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
480       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
481     }
482     {
483       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
484       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
485     }
486     {
487       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
488       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
489     }
490     {
491       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
492       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
493     }
494     {
495       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
496       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
497     }
498     {
499       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
500       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
501     }
502     {
503       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
504       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
505     }
506     {
507       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
508       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
509     }
510     {
511       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
512       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
513     }
514     {
515       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
516       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
517     }
518     {
519       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
520       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
521     }
522     {
523       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
524       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
525     }
526     {
527       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
528       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
529     }
530     {
531       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
532       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
533     }
534     {
535       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
536       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
537     }
538     {
539       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
540       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
541     }
542     {
543       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
544       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
545     }
546     {
547       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
548       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
549     }
550     {
551       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
552       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
553     }
554     {
555       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
556       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
557     }
558     {
559       gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
560       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
561     }
562     {
563       gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
564       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
565     }
566     {
567       gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
568       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
569     }
570     {
571       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
572       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
573     }
574     {
575       gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
576       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
577     }
578     {
579       gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
580       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
581     }
582     {
583       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
584       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
585     }
586     {
587       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
588       aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
589     }
590     break;
591   }
592   }
593   return aQuality;
594 }
595
596 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
597 {
598   // the aspect ratio is in the range [1.0,infinity]
599   // 1.0 = good
600   // infinity = bad
601   return Value / 1000.;
602 }
603
604 SMDSAbs_ElementType AspectRatio3D::GetType() const
605 {
606   return SMDSAbs_Volume;
607 }
608
609
610 /*
611   Class       : Warping
612   Description : Functor for calculating warping
613 */
614 double Warping::GetValue( const TSequenceOfXYZ& P )
615 {
616   if ( P.size() != 4 )
617     return 0;
618
619   gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4;
620
621   double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G );
622   double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G );
623   double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G );
624   double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G );
625
626   return Max( Max( A1, A2 ), Max( A3, A4 ) );
627 }
628
629 double Warping::ComputeA( const gp_XYZ& thePnt1,
630                           const gp_XYZ& thePnt2,
631                           const gp_XYZ& thePnt3,
632                           const gp_XYZ& theG ) const
633 {
634   double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
635   double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
636   double L = Min( aLen1, aLen2 ) * 0.5;
637   if ( L < Precision::Confusion())
638     return 0.;
639
640   gp_XYZ GI = ( thePnt2 - thePnt1 ) / 2. - theG;
641   gp_XYZ GJ = ( thePnt3 - thePnt2 ) / 2. - theG;
642   gp_XYZ N  = GI.Crossed( GJ );
643
644   if ( N.Modulus() < gp::Resolution() )
645     return PI / 2;
646
647   N.Normalize();
648
649   double H = ( thePnt2 - theG ).Dot( N );
650   return asin( fabs( H / L ) ) * 180 / PI;
651 }
652
653 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
654 {
655   // the warp is in the range [0.0,PI/2]
656   // 0.0 = good (no warp)
657   // PI/2 = bad  (face pliee)
658   return Value;
659 }
660
661 SMDSAbs_ElementType Warping::GetType() const
662 {
663   return SMDSAbs_Face;
664 }
665
666
667 /*
668   Class       : Taper
669   Description : Functor for calculating taper
670 */
671 double Taper::GetValue( const TSequenceOfXYZ& P )
672 {
673   if ( P.size() != 4 )
674     return 0;
675
676   // Compute taper
677   double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ) / 2;
678   double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ) / 2;
679   double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ) / 2;
680   double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ) / 2;
681
682   double JA = 0.25 * ( J1 + J2 + J3 + J4 );
683   if ( JA <= Precision::Confusion() )
684     return 0.;
685
686   double T1 = fabs( ( J1 - JA ) / JA );
687   double T2 = fabs( ( J2 - JA ) / JA );
688   double T3 = fabs( ( J3 - JA ) / JA );
689   double T4 = fabs( ( J4 - JA ) / JA );
690
691   return Max( Max( T1, T2 ), Max( T3, T4 ) );
692 }
693
694 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
695 {
696   // the taper is in the range [0.0,1.0]
697   // 0.0  = good (no taper)
698   // 1.0 = bad  (les cotes opposes sont allignes)
699   return Value;
700 }
701
702 SMDSAbs_ElementType Taper::GetType() const
703 {
704   return SMDSAbs_Face;
705 }
706
707
708 /*
709   Class       : Skew
710   Description : Functor for calculating skew in degrees
711 */
712 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
713 {
714   gp_XYZ p12 = ( p2 + p1 ) / 2;
715   gp_XYZ p23 = ( p3 + p2 ) / 2;
716   gp_XYZ p31 = ( p3 + p1 ) / 2;
717
718   gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
719
720   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
721 }
722
723 double Skew::GetValue( const TSequenceOfXYZ& P )
724 {
725   if ( P.size() != 3 && P.size() != 4 )
726     return 0;
727
728   // Compute skew
729   static double PI2 = PI / 2;
730   if ( P.size() == 3 )
731   {
732     double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
733     double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
734     double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
735
736     return Max( A0, Max( A1, A2 ) ) * 180 / PI;
737   }
738   else 
739   {
740     gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2;
741     gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2;
742     gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2;
743     gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2;
744
745     gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
746     double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
747       ? 0 : fabs( PI2 - v1.Angle( v2 ) );
748
749     return A * 180 / PI;
750   }
751 }
752
753 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
754 {
755   // the skew is in the range [0.0,PI/2].
756   // 0.0 = good
757   // PI/2 = bad
758   return Value;
759 }
760
761 SMDSAbs_ElementType Skew::GetType() const
762 {
763   return SMDSAbs_Face;
764 }
765
766
767 /*
768   Class       : Area
769   Description : Functor for calculating area
770 */
771 double Area::GetValue( const TSequenceOfXYZ& P )
772 {
773   if ( P.size() == 3 )
774     return getArea( P( 1 ), P( 2 ), P( 3 ) );
775   else if ( P.size() == 4 )
776     return getArea( P( 1 ), P( 2 ), P( 3 ) ) + getArea( P( 1 ), P( 3 ), P( 4 ) );
777   else
778     return 0;
779 }
780
781 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
782 {
783   return Value;
784 }
785
786 SMDSAbs_ElementType Area::GetType() const
787 {
788   return SMDSAbs_Face;
789 }
790
791
792 /*
793   Class       : Length
794   Description : Functor for calculating length off edge
795 */
796 double Length::GetValue( const TSequenceOfXYZ& P )
797 {
798   return ( P.size() == 2 ? getDistance( P( 1 ), P( 2 ) ) : 0 );
799 }
800
801 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
802 {
803   return Value;
804 }
805
806 SMDSAbs_ElementType Length::GetType() const
807 {
808   return SMDSAbs_Edge;
809 }
810
811 /*
812   Class       : Length2D
813   Description : Functor for calculating length of edge
814 */
815
816 double Length2D::GetValue( long theElementId)
817 {
818   TSequenceOfXYZ P;
819
820   if (GetPoints(theElementId,P)){
821     
822     double  aVal;// = GetValue( P );
823     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
824     SMDSAbs_ElementType aType = aElem->GetType();
825     
826     int len = P.size();
827     
828     switch (aType){
829     case SMDSAbs_All:
830     case SMDSAbs_Node: 
831     case SMDSAbs_Edge:
832       if (len == 2){
833         aVal = getDistance( P( 1 ), P( 2 ) );
834         break;
835       }
836     case SMDSAbs_Face:
837       if (len == 3){ // triangles
838         double L1 = getDistance(P( 1 ),P( 2 ));
839         double L2 = getDistance(P( 2 ),P( 3 ));
840         double L3 = getDistance(P( 3 ),P( 1 ));
841         aVal = Max(L1,Max(L2,L3));
842         break;
843       }
844       else if (len == 4){ // quadrangles
845         double L1 = getDistance(P( 1 ),P( 2 ));
846         double L2 = getDistance(P( 2 ),P( 3 ));
847         double L3 = getDistance(P( 3 ),P( 4 ));
848         double L4 = getDistance(P( 4 ),P( 1 ));
849         aVal = Max(Max(L1,L2),Max(L3,L4));
850         break;
851       }
852     case SMDSAbs_Volume:
853       if (len == 4){ // tetraidrs
854         double L1 = getDistance(P( 1 ),P( 2 ));
855         double L2 = getDistance(P( 2 ),P( 3 ));
856         double L3 = getDistance(P( 3 ),P( 1 ));
857         double L4 = getDistance(P( 1 ),P( 4 ));
858         double L5 = getDistance(P( 2 ),P( 4 ));
859         double L6 = getDistance(P( 3 ),P( 4 ));
860         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
861         break;
862       } 
863       else if (len == 5){ // piramids
864         double L1 = getDistance(P( 1 ),P( 2 ));
865         double L2 = getDistance(P( 2 ),P( 3 ));
866         double L3 = getDistance(P( 3 ),P( 1 ));
867         double L4 = getDistance(P( 4 ),P( 1 ));
868         double L5 = getDistance(P( 1 ),P( 5 ));
869         double L6 = getDistance(P( 2 ),P( 5 ));
870         double L7 = getDistance(P( 3 ),P( 5 ));
871         double L8 = getDistance(P( 4 ),P( 5 ));
872       
873         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
874         aVal = Max(aVal,Max(L7,L8));
875         break;
876       }
877       else if (len == 6){ // pentaidres
878         double L1 = getDistance(P( 1 ),P( 2 ));
879         double L2 = getDistance(P( 2 ),P( 3 ));
880         double L3 = getDistance(P( 3 ),P( 1 ));
881         double L4 = getDistance(P( 4 ),P( 5 ));
882         double L5 = getDistance(P( 5 ),P( 6 ));
883         double L6 = getDistance(P( 6 ),P( 4 ));
884         double L7 = getDistance(P( 1 ),P( 4 ));
885         double L8 = getDistance(P( 2 ),P( 5 ));
886         double L9 = getDistance(P( 3 ),P( 6 ));
887       
888         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
889         aVal = Max(aVal,Max(Max(L7,L8),L9));
890         break;
891       }
892       else if (len == 8){ // hexaider
893         double L1 = getDistance(P( 1 ),P( 2 ));
894         double L2 = getDistance(P( 2 ),P( 3 ));
895         double L3 = getDistance(P( 3 ),P( 4 ));
896         double L4 = getDistance(P( 4 ),P( 1 ));
897         double L5 = getDistance(P( 5 ),P( 6 ));
898         double L6 = getDistance(P( 6 ),P( 7 ));
899         double L7 = getDistance(P( 7 ),P( 8 ));
900         double L8 = getDistance(P( 8 ),P( 5 ));
901         double L9 = getDistance(P( 1 ),P( 5 ));
902         double L10= getDistance(P( 2 ),P( 6 ));
903         double L11= getDistance(P( 3 ),P( 7 ));
904         double L12= getDistance(P( 4 ),P( 8 ));
905       
906         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
907         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
908         aVal = Max(aVal,Max(L11,L12));
909         break;
910         
911       }
912       
913     default: aVal=-1; 
914     }
915     
916     if (aVal <0){
917       return 0.;
918     }
919
920     if ( myPrecision >= 0 )
921     {
922       double prec = pow( 10., (double)( myPrecision ) );
923       aVal = floor( aVal * prec + 0.5 ) / prec;
924     }
925     
926     return aVal;
927
928   }
929   return 0.;
930 }
931
932 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
933 {
934   return Value;
935 }
936
937 SMDSAbs_ElementType Length2D::GetType() const
938 {
939   return SMDSAbs_Face;
940 }
941
942 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
943   myLength(theLength)
944 {
945   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
946   if(thePntId1 > thePntId2){
947     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
948   }
949 }
950
951 bool Length2D::Value::operator<(const Length2D::Value& x) const{
952   if(myPntId[0] < x.myPntId[0]) return true;
953   if(myPntId[0] == x.myPntId[0])
954     if(myPntId[1] < x.myPntId[1]) return true;
955   return false;
956 }
957
958 void Length2D::GetValues(TValues& theValues){
959   TValues aValues;
960   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
961   for(; anIter->more(); ){
962     const SMDS_MeshFace* anElem = anIter->next();
963     SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
964     long aNodeId[2];
965     gp_Pnt P[3];
966     
967     double aLength;
968     const SMDS_MeshElement* aNode;
969     if(aNodesIter->more()){
970       aNode = aNodesIter->next();
971       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
972       P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
973       aNodeId[0] = aNodeId[1] = aNode->GetID();
974       aLength = 0;
975     }   
976     for(; aNodesIter->more(); ){
977       aNode = aNodesIter->next();
978       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
979       long anId = aNode->GetID();
980       
981       P[2] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
982
983       aLength = P[1].Distance(P[2]);
984       
985       Value aValue(aLength,aNodeId[1],anId);
986       aNodeId[1] = anId;
987       P[1] = P[2];
988       theValues.insert(aValue);
989     }
990     
991     aLength = P[0].Distance(P[1]);
992     
993     Value aValue(aLength,aNodeId[0],aNodeId[1]);
994     theValues.insert(aValue);
995   }
996 }
997
998 /*
999   Class       : MultiConnection
1000   Description : Functor for calculating number of faces conneted to the edge
1001 */
1002 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
1003 {
1004   return 0;
1005 }
1006 double MultiConnection::GetValue( long theId )
1007 {
1008   return getNbMultiConnection( myMesh, theId );
1009 }
1010
1011 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
1012 {
1013   return Value;
1014 }
1015
1016 SMDSAbs_ElementType MultiConnection::GetType() const
1017 {
1018   return SMDSAbs_Edge;
1019 }
1020
1021 /*
1022   Class       : MultiConnection2D
1023   Description : Functor for calculating number of faces conneted to the edge
1024 */
1025 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
1026 {
1027   return 0;
1028 }
1029
1030 double MultiConnection2D::GetValue( long theElementId )
1031 {
1032   TSequenceOfXYZ P;
1033   int aResult = 0;
1034   
1035   if (GetPoints(theElementId,P)){
1036     double  aVal;
1037     const SMDS_MeshElement* anFaceElem = myMesh->FindElement( theElementId );
1038     SMDSAbs_ElementType aType = anFaceElem->GetType();
1039     
1040     int len = P.size();
1041     
1042     TColStd_MapOfInteger aMap;
1043     int aResult = 0;
1044     
1045     switch (aType){
1046     case SMDSAbs_All:
1047     case SMDSAbs_Node: 
1048     case SMDSAbs_Edge:
1049     case SMDSAbs_Face:
1050       if (len == 3){ // triangles
1051         int Nb[3] = {0,0,0};
1052
1053         int i=0;
1054         SMDS_ElemIteratorPtr anIter = anFaceElem->nodesIterator();
1055         if ( anIter != 0 ) {
1056           while( anIter->more() ) {
1057             const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
1058             if ( aNode == 0 ){
1059               break;
1060             }
1061             SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
1062             while( anElemIter->more() ) {
1063               const SMDS_MeshElement* anElem = anElemIter->next();
1064               if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
1065                 int anId = anElem->GetID();
1066
1067                 if ( anIter->more() )              // i.e. first node
1068                   aMap.Add( anId );
1069                 else if ( aMap.Contains( anId ) ){
1070                   Nb[i]++;
1071                 }
1072               }
1073               else if ( anElem != 0 && anElem->GetType() == SMDSAbs_Edge ) i++;
1074             }
1075           }
1076         }
1077         
1078         aResult = Max(Max(Nb[0],Nb[1]),Nb[2]);
1079       }
1080       break;
1081     case SMDSAbs_Volume:
1082     default: aResult=0;
1083     }
1084     
1085   }
1086   return aResult;//getNbMultiConnection( myMesh, theId );
1087 }
1088
1089 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1090 {
1091   return Value;
1092 }
1093
1094 SMDSAbs_ElementType MultiConnection2D::GetType() const
1095 {
1096   return SMDSAbs_Face;
1097 }
1098
1099 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
1100 {
1101   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1102   if(thePntId1 > thePntId2){
1103     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1104   }
1105 }
1106
1107 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const{
1108   if(myPntId[0] < x.myPntId[0]) return true;
1109   if(myPntId[0] == x.myPntId[0])
1110     if(myPntId[1] < x.myPntId[1]) return true;
1111   return false;
1112 }
1113
1114 void MultiConnection2D::GetValues(MValues& theValues){
1115   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1116   for(; anIter->more(); ){
1117     const SMDS_MeshFace* anElem = anIter->next();
1118     long anElemId = anElem->GetID();
1119     SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
1120     long aNodeId[3];
1121
1122     //int aNbConnects=0;
1123     const SMDS_MeshNode* aNode0;
1124     const SMDS_MeshNode* aNode1;
1125     const SMDS_MeshNode* aNode2;
1126     if(aNodesIter->more()){
1127       aNode0 = (SMDS_MeshNode*) aNodesIter->next();
1128       aNode1 = aNode0;
1129       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode1;
1130       aNodeId[0] = aNodeId[1] = aNodes->GetID();
1131     }
1132     for(; aNodesIter->more(); ){
1133       aNode2 = (SMDS_MeshNode*) aNodesIter->next();
1134       long anId = aNode2->GetID();
1135       aNodeId[2] = anId;
1136       
1137       Value aValue(aNodeId[1],aNodeId[2]);
1138       MValues::iterator aItr = theValues.find(aValue);
1139       if (aItr != theValues.end()){
1140         aItr->second += 1;
1141         //aNbConnects = nb;
1142       } else {
1143         theValues[aValue] = 1;
1144         //aNbConnects = 1;
1145       }
1146       //cout << "NodeIds: "<<aNodeId[1]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1147       aNodeId[1] = aNodeId[2];
1148       aNode1 = aNode2;
1149     }
1150     Value aValue(aNodeId[0],aNodeId[2]);
1151     MValues::iterator aItr = theValues.find(aValue);
1152     if (aItr != theValues.end()){
1153       aItr->second += 1;
1154       //aNbConnects = nb;
1155     } else {
1156       theValues[aValue] = 1;
1157       //aNbConnects = 1;
1158     }
1159     //cout << "NodeIds: "<<aNodeId[0]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1160   }
1161
1162 }
1163
1164 /*
1165                             PREDICATES
1166 */
1167
1168 /*
1169   Class       : FreeBorders
1170   Description : Predicate for free borders
1171 */
1172
1173 FreeBorders::FreeBorders()
1174 {
1175   myMesh = 0;
1176 }
1177
1178 void FreeBorders::SetMesh( SMDS_Mesh* theMesh )
1179 {
1180   myMesh = theMesh;
1181 }
1182
1183 bool FreeBorders::IsSatisfy( long theId )
1184 {
1185   return getNbMultiConnection( myMesh, theId ) == 1;
1186 }
1187
1188 SMDSAbs_ElementType FreeBorders::GetType() const
1189 {
1190   return SMDSAbs_Edge;
1191 }
1192
1193
1194 /*
1195   Class       : FreeEdges
1196   Description : Predicate for free Edges
1197 */
1198 FreeEdges::FreeEdges()
1199 {
1200   myMesh = 0;
1201 }
1202
1203 void FreeEdges::SetMesh( SMDS_Mesh* theMesh )
1204 {
1205   myMesh = theMesh;
1206 }
1207
1208 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
1209 {
1210   TColStd_MapOfInteger aMap;
1211   for ( int i = 0; i < 2; i++ )
1212   {
1213     SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator();
1214     while( anElemIter->more() )
1215     {
1216       const SMDS_MeshElement* anElem = anElemIter->next();
1217       if ( anElem != 0 && anElem->GetType() == SMDSAbs_Face )
1218       {
1219         int anId = anElem->GetID();
1220
1221         if ( i == 0 ) 
1222           aMap.Add( anId );
1223         else if ( aMap.Contains( anId ) && anId != theFaceId )
1224           return false;
1225       }
1226     }
1227   }
1228   return true;
1229 }
1230
1231 bool FreeEdges::IsSatisfy( long theId )
1232 {
1233   if ( myMesh == 0 )
1234     return false;
1235
1236   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
1237   if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
1238     return false;
1239
1240   int nbNodes = aFace->NbNodes();
1241   const SMDS_MeshNode* aNodes[ nbNodes ];
1242   int i = 0;
1243   SMDS_ElemIteratorPtr anIter = aFace->nodesIterator();
1244   if ( anIter != 0 )
1245   {
1246     while( anIter->more() )
1247     {
1248       const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
1249       if ( aNode == 0 )
1250         return false;
1251       aNodes[ i++ ] = aNode;
1252     }
1253   }
1254
1255   for ( int i = 0; i < nbNodes - 1; i++ )
1256     if ( IsFreeEdge( &aNodes[ i ], theId ) )
1257       return true;
1258
1259   aNodes[ 1 ] = aNodes[ nbNodes - 1 ];
1260   
1261   return IsFreeEdge( &aNodes[ 0 ], theId );
1262
1263 }
1264
1265 SMDSAbs_ElementType FreeEdges::GetType() const
1266 {
1267   return SMDSAbs_Face;
1268 }
1269
1270 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
1271   myElemId(theElemId)
1272 {
1273   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
1274   if(thePntId1 > thePntId2){
1275     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
1276   }
1277 }
1278
1279 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
1280   if(myPntId[0] < x.myPntId[0]) return true;
1281   if(myPntId[0] == x.myPntId[0])
1282     if(myPntId[1] < x.myPntId[1]) return true;
1283   return false;
1284 }
1285
1286 inline void UpdateBorders(const FreeEdges::Border& theBorder,
1287                           FreeEdges::TBorders& theRegistry, 
1288                           FreeEdges::TBorders& theContainer)
1289 {
1290   if(theRegistry.find(theBorder) == theRegistry.end()){
1291     theRegistry.insert(theBorder);
1292     theContainer.insert(theBorder);
1293   }else{
1294     theContainer.erase(theBorder);
1295   }
1296 }
1297
1298 void FreeEdges::GetBoreders(TBorders& theBorders)
1299 {
1300   TBorders aRegistry;
1301   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
1302   for(; anIter->more(); ){
1303     const SMDS_MeshFace* anElem = anIter->next();
1304     long anElemId = anElem->GetID();
1305     SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
1306     long aNodeId[2];
1307     const SMDS_MeshElement* aNode;
1308     if(aNodesIter->more()){
1309       aNode = aNodesIter->next();
1310       aNodeId[0] = aNodeId[1] = aNode->GetID();
1311     }   
1312     for(; aNodesIter->more(); ){
1313       aNode = aNodesIter->next();
1314       long anId = aNode->GetID();
1315       Border aBorder(anElemId,aNodeId[1],anId);
1316       aNodeId[1] = anId;
1317       //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
1318       UpdateBorders(aBorder,aRegistry,theBorders);
1319     }
1320     Border aBorder(anElemId,aNodeId[0],aNodeId[1]);
1321     //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
1322     UpdateBorders(aBorder,aRegistry,theBorders);
1323   }
1324   //std::cout<<"theBorders.size() = "<<theBorders.size()<<endl;
1325 }
1326
1327 /*
1328   Class       : RangeOfIds
1329   Description : Predicate for Range of Ids.
1330                 Range may be specified with two ways.
1331                 1. Using AddToRange method
1332                 2. With SetRangeStr method. Parameter of this method is a string
1333                    like as "1,2,3,50-60,63,67,70-"
1334 */
1335
1336 //=======================================================================
1337 // name    : RangeOfIds
1338 // Purpose : Constructor
1339 //=======================================================================
1340 RangeOfIds::RangeOfIds()
1341 {
1342   myMesh = 0;
1343   myType = SMDSAbs_All;
1344 }
1345
1346 //=======================================================================
1347 // name    : SetMesh
1348 // Purpose : Set mesh 
1349 //=======================================================================
1350 void RangeOfIds::SetMesh( SMDS_Mesh* theMesh )
1351 {
1352   myMesh = theMesh;
1353 }
1354
1355 //=======================================================================
1356 // name    : AddToRange
1357 // Purpose : Add ID to the range
1358 //=======================================================================
1359 bool RangeOfIds::AddToRange( long theEntityId )
1360 {
1361   myIds.Add( theEntityId );
1362   return true;
1363 }
1364
1365 //=======================================================================
1366 // name    : GetRangeStr
1367 // Purpose : Get range as a string.
1368 //           Example: "1,2,3,50-60,63,67,70-"
1369 //=======================================================================
1370 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
1371 {
1372   theResStr.Clear();
1373
1374   TColStd_SequenceOfInteger     anIntSeq;
1375   TColStd_SequenceOfAsciiString aStrSeq;
1376
1377   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
1378   for ( ; anIter.More(); anIter.Next() )
1379   {
1380     int anId = anIter.Key();
1381     TCollection_AsciiString aStr( anId );
1382     anIntSeq.Append( anId );
1383     aStrSeq.Append( aStr );
1384   }
1385
1386   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1387   {
1388     int aMinId = myMin( i );
1389     int aMaxId = myMax( i );
1390
1391     TCollection_AsciiString aStr;
1392     if ( aMinId != IntegerFirst() )
1393       aStr += aMinId;
1394       
1395     aStr += "-";
1396       
1397     if ( aMaxId != IntegerLast() )
1398       aStr += aMaxId;
1399
1400     // find position of the string in result sequence and insert string in it
1401     if ( anIntSeq.Length() == 0 )
1402     {
1403       anIntSeq.Append( aMinId );
1404       aStrSeq.Append( aStr );
1405     }
1406     else
1407     {
1408       if ( aMinId < anIntSeq.First() )
1409       {
1410         anIntSeq.Prepend( aMinId );
1411         aStrSeq.Prepend( aStr );
1412       }
1413       else if ( aMinId > anIntSeq.Last() )
1414       {
1415         anIntSeq.Append( aMinId );
1416         aStrSeq.Append( aStr );
1417       }
1418       else
1419         for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
1420           if ( aMinId < anIntSeq( j ) )
1421           {
1422             anIntSeq.InsertBefore( j, aMinId );
1423             aStrSeq.InsertBefore( j, aStr );
1424             break;
1425           }
1426     }
1427   }
1428
1429   if ( aStrSeq.Length() == 0 )
1430     return;
1431
1432   theResStr = aStrSeq( 1 );
1433   for ( int j = 2, k = aStrSeq.Length(); j <= k; j++  )
1434   {
1435     theResStr += ",";
1436     theResStr += aStrSeq( j );
1437   }
1438 }
1439
1440 //=======================================================================
1441 // name    : SetRangeStr
1442 // Purpose : Define range with string
1443 //           Example of entry string: "1,2,3,50-60,63,67,70-"
1444 //=======================================================================
1445 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
1446 {
1447   myMin.Clear();
1448   myMax.Clear();
1449   myIds.Clear();
1450
1451   TCollection_AsciiString aStr = theStr;
1452   aStr.RemoveAll( ' ' );
1453   aStr.RemoveAll( '\t' );
1454
1455   for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) )
1456     aStr.Remove( aPos, 2 );
1457
1458   TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
1459   int i = 1;
1460   while ( tmpStr != "" )
1461   {
1462     tmpStr = aStr.Token( ",", i++ );
1463     int aPos = tmpStr.Search( '-' );
1464     
1465     if ( aPos == -1 )
1466     {
1467       if ( tmpStr.IsIntegerValue() )
1468         myIds.Add( tmpStr.IntegerValue() );
1469       else
1470         return false;
1471     }
1472     else
1473     {
1474       TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
1475       TCollection_AsciiString aMinStr = tmpStr;
1476       
1477       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
1478       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
1479
1480       if ( !aMinStr.IsEmpty() && !aMinStr.IsIntegerValue() ||
1481            !aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue() )
1482         return false;
1483            
1484       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
1485       myMax.Append( aMaxStr.IsEmpty() ? IntegerLast()  : aMaxStr.IntegerValue() );
1486     }
1487   }
1488
1489   return true;
1490 }
1491
1492 //=======================================================================
1493 // name    : GetType
1494 // Purpose : Get type of supported entities
1495 //=======================================================================
1496 SMDSAbs_ElementType RangeOfIds::GetType() const
1497 {
1498   return myType;
1499 }
1500
1501 //=======================================================================
1502 // name    : SetType
1503 // Purpose : Set type of supported entities
1504 //=======================================================================
1505 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
1506 {
1507   myType = theType;
1508 }
1509
1510 //=======================================================================
1511 // name    : IsSatisfy
1512 // Purpose : Verify whether entity satisfies to this rpedicate
1513 //=======================================================================
1514 bool RangeOfIds::IsSatisfy( long theId )
1515 {
1516   if ( !myMesh )
1517     return false;
1518
1519   if ( myType == SMDSAbs_Node )
1520   {
1521     if ( myMesh->FindNode( theId ) == 0 )
1522       return false;
1523   }
1524   else
1525   {
1526     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
1527     if ( anElem == 0 || myType != anElem->GetType() && myType != SMDSAbs_All )
1528       return false;
1529   }
1530     
1531   if ( myIds.Contains( theId ) )
1532     return true;
1533
1534   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1535     if ( theId >= myMin( i ) && theId <= myMax( i ) )
1536       return true;
1537
1538   return false;
1539 }
1540
1541 /*
1542   Class       : Comparator
1543   Description : Base class for comparators
1544 */
1545 Comparator::Comparator():
1546   myMargin(0)
1547 {}
1548
1549 Comparator::~Comparator()
1550 {}
1551
1552 void Comparator::SetMesh( SMDS_Mesh* theMesh )
1553 {
1554   if ( myFunctor )
1555     myFunctor->SetMesh( theMesh );
1556 }
1557
1558 void Comparator::SetMargin( double theValue )
1559 {
1560   myMargin = theValue;
1561 }
1562
1563 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
1564 {
1565   myFunctor = theFunct;
1566 }
1567
1568 SMDSAbs_ElementType Comparator::GetType() const
1569 {
1570   return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
1571 }
1572
1573 double Comparator::GetMargin()
1574 {
1575   return myMargin;
1576 }
1577
1578
1579 /*
1580   Class       : LessThan
1581   Description : Comparator "<"
1582 */
1583 bool LessThan::IsSatisfy( long theId )
1584 {
1585   return myFunctor && myFunctor->GetValue( theId ) < myMargin;
1586 }
1587
1588
1589 /*
1590   Class       : MoreThan
1591   Description : Comparator ">"
1592 */
1593 bool MoreThan::IsSatisfy( long theId )
1594 {
1595   return myFunctor && myFunctor->GetValue( theId ) > myMargin;
1596 }
1597
1598
1599 /*
1600   Class       : EqualTo
1601   Description : Comparator "="
1602 */
1603 EqualTo::EqualTo():
1604   myToler(Precision::Confusion())
1605 {}
1606
1607 bool EqualTo::IsSatisfy( long theId )
1608 {
1609   return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
1610 }
1611
1612 void EqualTo::SetTolerance( double theToler )
1613 {
1614   myToler = theToler;
1615 }
1616
1617 double EqualTo::GetTolerance()
1618 {
1619   return myToler;
1620 }
1621
1622 /*
1623   Class       : LogicalNOT
1624   Description : Logical NOT predicate
1625 */
1626 LogicalNOT::LogicalNOT()
1627 {}
1628
1629 LogicalNOT::~LogicalNOT()
1630 {}
1631
1632 bool LogicalNOT::IsSatisfy( long theId )
1633 {
1634   return myPredicate && !myPredicate->IsSatisfy( theId );
1635 }
1636
1637 void LogicalNOT::SetMesh( SMDS_Mesh* theMesh )
1638 {
1639   if ( myPredicate )
1640     myPredicate->SetMesh( theMesh );
1641 }
1642
1643 void LogicalNOT::SetPredicate( PredicatePtr thePred )
1644 {
1645   myPredicate = thePred;
1646 }
1647
1648 SMDSAbs_ElementType LogicalNOT::GetType() const
1649 {
1650   return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
1651 }
1652
1653
1654 /*
1655   Class       : LogicalBinary
1656   Description : Base class for binary logical predicate
1657 */
1658 LogicalBinary::LogicalBinary()
1659 {}
1660
1661 LogicalBinary::~LogicalBinary()
1662 {}
1663
1664 void LogicalBinary::SetMesh( SMDS_Mesh* theMesh )
1665 {
1666   if ( myPredicate1 )
1667     myPredicate1->SetMesh( theMesh );
1668
1669   if ( myPredicate2 )
1670     myPredicate2->SetMesh( theMesh );
1671 }
1672
1673 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
1674 {
1675   myPredicate1 = thePredicate;
1676 }
1677
1678 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
1679 {
1680   myPredicate2 = thePredicate;
1681 }
1682
1683 SMDSAbs_ElementType LogicalBinary::GetType() const
1684 {
1685   if ( !myPredicate1 || !myPredicate2 )
1686     return SMDSAbs_All;
1687
1688   SMDSAbs_ElementType aType1 = myPredicate1->GetType();
1689   SMDSAbs_ElementType aType2 = myPredicate2->GetType();
1690
1691   return aType1 == aType2 ? aType1 : SMDSAbs_All;
1692 }
1693
1694
1695 /*
1696   Class       : LogicalAND
1697   Description : Logical AND
1698 */
1699 bool LogicalAND::IsSatisfy( long theId )
1700 {
1701   return 
1702     myPredicate1 && 
1703     myPredicate2 && 
1704     myPredicate1->IsSatisfy( theId ) && 
1705     myPredicate2->IsSatisfy( theId );
1706 }
1707
1708
1709 /*
1710   Class       : LogicalOR
1711   Description : Logical OR
1712 */
1713 bool LogicalOR::IsSatisfy( long theId )
1714 {
1715   return 
1716     myPredicate1 && 
1717     myPredicate2 && 
1718     myPredicate1->IsSatisfy( theId ) || 
1719     myPredicate2->IsSatisfy( theId );
1720 }
1721
1722
1723 /*
1724                               FILTER
1725 */
1726
1727 Filter::Filter()
1728 {}
1729
1730 Filter::~Filter()
1731 {}
1732
1733 void Filter::SetPredicate( PredicatePtr thePredicate )
1734 {
1735   myPredicate = thePredicate;
1736 }
1737
1738
1739 template<class TElement, class TIterator, class TPredicate> 
1740 void FillSequence(const TIterator& theIterator,
1741                   TPredicate& thePredicate,
1742                   Filter::TIdSequence& theSequence)
1743 {
1744   if ( theIterator ) {
1745     while( theIterator->more() ) {
1746       TElement anElem = theIterator->next();
1747       long anId = anElem->GetID();
1748       if ( thePredicate->IsSatisfy( anId ) )
1749         theSequence.push_back( anId );
1750     }
1751   }
1752 }
1753
1754 Filter::TIdSequence
1755 Filter::GetElementsId( SMDS_Mesh* theMesh )
1756 {
1757   TIdSequence aSequence;
1758   if ( !theMesh || !myPredicate ) return aSequence;
1759
1760   myPredicate->SetMesh( theMesh );
1761
1762   SMDSAbs_ElementType aType = myPredicate->GetType();
1763   switch(aType){
1764   case SMDSAbs_Node:{
1765     FillSequence<const SMDS_MeshNode*>(theMesh->nodesIterator(),myPredicate,aSequence);
1766     break;
1767   }
1768   case SMDSAbs_Edge:{
1769     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),myPredicate,aSequence);
1770     break;
1771   }
1772   case SMDSAbs_Face:{
1773     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),myPredicate,aSequence);
1774     break;
1775   }
1776   case SMDSAbs_Volume:{
1777     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),myPredicate,aSequence);
1778     break;
1779   }
1780   case SMDSAbs_All:{
1781     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),myPredicate,aSequence);
1782     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),myPredicate,aSequence);
1783     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),myPredicate,aSequence);
1784     break;
1785   }
1786   }
1787   return aSequence;
1788 }
1789
1790 /*
1791                               ManifoldPart
1792 */
1793
1794 typedef std::set<SMDS_MeshFace*>                    TMapOfFacePtr;
1795
1796 /*  
1797    Internal class Link
1798 */ 
1799
1800 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
1801                           SMDS_MeshNode* theNode2 )
1802 {
1803   myNode1 = theNode1;
1804   myNode2 = theNode2;
1805 }
1806
1807 ManifoldPart::Link::~Link()
1808 {
1809   myNode1 = 0;
1810   myNode2 = 0;
1811 }
1812
1813 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
1814 {
1815   if ( myNode1 == theLink.myNode1 &&
1816        myNode2 == theLink.myNode2 )
1817     return true;
1818   else if ( myNode1 == theLink.myNode2 &&
1819             myNode2 == theLink.myNode1 )
1820     return true;
1821   else
1822     return false;
1823 }
1824
1825 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
1826 {
1827   if(myNode1 < x.myNode1) return true;
1828   if(myNode1 == x.myNode1)
1829     if(myNode2 < x.myNode2) return true;
1830   return false;
1831 }
1832
1833 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
1834                             const ManifoldPart::Link& theLink2 )
1835
1836   return theLink1.IsEqual( theLink2 );
1837 }
1838
1839 ManifoldPart::ManifoldPart()
1840 {
1841   myMesh = 0;
1842   myAngToler = Precision::Angular();
1843   myIsOnlyManifold = true;
1844 }
1845
1846 ManifoldPart::~ManifoldPart()
1847 {
1848   myMesh = 0;
1849 }
1850
1851 void ManifoldPart::SetMesh( SMDS_Mesh* theMesh )
1852 {
1853   myMesh = theMesh;
1854   process();
1855 }
1856
1857 SMDSAbs_ElementType ManifoldPart::GetType() const
1858 { return SMDSAbs_Face; }
1859
1860 bool ManifoldPart::IsSatisfy( long theElementId )
1861 {
1862   return myMapIds.Contains( theElementId );
1863 }
1864
1865 void ManifoldPart::SetAngleTolerance( const double theAngToler )
1866 { myAngToler = theAngToler; }
1867
1868 double ManifoldPart::GetAngleTolerance() const
1869 { return myAngToler; }
1870
1871 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
1872 { myIsOnlyManifold = theIsOnly; }
1873
1874 void ManifoldPart::SetStartElem( const long  theStartId )
1875 { myStartElemId = theStartId; }
1876
1877 bool ManifoldPart::process()
1878 {
1879   myMapIds.Clear();
1880   myMapBadGeomIds.Clear();
1881   
1882   myAllFacePtr.clear();
1883   myAllFacePtrIntDMap.clear();
1884   if ( !myMesh )
1885     return false;
1886
1887   // collect all faces into own map
1888   SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
1889   for (; anFaceItr->more(); )
1890   {
1891     SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
1892     myAllFacePtr.push_back( aFacePtr );
1893     myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
1894   }
1895
1896   SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
1897   if ( !aStartFace )
1898     return false;
1899
1900   // the map of non manifold links and bad geometry
1901   TMapOfLink aMapOfNonManifold;
1902   TColStd_MapOfInteger aMapOfTreated;
1903
1904   // begin cycle on faces from start index and run on vector till the end
1905   //  and from begin to start index to cover whole vector
1906   const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
1907   bool isStartTreat = false;
1908   for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
1909   {
1910     if ( fi == aStartIndx )
1911       isStartTreat = true;
1912     // as result next time when fi will be equal to aStartIndx
1913     
1914     SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
1915     if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
1916       continue;
1917
1918     aMapOfTreated.Add( aFacePtr->GetID() );
1919     TColStd_MapOfInteger aResFaces;
1920     if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
1921                          aMapOfNonManifold, aResFaces ) )
1922       continue;
1923     TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
1924     for ( ; anItr.More(); anItr.Next() )
1925     {
1926       int aFaceId = anItr.Key();
1927       aMapOfTreated.Add( aFaceId );
1928       myMapIds.Add( aFaceId );
1929     }
1930
1931     if ( fi == ( myAllFacePtr.size() - 1 ) )
1932       fi = 0;
1933   } // end run on vector of faces
1934   return !myMapIds.IsEmpty();
1935 }
1936
1937 static void getLinks( const SMDS_MeshFace* theFace,
1938                       ManifoldPart::TVectorOfLink& theLinks )
1939 {
1940   int aNbNode = theFace->NbNodes();
1941   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
1942   int i = 1;
1943   SMDS_MeshNode* aNode = 0;
1944   for ( ; aNodeItr->more() && i <= aNbNode; )
1945   {
1946     
1947     SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
1948     if ( i == 1 )
1949       aNode = aN1;
1950     i++;
1951     SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
1952     i++;
1953     ManifoldPart::Link aLink( aN1, aN2 );
1954     theLinks.push_back( aLink );
1955   }
1956 }
1957
1958 static gp_XYZ getNormale( const SMDS_MeshFace* theFace )
1959 {
1960   gp_XYZ n;
1961   int aNbNode = theFace->NbNodes();
1962   TColgp_Array1OfXYZ anArrOfXYZ(1,4);
1963   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
1964   int i = 1;
1965   for ( ; aNodeItr->more() && i <= 4; i++ )
1966   {
1967     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
1968     anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
1969   }
1970   
1971   gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1);
1972   gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1);
1973   n  = q1 ^ q2;
1974   if ( aNbNode > 3 )
1975   {
1976     gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1);
1977     n += q2 ^ q3;
1978   }
1979   double len = n.Modulus();
1980   if ( len > 0 )
1981     n /= len;
1982
1983   return n;
1984 }
1985
1986 bool ManifoldPart::findConnected
1987                  ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
1988                   SMDS_MeshFace*                           theStartFace,
1989                   ManifoldPart::TMapOfLink&                theNonManifold,
1990                   TColStd_MapOfInteger&                    theResFaces )
1991 {
1992   theResFaces.Clear();
1993   if ( !theAllFacePtrInt.size() )
1994     return false;
1995   
1996   if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
1997   {
1998     myMapBadGeomIds.Add( theStartFace->GetID() );
1999     return false;
2000   }
2001
2002   ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
2003   ManifoldPart::TVectorOfLink aSeqOfBoundary;
2004   theResFaces.Add( theStartFace->GetID() );
2005   ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
2006
2007   expandBoundary( aMapOfBoundary, aSeqOfBoundary, 
2008                  aDMapLinkFace, theNonManifold, theStartFace );
2009
2010   bool isDone = false;
2011   while ( !isDone && aMapOfBoundary.size() != 0 )
2012   {
2013     bool isToReset = false;
2014     ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
2015     for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
2016     {
2017       ManifoldPart::Link aLink = *pLink;
2018       if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
2019         continue;
2020       // each link could be treated only once
2021       aMapToSkip.insert( aLink );
2022
2023       ManifoldPart::TVectorOfFacePtr aFaces;
2024       // find next
2025       if ( myIsOnlyManifold && 
2026            (theNonManifold.find( aLink ) != theNonManifold.end()) )
2027         continue;
2028       else
2029       {
2030         getFacesByLink( aLink, aFaces );
2031         // filter the element to keep only indicated elements
2032         ManifoldPart::TVectorOfFacePtr aFiltered;
2033         ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
2034         for ( ; pFace != aFaces.end(); ++pFace )
2035         {
2036           SMDS_MeshFace* aFace = *pFace;
2037           if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
2038             aFiltered.push_back( aFace );
2039         }
2040         aFaces = aFiltered;
2041         if ( aFaces.size() < 2 )  // no neihgbour faces
2042           continue;
2043         else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
2044         {
2045           theNonManifold.insert( aLink );
2046           continue;
2047         }
2048       }
2049       
2050       // compare normal with normals of neighbor element
2051       SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
2052       ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
2053       for ( ; pFace != aFaces.end(); ++pFace )
2054       {
2055         SMDS_MeshFace* aNextFace = *pFace;
2056         if ( aPrevFace == aNextFace )
2057           continue;
2058         int anNextFaceID = aNextFace->GetID();
2059         if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
2060          // should not be with non manifold restriction. probably bad topology
2061           continue;
2062         // check if face was treated and skipped
2063         if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
2064              !isInPlane( aPrevFace, aNextFace ) )
2065           continue;
2066         // add new element to connected and extend the boundaries.
2067         theResFaces.Add( anNextFaceID );
2068         expandBoundary( aMapOfBoundary, aSeqOfBoundary, 
2069                         aDMapLinkFace, theNonManifold, aNextFace );
2070         isToReset = true;
2071       }
2072     }
2073     isDone = !isToReset;
2074   }
2075
2076   return !theResFaces.IsEmpty();
2077 }
2078
2079 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
2080                               const SMDS_MeshFace* theFace2 )
2081 {
2082   gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
2083   gp_XYZ aNorm2XYZ = getNormale( theFace2 );
2084   if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
2085   {
2086     myMapBadGeomIds.Add( theFace2->GetID() );
2087     return false;
2088   }
2089   if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
2090     return true;
2091
2092   return false;
2093 }
2094
2095 void ManifoldPart::expandBoundary
2096                    ( ManifoldPart::TMapOfLink&            theMapOfBoundary,
2097                      ManifoldPart::TVectorOfLink&         theSeqOfBoundary,
2098                      ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
2099                      ManifoldPart::TMapOfLink&            theNonManifold,
2100                      SMDS_MeshFace*                       theNextFace ) const
2101 {
2102   ManifoldPart::TVectorOfLink aLinks;
2103   getLinks( theNextFace, aLinks );
2104   int aNbLink = aLinks.size();
2105   for ( int i = 0; i < aNbLink; i++ )
2106   {
2107     ManifoldPart::Link aLink = aLinks[ i ];
2108     if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
2109       continue;
2110     if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
2111     {
2112       if ( myIsOnlyManifold )
2113       {
2114         // remove from boundary
2115         theMapOfBoundary.erase( aLink );
2116         ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
2117         for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
2118         {
2119           ManifoldPart::Link aBoundLink = *pLink;
2120           if ( aBoundLink.IsEqual( aLink ) )
2121           {
2122             theSeqOfBoundary.erase( pLink );
2123             break;
2124           }
2125         }
2126       }
2127     }
2128     else
2129     {
2130       theMapOfBoundary.insert( aLink );
2131       theSeqOfBoundary.push_back( aLink );
2132       theDMapLinkFacePtr[ aLink ] = theNextFace;
2133     }
2134   }
2135 }
2136
2137 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
2138                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
2139 {
2140   SMDS_Mesh::SetOfFaces aSetOfFaces;
2141   // take all faces that shared first node
2142   SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
2143   for ( ; anItr->more(); )
2144   {
2145     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2146     if ( !aFace )
2147       continue;
2148     aSetOfFaces.Add( aFace );
2149   }
2150   // take all faces that shared second node
2151   anItr = theLink.myNode2->facesIterator();
2152   // find the common part of two sets
2153   for ( ; anItr->more(); )
2154   {
2155     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2156     if ( aSetOfFaces.Contains( aFace ) )
2157       theFaces.push_back( aFace );
2158   }
2159 }
2160
2161
2162 /*
2163    ElementsOnSurface
2164 */
2165
2166 ElementsOnSurface::ElementsOnSurface()
2167 {
2168   myMesh = 0;
2169   myIds.Clear();
2170   myType = SMDSAbs_All;
2171   mySurf.Nullify();
2172   myToler = Precision::Confusion();
2173 }
2174
2175 ElementsOnSurface::~ElementsOnSurface()
2176 {
2177   myMesh = 0;
2178 }
2179
2180 void ElementsOnSurface::SetMesh( SMDS_Mesh* theMesh )
2181
2182   if ( myMesh == theMesh )
2183     return;
2184   myMesh = theMesh;
2185   myIds.Clear();
2186   process();
2187 }
2188
2189 bool ElementsOnSurface::IsSatisfy( long theElementId )
2190 {
2191   return myIds.Contains( theElementId );
2192 }
2193
2194 SMDSAbs_ElementType ElementsOnSurface::GetType() const
2195 { return myType; }
2196
2197 void ElementsOnSurface::SetTolerance( const double theToler )
2198 { myToler = theToler; }
2199
2200 double ElementsOnSurface::GetTolerance() const
2201 {
2202   return myToler;
2203 }
2204
2205 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
2206                                     const SMDSAbs_ElementType theType )
2207 {
2208   myType = theType;
2209   mySurf.Nullify();
2210   if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
2211   {
2212     mySurf.Nullify();
2213     return;
2214   }
2215   TopoDS_Face aFace = TopoDS::Face( theShape );
2216   mySurf = BRep_Tool::Surface( aFace );
2217 }
2218
2219 void ElementsOnSurface::process()
2220 {
2221   myIds.Clear();
2222   if ( mySurf.IsNull() )
2223     return;
2224
2225   if ( myMesh == 0 )
2226     return;
2227
2228   if ( myType == SMDSAbs_Face || myType == SMDSAbs_All )
2229   {
2230     SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
2231     for(; anIter->more(); )
2232       process( anIter->next() );
2233   }
2234
2235   if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All )
2236   {
2237     SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator();
2238     for(; anIter->more(); )
2239       process( anIter->next() );
2240   }
2241
2242   if ( myType == SMDSAbs_Node )
2243   {
2244     SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator();
2245     for(; anIter->more(); )
2246       process( anIter->next() );
2247   }
2248 }
2249
2250 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
2251 {
2252   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
2253   bool isSatisfy = true;
2254   for ( ; aNodeItr->more(); )
2255   {
2256     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
2257     if ( !isOnSurface( aNode ) )
2258     {
2259       isSatisfy = false;
2260       break;
2261     }
2262   }
2263   if ( isSatisfy )
2264     myIds.Add( theElemPtr->GetID() );
2265 }
2266
2267 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) const
2268 {
2269   if ( mySurf.IsNull() )
2270     return false;
2271
2272   gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
2273   double aToler2 = myToler * myToler;
2274   if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
2275   {
2276     gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
2277     if ( aPln.SquareDistance( aPnt ) > aToler2 )
2278       return false;
2279   }
2280   else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
2281   {
2282     gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
2283     double aRad = aCyl.Radius();
2284     gp_Ax3 anAxis = aCyl.Position();
2285     gp_XYZ aLoc = aCyl.Location().XYZ();
2286     double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
2287     double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
2288     if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
2289       return false;
2290   }
2291   else
2292     return false;
2293
2294   return true;
2295 }