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