1 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
18 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
20 #include "SMESH_ControlsDef.hxx"
24 #include <BRep_Tool.hxx>
26 #include <gp_Cylinder.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>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Shape.hxx>
44 #include "SMDS_Mesh.hxx"
45 #include "SMDS_Iterator.hxx"
46 #include "SMDS_MeshElement.hxx"
47 #include "SMDS_MeshNode.hxx"
55 inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
57 gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
59 return v1.Magnitude() < gp::Resolution() ||
60 v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
63 inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
65 gp_Vec aVec1( P2 - P1 );
66 gp_Vec aVec2( P3 - P1 );
67 return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
70 inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
72 return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
77 inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
79 double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
83 int getNbMultiConnection( SMDS_Mesh* theMesh, const int theId )
88 const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
89 if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge || anEdge->NbNodes() != 2 )
92 TColStd_MapOfInteger aMap;
95 SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator();
97 while( anIter->more() ) {
98 const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
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();
107 if ( anIter->more() ) // i.e. first node
109 else if ( aMap.Contains( anId ) )
123 using namespace SMESH::Controls;
130 Class : NumericalFunctor
131 Description : Base class for numerical functors
133 NumericalFunctor::NumericalFunctor():
139 void NumericalFunctor::SetMesh( SMDS_Mesh* theMesh )
144 bool NumericalFunctor::GetPoints(const int theId,
145 TSequenceOfXYZ& theRes ) const
152 return GetPoints( myMesh->FindElement( theId ), theRes );
155 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
156 TSequenceOfXYZ& theRes )
163 // Get nodes of the element
164 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
167 while( anIter->more() )
169 const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
171 theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
179 long NumericalFunctor::GetPrecision() const
184 void NumericalFunctor::SetPrecision( const long thePrecision )
186 myPrecision = thePrecision;
189 double NumericalFunctor::GetValue( long theId )
192 if ( GetPoints( theId, P ))
194 double aVal = GetValue( P );
195 if ( myPrecision >= 0 )
197 double prec = pow( 10., (double)( myPrecision ) );
198 aVal = floor( aVal * prec + 0.5 ) / prec;
208 Description : Functor for calculation of minimum angle
211 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
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 ) );
221 aMin = Min( A0, Min( A1, A2 ) );
223 else if ( P.size() == 4 )
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 ) );
230 aMin = Min( Min( A0, A1 ), Min( A2, A3 ) );
235 return aMin * 180 / PI;
238 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
240 const double aBestAngle = PI / nbNodes;
241 return ( fabs( aBestAngle - Value ));
244 SMDSAbs_ElementType MinimumAngle::GetType() const
252 Description : Functor for calculating aspect ratio
254 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
256 int nbNodes = P.size();
258 if ( nbNodes != 3 && nbNodes != 4 )
261 // Compute lengths of the sides
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 ) );
268 // Compute aspect ratio
272 double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) );
273 if ( anArea <= Precision::Confusion() )
275 double aMaxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
276 static double aCoef = sqrt( 3. ) / 4;
278 return aCoef * aMaxLen * aMaxLen / anArea;
282 double aMinLen = Min( Min( aLen[ 0 ], aLen[ 1 ] ), Min( aLen[ 2 ], aLen[ 3 ] ) );
283 if ( aMinLen <= Precision::Confusion() )
285 double aMaxLen = Max( Max( aLen[ 0 ], aLen[ 1 ] ), Max( aLen[ 2 ], aLen[ 3 ] ) );
287 return aMaxLen / aMinLen;
291 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
293 // the aspect ratio is in the range [1.0,infinity]
296 return Value / 1000.;
299 SMDSAbs_ElementType AspectRatio::GetType() const
306 Class : AspectRatio3D
307 Description : Functor for calculating aspect ratio
311 inline double getHalfPerimeter(double theTria[3]){
312 return (theTria[0] + theTria[1] + theTria[2])/2.0;
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]));
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;
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];
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;
348 return sqrt(P+Q+R-S)/12.0;
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;
359 inline double getMaxHeight(double theLen[6])
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]);
371 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
373 double aQuality = 0.0;
374 int nbNodes = P.size();
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
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
391 double aSumArea = 0.0;
392 double aHalfPerimeter = getHalfPerimeter(aTria[0]);
393 double anArea = getArea(aHalfPerimeter,aTria[0]);
395 aHalfPerimeter = getHalfPerimeter(aTria[1]);
396 anArea = getArea(aHalfPerimeter,aTria[1]);
398 aHalfPerimeter = getHalfPerimeter(aTria[2]);
399 anArea = getArea(aHalfPerimeter,aTria[2]);
401 aHalfPerimeter = getHalfPerimeter(aTria[3]);
402 anArea = getArea(aHalfPerimeter,aTria[3]);
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;
413 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
414 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
417 gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
418 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
421 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
422 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
425 gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
426 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
432 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
433 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
436 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
437 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
440 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
441 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
444 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
445 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
448 gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
449 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
452 gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
453 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
459 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
460 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
463 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
464 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
467 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
468 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
471 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
472 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
475 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
476 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
479 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
480 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
483 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
484 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
487 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
488 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
491 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
492 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
495 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
496 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
499 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
500 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
503 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
504 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
507 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
508 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
511 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
512 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
515 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
516 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
519 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
520 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
523 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
524 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
527 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
528 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
531 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
532 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
535 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
536 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
539 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
540 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
543 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
544 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
547 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
548 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
551 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
552 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
555 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
556 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
559 gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
560 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
563 gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
564 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
567 gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
568 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
571 gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
572 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
575 gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
576 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
579 gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
580 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
583 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
584 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
587 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
588 aQuality = max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
596 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
598 // the aspect ratio is in the range [1.0,infinity]
601 return Value / 1000.;
604 SMDSAbs_ElementType AspectRatio3D::GetType() const
606 return SMDSAbs_Volume;
612 Description : Functor for calculating warping
614 double Warping::GetValue( const TSequenceOfXYZ& P )
619 gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4;
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 );
626 return Max( Max( A1, A2 ), Max( A3, A4 ) );
629 double Warping::ComputeA( const gp_XYZ& thePnt1,
630 const gp_XYZ& thePnt2,
631 const gp_XYZ& thePnt3,
632 const gp_XYZ& theG ) const
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())
640 gp_XYZ GI = ( thePnt2 - thePnt1 ) / 2. - theG;
641 gp_XYZ GJ = ( thePnt3 - thePnt2 ) / 2. - theG;
642 gp_XYZ N = GI.Crossed( GJ );
644 if ( N.Modulus() < gp::Resolution() )
649 double H = ( thePnt2 - theG ).Dot( N );
650 return asin( fabs( H / L ) ) * 180 / PI;
653 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
655 // the warp is in the range [0.0,PI/2]
656 // 0.0 = good (no warp)
657 // PI/2 = bad (face pliee)
661 SMDSAbs_ElementType Warping::GetType() const
669 Description : Functor for calculating taper
671 double Taper::GetValue( const TSequenceOfXYZ& P )
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;
682 double JA = 0.25 * ( J1 + J2 + J3 + J4 );
683 if ( JA <= Precision::Confusion() )
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 );
691 return Max( Max( T1, T2 ), Max( T3, T4 ) );
694 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
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)
702 SMDSAbs_ElementType Taper::GetType() const
710 Description : Functor for calculating skew in degrees
712 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
714 gp_XYZ p12 = ( p2 + p1 ) / 2;
715 gp_XYZ p23 = ( p3 + p2 ) / 2;
716 gp_XYZ p31 = ( p3 + p1 ) / 2;
718 gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
720 return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
723 double Skew::GetValue( const TSequenceOfXYZ& P )
725 if ( P.size() != 3 && P.size() != 4 )
729 static double PI2 = PI / 2;
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 ) ) );
736 return Max( A0, Max( A1, A2 ) ) * 180 / PI;
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;
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 ) );
753 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
755 // the skew is in the range [0.0,PI/2].
761 SMDSAbs_ElementType Skew::GetType() const
769 Description : Functor for calculating area
771 double Area::GetValue( const TSequenceOfXYZ& P )
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 ) );
781 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
786 SMDSAbs_ElementType Area::GetType() const
794 Description : Functor for calculating length off edge
796 double Length::GetValue( const TSequenceOfXYZ& P )
798 return ( P.size() == 2 ? getDistance( P( 1 ), P( 2 ) ) : 0 );
801 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
806 SMDSAbs_ElementType Length::GetType() const
813 Description : Functor for calculating length of edge
816 double Length2D::GetValue( long theElementId)
820 if (GetPoints(theElementId,P)){
822 double aVal;// = GetValue( P );
823 const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
824 SMDSAbs_ElementType aType = aElem->GetType();
833 aVal = getDistance( P( 1 ), P( 2 ) );
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));
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));
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));
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 ));
873 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
874 aVal = Max(aVal,Max(L7,L8));
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 ));
888 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
889 aVal = Max(aVal,Max(Max(L7,L8),L9));
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 ));
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));
920 if ( myPrecision >= 0 )
922 double prec = pow( 10., (double)( myPrecision ) );
923 aVal = floor( aVal * prec + 0.5 ) / prec;
932 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
937 SMDSAbs_ElementType Length2D::GetType() const
942 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
945 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
946 if(thePntId1 > thePntId2){
947 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
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;
958 void Length2D::GetValues(TValues& theValues){
960 SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
961 for(; anIter->more(); ){
962 const SMDS_MeshFace* anElem = anIter->next();
963 SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
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();
976 for(; aNodesIter->more(); ){
977 aNode = aNodesIter->next();
978 const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
979 long anId = aNode->GetID();
981 P[2] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
983 aLength = P[1].Distance(P[2]);
985 Value aValue(aLength,aNodeId[1],anId);
988 theValues.insert(aValue);
991 aLength = P[0].Distance(P[1]);
993 Value aValue(aLength,aNodeId[0],aNodeId[1]);
994 theValues.insert(aValue);
999 Class : MultiConnection
1000 Description : Functor for calculating number of faces conneted to the edge
1002 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
1006 double MultiConnection::GetValue( long theId )
1008 return getNbMultiConnection( myMesh, theId );
1011 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
1016 SMDSAbs_ElementType MultiConnection::GetType() const
1018 return SMDSAbs_Edge;
1022 Class : MultiConnection2D
1023 Description : Functor for calculating number of faces conneted to the edge
1025 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
1030 double MultiConnection2D::GetValue( long theElementId )
1035 if (GetPoints(theElementId,P)){
1037 const SMDS_MeshElement* anFaceElem = myMesh->FindElement( theElementId );
1038 SMDSAbs_ElementType aType = anFaceElem->GetType();
1042 TColStd_MapOfInteger aMap;
1050 if (len == 3){ // triangles
1051 int Nb[3] = {0,0,0};
1054 SMDS_ElemIteratorPtr anIter = anFaceElem->nodesIterator();
1055 if ( anIter != 0 ) {
1056 while( anIter->more() ) {
1057 const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
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();
1067 if ( anIter->more() ) // i.e. first node
1069 else if ( aMap.Contains( anId ) ){
1073 else if ( anElem != 0 && anElem->GetType() == SMDSAbs_Edge ) i++;
1078 aResult = Max(Max(Nb[0],Nb[1]),Nb[2]);
1081 case SMDSAbs_Volume:
1086 return aResult;//getNbMultiConnection( myMesh, theId );
1089 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
1094 SMDSAbs_ElementType MultiConnection2D::GetType() const
1096 return SMDSAbs_Face;
1099 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
1101 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
1102 if(thePntId1 > thePntId2){
1103 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
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;
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();
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();
1129 const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode1;
1130 aNodeId[0] = aNodeId[1] = aNodes->GetID();
1132 for(; aNodesIter->more(); ){
1133 aNode2 = (SMDS_MeshNode*) aNodesIter->next();
1134 long anId = aNode2->GetID();
1137 Value aValue(aNodeId[1],aNodeId[2]);
1138 MValues::iterator aItr = theValues.find(aValue);
1139 if (aItr != theValues.end()){
1143 theValues[aValue] = 1;
1146 //cout << "NodeIds: "<<aNodeId[1]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1147 aNodeId[1] = aNodeId[2];
1150 Value aValue(aNodeId[0],aNodeId[2]);
1151 MValues::iterator aItr = theValues.find(aValue);
1152 if (aItr != theValues.end()){
1156 theValues[aValue] = 1;
1159 //cout << "NodeIds: "<<aNodeId[0]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
1170 Description : Predicate for free borders
1173 FreeBorders::FreeBorders()
1178 void FreeBorders::SetMesh( SMDS_Mesh* theMesh )
1183 bool FreeBorders::IsSatisfy( long theId )
1185 return getNbMultiConnection( myMesh, theId ) == 1;
1188 SMDSAbs_ElementType FreeBorders::GetType() const
1190 return SMDSAbs_Edge;
1196 Description : Predicate for free Edges
1198 FreeEdges::FreeEdges()
1203 void FreeEdges::SetMesh( SMDS_Mesh* theMesh )
1208 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId )
1210 TColStd_MapOfInteger aMap;
1211 for ( int i = 0; i < 2; i++ )
1213 SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator();
1214 while( anElemIter->more() )
1216 const SMDS_MeshElement* anElem = anElemIter->next();
1217 if ( anElem != 0 && anElem->GetType() == SMDSAbs_Face )
1219 int anId = anElem->GetID();
1223 else if ( aMap.Contains( anId ) && anId != theFaceId )
1231 bool FreeEdges::IsSatisfy( long theId )
1236 const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
1237 if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
1240 int nbNodes = aFace->NbNodes();
1241 const SMDS_MeshNode* aNodes[ nbNodes ];
1243 SMDS_ElemIteratorPtr anIter = aFace->nodesIterator();
1246 while( anIter->more() )
1248 const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
1251 aNodes[ i++ ] = aNode;
1255 for ( int i = 0; i < nbNodes - 1; i++ )
1256 if ( IsFreeEdge( &aNodes[ i ], theId ) )
1259 aNodes[ 1 ] = aNodes[ nbNodes - 1 ];
1261 return IsFreeEdge( &aNodes[ 0 ], theId );
1265 SMDSAbs_ElementType FreeEdges::GetType() const
1267 return SMDSAbs_Face;
1270 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
1273 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
1274 if(thePntId1 > thePntId2){
1275 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
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;
1286 inline void UpdateBorders(const FreeEdges::Border& theBorder,
1287 FreeEdges::TBorders& theRegistry,
1288 FreeEdges::TBorders& theContainer)
1290 if(theRegistry.find(theBorder) == theRegistry.end()){
1291 theRegistry.insert(theBorder);
1292 theContainer.insert(theBorder);
1294 theContainer.erase(theBorder);
1298 void FreeEdges::GetBoreders(TBorders& theBorders)
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();
1307 const SMDS_MeshElement* aNode;
1308 if(aNodesIter->more()){
1309 aNode = aNodesIter->next();
1310 aNodeId[0] = aNodeId[1] = aNode->GetID();
1312 for(; aNodesIter->more(); ){
1313 aNode = aNodesIter->next();
1314 long anId = aNode->GetID();
1315 Border aBorder(anElemId,aNodeId[1],anId);
1317 //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
1318 UpdateBorders(aBorder,aRegistry,theBorders);
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);
1324 //std::cout<<"theBorders.size() = "<<theBorders.size()<<endl;
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-"
1336 //=======================================================================
1337 // name : RangeOfIds
1338 // Purpose : Constructor
1339 //=======================================================================
1340 RangeOfIds::RangeOfIds()
1343 myType = SMDSAbs_All;
1346 //=======================================================================
1348 // Purpose : Set mesh
1349 //=======================================================================
1350 void RangeOfIds::SetMesh( SMDS_Mesh* theMesh )
1355 //=======================================================================
1356 // name : AddToRange
1357 // Purpose : Add ID to the range
1358 //=======================================================================
1359 bool RangeOfIds::AddToRange( long theEntityId )
1361 myIds.Add( theEntityId );
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 )
1374 TColStd_SequenceOfInteger anIntSeq;
1375 TColStd_SequenceOfAsciiString aStrSeq;
1377 TColStd_MapIteratorOfMapOfInteger anIter( myIds );
1378 for ( ; anIter.More(); anIter.Next() )
1380 int anId = anIter.Key();
1381 TCollection_AsciiString aStr( anId );
1382 anIntSeq.Append( anId );
1383 aStrSeq.Append( aStr );
1386 for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1388 int aMinId = myMin( i );
1389 int aMaxId = myMax( i );
1391 TCollection_AsciiString aStr;
1392 if ( aMinId != IntegerFirst() )
1397 if ( aMaxId != IntegerLast() )
1400 // find position of the string in result sequence and insert string in it
1401 if ( anIntSeq.Length() == 0 )
1403 anIntSeq.Append( aMinId );
1404 aStrSeq.Append( aStr );
1408 if ( aMinId < anIntSeq.First() )
1410 anIntSeq.Prepend( aMinId );
1411 aStrSeq.Prepend( aStr );
1413 else if ( aMinId > anIntSeq.Last() )
1415 anIntSeq.Append( aMinId );
1416 aStrSeq.Append( aStr );
1419 for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
1420 if ( aMinId < anIntSeq( j ) )
1422 anIntSeq.InsertBefore( j, aMinId );
1423 aStrSeq.InsertBefore( j, aStr );
1429 if ( aStrSeq.Length() == 0 )
1432 theResStr = aStrSeq( 1 );
1433 for ( int j = 2, k = aStrSeq.Length(); j <= k; j++ )
1436 theResStr += aStrSeq( j );
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 )
1451 TCollection_AsciiString aStr = theStr;
1452 aStr.RemoveAll( ' ' );
1453 aStr.RemoveAll( '\t' );
1455 for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) )
1456 aStr.Remove( aPos, 2 );
1458 TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
1460 while ( tmpStr != "" )
1462 tmpStr = aStr.Token( ",", i++ );
1463 int aPos = tmpStr.Search( '-' );
1467 if ( tmpStr.IsIntegerValue() )
1468 myIds.Add( tmpStr.IntegerValue() );
1474 TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
1475 TCollection_AsciiString aMinStr = tmpStr;
1477 while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
1478 while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
1480 if ( !aMinStr.IsEmpty() && !aMinStr.IsIntegerValue() ||
1481 !aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue() )
1484 myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
1485 myMax.Append( aMaxStr.IsEmpty() ? IntegerLast() : aMaxStr.IntegerValue() );
1492 //=======================================================================
1494 // Purpose : Get type of supported entities
1495 //=======================================================================
1496 SMDSAbs_ElementType RangeOfIds::GetType() const
1501 //=======================================================================
1503 // Purpose : Set type of supported entities
1504 //=======================================================================
1505 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
1510 //=======================================================================
1512 // Purpose : Verify whether entity satisfies to this rpedicate
1513 //=======================================================================
1514 bool RangeOfIds::IsSatisfy( long theId )
1519 if ( myType == SMDSAbs_Node )
1521 if ( myMesh->FindNode( theId ) == 0 )
1526 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
1527 if ( anElem == 0 || myType != anElem->GetType() && myType != SMDSAbs_All )
1531 if ( myIds.Contains( theId ) )
1534 for ( int i = 1, n = myMin.Length(); i <= n; i++ )
1535 if ( theId >= myMin( i ) && theId <= myMax( i ) )
1543 Description : Base class for comparators
1545 Comparator::Comparator():
1549 Comparator::~Comparator()
1552 void Comparator::SetMesh( SMDS_Mesh* theMesh )
1555 myFunctor->SetMesh( theMesh );
1558 void Comparator::SetMargin( double theValue )
1560 myMargin = theValue;
1563 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
1565 myFunctor = theFunct;
1568 SMDSAbs_ElementType Comparator::GetType() const
1570 return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
1573 double Comparator::GetMargin()
1581 Description : Comparator "<"
1583 bool LessThan::IsSatisfy( long theId )
1585 return myFunctor && myFunctor->GetValue( theId ) < myMargin;
1591 Description : Comparator ">"
1593 bool MoreThan::IsSatisfy( long theId )
1595 return myFunctor && myFunctor->GetValue( theId ) > myMargin;
1601 Description : Comparator "="
1604 myToler(Precision::Confusion())
1607 bool EqualTo::IsSatisfy( long theId )
1609 return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
1612 void EqualTo::SetTolerance( double theToler )
1617 double EqualTo::GetTolerance()
1624 Description : Logical NOT predicate
1626 LogicalNOT::LogicalNOT()
1629 LogicalNOT::~LogicalNOT()
1632 bool LogicalNOT::IsSatisfy( long theId )
1634 return myPredicate && !myPredicate->IsSatisfy( theId );
1637 void LogicalNOT::SetMesh( SMDS_Mesh* theMesh )
1640 myPredicate->SetMesh( theMesh );
1643 void LogicalNOT::SetPredicate( PredicatePtr thePred )
1645 myPredicate = thePred;
1648 SMDSAbs_ElementType LogicalNOT::GetType() const
1650 return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
1655 Class : LogicalBinary
1656 Description : Base class for binary logical predicate
1658 LogicalBinary::LogicalBinary()
1661 LogicalBinary::~LogicalBinary()
1664 void LogicalBinary::SetMesh( SMDS_Mesh* theMesh )
1667 myPredicate1->SetMesh( theMesh );
1670 myPredicate2->SetMesh( theMesh );
1673 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
1675 myPredicate1 = thePredicate;
1678 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
1680 myPredicate2 = thePredicate;
1683 SMDSAbs_ElementType LogicalBinary::GetType() const
1685 if ( !myPredicate1 || !myPredicate2 )
1688 SMDSAbs_ElementType aType1 = myPredicate1->GetType();
1689 SMDSAbs_ElementType aType2 = myPredicate2->GetType();
1691 return aType1 == aType2 ? aType1 : SMDSAbs_All;
1697 Description : Logical AND
1699 bool LogicalAND::IsSatisfy( long theId )
1704 myPredicate1->IsSatisfy( theId ) &&
1705 myPredicate2->IsSatisfy( theId );
1711 Description : Logical OR
1713 bool LogicalOR::IsSatisfy( long theId )
1718 myPredicate1->IsSatisfy( theId ) ||
1719 myPredicate2->IsSatisfy( theId );
1733 void Filter::SetPredicate( PredicatePtr thePredicate )
1735 myPredicate = thePredicate;
1739 template<class TElement, class TIterator, class TPredicate>
1740 void FillSequence(const TIterator& theIterator,
1741 TPredicate& thePredicate,
1742 Filter::TIdSequence& theSequence)
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 );
1755 Filter::GetElementsId( SMDS_Mesh* theMesh )
1757 TIdSequence aSequence;
1758 if ( !theMesh || !myPredicate ) return aSequence;
1760 myPredicate->SetMesh( theMesh );
1762 SMDSAbs_ElementType aType = myPredicate->GetType();
1765 FillSequence<const SMDS_MeshNode*>(theMesh->nodesIterator(),myPredicate,aSequence);
1769 FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),myPredicate,aSequence);
1773 FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),myPredicate,aSequence);
1776 case SMDSAbs_Volume:{
1777 FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),myPredicate,aSequence);
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);
1794 typedef std::set<SMDS_MeshFace*> TMapOfFacePtr;
1800 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
1801 SMDS_MeshNode* theNode2 )
1807 ManifoldPart::Link::~Link()
1813 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
1815 if ( myNode1 == theLink.myNode1 &&
1816 myNode2 == theLink.myNode2 )
1818 else if ( myNode1 == theLink.myNode2 &&
1819 myNode2 == theLink.myNode1 )
1825 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
1827 if(myNode1 < x.myNode1) return true;
1828 if(myNode1 == x.myNode1)
1829 if(myNode2 < x.myNode2) return true;
1833 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
1834 const ManifoldPart::Link& theLink2 )
1836 return theLink1.IsEqual( theLink2 );
1839 ManifoldPart::ManifoldPart()
1842 myAngToler = Precision::Angular();
1843 myIsOnlyManifold = true;
1846 ManifoldPart::~ManifoldPart()
1851 void ManifoldPart::SetMesh( SMDS_Mesh* theMesh )
1857 SMDSAbs_ElementType ManifoldPart::GetType() const
1858 { return SMDSAbs_Face; }
1860 bool ManifoldPart::IsSatisfy( long theElementId )
1862 return myMapIds.Contains( theElementId );
1865 void ManifoldPart::SetAngleTolerance( const double theAngToler )
1866 { myAngToler = theAngToler; }
1868 double ManifoldPart::GetAngleTolerance() const
1869 { return myAngToler; }
1871 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
1872 { myIsOnlyManifold = theIsOnly; }
1874 void ManifoldPart::SetStartElem( const long theStartId )
1875 { myStartElemId = theStartId; }
1877 bool ManifoldPart::process()
1880 myMapBadGeomIds.Clear();
1882 myAllFacePtr.clear();
1883 myAllFacePtrIntDMap.clear();
1887 // collect all faces into own map
1888 SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
1889 for (; anFaceItr->more(); )
1891 SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
1892 myAllFacePtr.push_back( aFacePtr );
1893 myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
1896 SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
1900 // the map of non manifold links and bad geometry
1901 TMapOfLink aMapOfNonManifold;
1902 TColStd_MapOfInteger aMapOfTreated;
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++ )
1910 if ( fi == aStartIndx )
1911 isStartTreat = true;
1912 // as result next time when fi will be equal to aStartIndx
1914 SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
1915 if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
1918 aMapOfTreated.Add( aFacePtr->GetID() );
1919 TColStd_MapOfInteger aResFaces;
1920 if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
1921 aMapOfNonManifold, aResFaces ) )
1923 TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
1924 for ( ; anItr.More(); anItr.Next() )
1926 int aFaceId = anItr.Key();
1927 aMapOfTreated.Add( aFaceId );
1928 myMapIds.Add( aFaceId );
1931 if ( fi == ( myAllFacePtr.size() - 1 ) )
1933 } // end run on vector of faces
1934 return !myMapIds.IsEmpty();
1937 static void getLinks( const SMDS_MeshFace* theFace,
1938 ManifoldPart::TVectorOfLink& theLinks )
1940 int aNbNode = theFace->NbNodes();
1941 SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
1943 SMDS_MeshNode* aNode = 0;
1944 for ( ; aNodeItr->more() && i <= aNbNode; )
1947 SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
1951 SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
1953 ManifoldPart::Link aLink( aN1, aN2 );
1954 theLinks.push_back( aLink );
1958 static gp_XYZ getNormale( const SMDS_MeshFace* theFace )
1961 int aNbNode = theFace->NbNodes();
1962 TColgp_Array1OfXYZ anArrOfXYZ(1,4);
1963 SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
1965 for ( ; aNodeItr->more() && i <= 4; i++ )
1967 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
1968 anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
1971 gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1);
1972 gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1);
1976 gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1);
1979 double len = n.Modulus();
1986 bool ManifoldPart::findConnected
1987 ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
1988 SMDS_MeshFace* theStartFace,
1989 ManifoldPart::TMapOfLink& theNonManifold,
1990 TColStd_MapOfInteger& theResFaces )
1992 theResFaces.Clear();
1993 if ( !theAllFacePtrInt.size() )
1996 if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
1998 myMapBadGeomIds.Add( theStartFace->GetID() );
2002 ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
2003 ManifoldPart::TVectorOfLink aSeqOfBoundary;
2004 theResFaces.Add( theStartFace->GetID() );
2005 ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
2007 expandBoundary( aMapOfBoundary, aSeqOfBoundary,
2008 aDMapLinkFace, theNonManifold, theStartFace );
2010 bool isDone = false;
2011 while ( !isDone && aMapOfBoundary.size() != 0 )
2013 bool isToReset = false;
2014 ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
2015 for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
2017 ManifoldPart::Link aLink = *pLink;
2018 if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
2020 // each link could be treated only once
2021 aMapToSkip.insert( aLink );
2023 ManifoldPart::TVectorOfFacePtr aFaces;
2025 if ( myIsOnlyManifold &&
2026 (theNonManifold.find( aLink ) != theNonManifold.end()) )
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 )
2036 SMDS_MeshFace* aFace = *pFace;
2037 if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
2038 aFiltered.push_back( aFace );
2041 if ( aFaces.size() < 2 ) // no neihgbour faces
2043 else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
2045 theNonManifold.insert( aLink );
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 )
2055 SMDS_MeshFace* aNextFace = *pFace;
2056 if ( aPrevFace == aNextFace )
2058 int anNextFaceID = aNextFace->GetID();
2059 if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
2060 // should not be with non manifold restriction. probably bad topology
2062 // check if face was treated and skipped
2063 if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
2064 !isInPlane( aPrevFace, aNextFace ) )
2066 // add new element to connected and extend the boundaries.
2067 theResFaces.Add( anNextFaceID );
2068 expandBoundary( aMapOfBoundary, aSeqOfBoundary,
2069 aDMapLinkFace, theNonManifold, aNextFace );
2073 isDone = !isToReset;
2076 return !theResFaces.IsEmpty();
2079 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
2080 const SMDS_MeshFace* theFace2 )
2082 gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
2083 gp_XYZ aNorm2XYZ = getNormale( theFace2 );
2084 if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
2086 myMapBadGeomIds.Add( theFace2->GetID() );
2089 if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
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
2102 ManifoldPart::TVectorOfLink aLinks;
2103 getLinks( theNextFace, aLinks );
2104 int aNbLink = aLinks.size();
2105 for ( int i = 0; i < aNbLink; i++ )
2107 ManifoldPart::Link aLink = aLinks[ i ];
2108 if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
2110 if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
2112 if ( myIsOnlyManifold )
2114 // remove from boundary
2115 theMapOfBoundary.erase( aLink );
2116 ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
2117 for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
2119 ManifoldPart::Link aBoundLink = *pLink;
2120 if ( aBoundLink.IsEqual( aLink ) )
2122 theSeqOfBoundary.erase( pLink );
2130 theMapOfBoundary.insert( aLink );
2131 theSeqOfBoundary.push_back( aLink );
2132 theDMapLinkFacePtr[ aLink ] = theNextFace;
2137 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
2138 ManifoldPart::TVectorOfFacePtr& theFaces ) const
2140 SMDS_Mesh::SetOfFaces aSetOfFaces;
2141 // take all faces that shared first node
2142 SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
2143 for ( ; anItr->more(); )
2145 SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2148 aSetOfFaces.Add( aFace );
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(); )
2155 SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
2156 if ( aSetOfFaces.Contains( aFace ) )
2157 theFaces.push_back( aFace );
2166 ElementsOnSurface::ElementsOnSurface()
2170 myType = SMDSAbs_All;
2172 myToler = Precision::Confusion();
2175 ElementsOnSurface::~ElementsOnSurface()
2180 void ElementsOnSurface::SetMesh( SMDS_Mesh* theMesh )
2182 if ( myMesh == theMesh )
2189 bool ElementsOnSurface::IsSatisfy( long theElementId )
2191 return myIds.Contains( theElementId );
2194 SMDSAbs_ElementType ElementsOnSurface::GetType() const
2197 void ElementsOnSurface::SetTolerance( const double theToler )
2198 { myToler = theToler; }
2200 double ElementsOnSurface::GetTolerance() const
2205 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
2206 const SMDSAbs_ElementType theType )
2210 if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
2215 TopoDS_Face aFace = TopoDS::Face( theShape );
2216 mySurf = BRep_Tool::Surface( aFace );
2219 void ElementsOnSurface::process()
2222 if ( mySurf.IsNull() )
2228 if ( myType == SMDSAbs_Face || myType == SMDSAbs_All )
2230 SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
2231 for(; anIter->more(); )
2232 process( anIter->next() );
2235 if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All )
2237 SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator();
2238 for(; anIter->more(); )
2239 process( anIter->next() );
2242 if ( myType == SMDSAbs_Node )
2244 SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator();
2245 for(; anIter->more(); )
2246 process( anIter->next() );
2250 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
2252 SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
2253 bool isSatisfy = true;
2254 for ( ; aNodeItr->more(); )
2256 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
2257 if ( !isOnSurface( aNode ) )
2264 myIds.Add( theElemPtr->GetID() );
2267 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) const
2269 if ( mySurf.IsNull() )
2272 gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
2273 double aToler2 = myToler * myToler;
2274 if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
2276 gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
2277 if ( aPln.SquareDistance( aPnt ) > aToler2 )
2280 else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
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 )