1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "SMESH_ControlsDef.hxx"
25 #include "SMDS_BallElement.hxx"
26 #include "SMDS_FacePosition.hxx"
27 #include "SMDS_Iterator.hxx"
28 #include "SMDS_Mesh.hxx"
29 #include "SMDS_MeshElement.hxx"
30 #include "SMDS_MeshNode.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMESHDS_GroupBase.hxx"
33 #include "SMESHDS_GroupOnFilter.hxx"
34 #include "SMESHDS_Mesh.hxx"
35 #include "SMESH_MeshAlgos.hxx"
36 #include "SMESH_OctreeNode.hxx"
37 #include "SMESH_Comment.hxx"
39 #include <GEOMUtils.hxx>
40 #include <Basics_Utils.hxx>
42 #include <BRepAdaptor_Surface.hxx>
43 #include <BRepBndLib.hxx>
44 #include <BRepBuilderAPI_Copy.hxx>
45 #include <BRepClass3d_SolidClassifier.hxx>
46 #include <BRepClass_FaceClassifier.hxx>
47 #include <BRep_Tool.hxx>
48 #include <GeomLib_IsPlanarSurface.hxx>
49 #include <Geom_CylindricalSurface.hxx>
50 #include <Geom_Plane.hxx>
51 #include <Geom_Surface.hxx>
52 #include <NCollection_Map.hxx>
53 #include <Precision.hxx>
54 #include <ShapeAnalysis_Surface.hxx>
55 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
56 #include <TColStd_MapOfInteger.hxx>
57 #include <TColStd_SequenceOfAsciiString.hxx>
58 #include <TColgp_Array1OfXYZ.hxx>
62 #include <TopoDS_Edge.hxx>
63 #include <TopoDS_Face.hxx>
64 #include <TopoDS_Iterator.hxx>
65 #include <TopoDS_Shape.hxx>
66 #include <TopoDS_Vertex.hxx>
68 #include <gp_Cylinder.hxx>
75 #include <vtkMeshQuality.h>
86 const double theEps = 1e-100;
87 const double theInf = 1e+100;
89 inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode )
91 return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() );
94 inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
96 gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
98 return v1.Magnitude() < gp::Resolution() ||
99 v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
102 inline double getCos2( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
104 gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
105 double dot = v1 * v2, len1 = v1.SquareMagnitude(), len2 = v2.SquareMagnitude();
107 return ( dot < 0 || len1 < gp::Resolution() || len2 < gp::Resolution() ? -1 :
108 dot * dot / len1 / len2 );
111 inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
113 gp_Vec aVec1( P2 - P1 );
114 gp_Vec aVec2( P3 - P1 );
115 return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
118 inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
120 return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
125 inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
127 double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
131 int getNbMultiConnection( const SMDS_Mesh* theMesh, const smIdType theId )
136 const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
137 if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */)
140 // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge)
141 // count elements containing both nodes of the pair.
142 // Note that there may be such cases for a quadratic edge (a horizontal line):
147 // +-----+------+ +-----+------+
150 // result should be 2 in both cases
152 int aResult0 = 0, aResult1 = 0;
153 // last node, it is a medium one in a quadratic edge
154 const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 );
155 const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 );
156 const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 );
157 if ( aNode1 == aLastNode ) aNode1 = 0;
159 SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator();
160 while( anElemIter->more() ) {
161 const SMDS_MeshElement* anElem = anElemIter->next();
162 if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
163 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
164 while ( anIter->more() ) {
165 if ( const SMDS_MeshElement* anElemNode = anIter->next() ) {
166 if ( anElemNode == aNode0 ) {
168 if ( !aNode1 ) break; // not a quadratic edge
170 else if ( anElemNode == aNode1 )
176 int aResult = std::max ( aResult0, aResult1 );
181 gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 )
183 int aNbNode = theFace->NbNodes();
185 gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0));
186 gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0));
189 gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0));
192 double len = n.Modulus();
193 bool zeroLen = ( len <= std::numeric_limits<double>::min());
197 if (ok) *ok = !zeroLen;
205 using namespace SMESH::Controls;
211 //================================================================================
213 Class : NumericalFunctor
214 Description : Base class for numerical functors
216 //================================================================================
218 NumericalFunctor::NumericalFunctor():
224 void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh )
229 bool NumericalFunctor::GetPoints(const smIdType theId,
230 TSequenceOfXYZ& theRes ) const
237 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
238 if ( !IsApplicable( anElem ))
241 return GetPoints( anElem, theRes );
244 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
245 TSequenceOfXYZ& theRes )
252 theRes.reserve( anElem->NbNodes() );
253 theRes.setElement( anElem );
255 // Get nodes of the element
256 SMDS_NodeIteratorPtr anIter= anElem->interlacedNodesIterator();
259 while( anIter->more() ) {
260 if ( p.Set( anIter->next() ))
261 theRes.push_back( p );
268 long NumericalFunctor::GetPrecision() const
273 void NumericalFunctor::SetPrecision( const long thePrecision )
275 myPrecision = thePrecision;
276 myPrecisionValue = pow( 10., (double)( myPrecision ) );
279 double NumericalFunctor::GetValue( long theId )
283 myCurrElement = myMesh->FindElement( theId );
286 if ( GetPoints( theId, P )) // elem type is checked here
287 aVal = Round( GetValue( P ));
292 double NumericalFunctor::Round( const double & aVal )
294 return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
297 //================================================================================
299 * \brief Return true if a value can be computed for a given element.
300 * Some NumericalFunctor's are meaningful for elements of a certain
303 //================================================================================
305 bool NumericalFunctor::IsApplicable( const SMDS_MeshElement* element ) const
307 return element && element->GetType() == this->GetType();
310 bool NumericalFunctor::IsApplicable( long theElementId ) const
312 return IsApplicable( myMesh->FindElement( theElementId ));
315 //================================================================================
317 * \brief Return histogram of functor values
318 * \param nbIntervals - number of intervals
319 * \param nbEvents - number of mesh elements having values within i-th interval
320 * \param funValues - boundaries of intervals
321 * \param elements - elements to check vulue of; empty list means "of all"
322 * \param minmax - boundaries of diapason of values to divide into intervals
324 //================================================================================
326 void NumericalFunctor::GetHistogram(int nbIntervals,
327 std::vector<int>& nbEvents,
328 std::vector<double>& funValues,
329 const std::vector<smIdType>& elements,
330 const double* minmax,
331 const bool isLogarithmic)
333 if ( nbIntervals < 1 ||
335 !myMesh->GetMeshInfo().NbElements( GetType() ))
337 nbEvents.resize( nbIntervals, 0 );
338 funValues.resize( nbIntervals+1 );
340 // get all values sorted
341 std::multiset< double > values;
342 if ( elements.empty() )
344 SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() );
345 while ( elemIt->more() )
346 values.insert( GetValue( elemIt->next()->GetID() ));
350 std::vector<smIdType>::const_iterator id = elements.begin();
351 for ( ; id != elements.end(); ++id )
352 values.insert( GetValue( *id ));
357 funValues[0] = minmax[0];
358 funValues[nbIntervals] = minmax[1];
362 funValues[0] = *values.begin();
363 funValues[nbIntervals] = *values.rbegin();
365 // case nbIntervals == 1
366 if ( nbIntervals == 1 )
368 nbEvents[0] = values.size();
372 if (funValues.front() == funValues.back())
374 nbEvents.resize( 1 );
375 nbEvents[0] = values.size();
376 funValues[1] = funValues.back();
377 funValues.resize( 2 );
380 std::multiset< double >::iterator min = values.begin(), max;
381 for ( int i = 0; i < nbIntervals; ++i )
383 // find end value of i-th interval
384 double r = (i+1) / double(nbIntervals);
385 if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) {
386 double logmin = log10(funValues.front());
387 double lval = logmin + r * (log10(funValues.back()) - logmin);
388 funValues[i+1] = pow(10.0, lval);
391 funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r;
394 // count values in the i-th interval if there are any
395 if ( min != values.end() && *min <= funValues[i+1] )
397 // find the first value out of the interval
398 max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end()
399 nbEvents[i] = std::distance( min, max );
403 // add values larger than minmax[1]
404 nbEvents.back() += std::distance( min, values.end() );
407 //=======================================================================
410 Description : Functor calculating volume of a 3D element
412 //================================================================================
414 double Volume::GetValue( long theElementId )
416 if ( theElementId && myMesh ) {
417 SMDS_VolumeTool aVolumeTool;
418 if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
419 return aVolumeTool.GetSize();
424 double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const
429 SMDSAbs_ElementType Volume::GetType() const
431 return SMDSAbs_Volume;
434 //=======================================================================
436 Class : MaxElementLength2D
437 Description : Functor calculating maximum length of 2D element
439 //================================================================================
441 double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P )
447 if( len == 3 ) { // triangles
448 double L1 = getDistance(P( 1 ),P( 2 ));
449 double L2 = getDistance(P( 2 ),P( 3 ));
450 double L3 = getDistance(P( 3 ),P( 1 ));
451 aVal = Max(L1,Max(L2,L3));
453 else if( len == 4 ) { // quadrangles
454 double L1 = getDistance(P( 1 ),P( 2 ));
455 double L2 = getDistance(P( 2 ),P( 3 ));
456 double L3 = getDistance(P( 3 ),P( 4 ));
457 double L4 = getDistance(P( 4 ),P( 1 ));
458 double D1 = getDistance(P( 1 ),P( 3 ));
459 double D2 = getDistance(P( 2 ),P( 4 ));
460 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
462 else if( len == 6 ) { // quadratic triangles
463 double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
464 double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
465 double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
466 aVal = Max(L1,Max(L2,L3));
468 else if( len == 8 || len == 9 ) { // quadratic quadrangles
469 double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
470 double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
471 double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
472 double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
473 double D1 = getDistance(P( 1 ),P( 5 ));
474 double D2 = getDistance(P( 3 ),P( 7 ));
475 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
477 // Diagonals are undefined for concave polygons
478 // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon
481 // aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 ));
482 // for ( size_t i = 1; i < P.size()-1; i += 2 )
484 // double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 ));
485 // aVal = Max( aVal, L );
488 // for ( int i = P.size()-5; i > 0; i -= 2 )
489 // for ( int j = i + 4; j < P.size() + i - 2; i += 2 )
491 // double D = getDistance( P( i ), P( j ));
492 // aVal = Max( aVal, D );
499 if( myPrecision >= 0 )
501 double prec = pow( 10., (double)myPrecision );
502 aVal = floor( aVal * prec + 0.5 ) / prec;
507 double MaxElementLength2D::GetValue( long theElementId )
510 return GetPoints( theElementId, P ) ? GetValue(P) : 0.0;
513 double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const
518 SMDSAbs_ElementType MaxElementLength2D::GetType() const
523 //=======================================================================
525 Class : MaxElementLength3D
526 Description : Functor calculating maximum length of 3D element
528 //================================================================================
530 double MaxElementLength3D::GetValue( long theElementId )
533 if( GetPoints( theElementId, P ) ) {
535 const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
536 SMDSAbs_EntityType aType = aElem->GetEntityType();
539 case SMDSEntity_Tetra: { // tetras
540 double L1 = getDistance(P( 1 ),P( 2 ));
541 double L2 = getDistance(P( 2 ),P( 3 ));
542 double L3 = getDistance(P( 3 ),P( 1 ));
543 double L4 = getDistance(P( 1 ),P( 4 ));
544 double L5 = getDistance(P( 2 ),P( 4 ));
545 double L6 = getDistance(P( 3 ),P( 4 ));
546 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
549 case SMDSEntity_Pyramid: { // pyramids
550 double L1 = getDistance(P( 1 ),P( 2 ));
551 double L2 = getDistance(P( 2 ),P( 3 ));
552 double L3 = getDistance(P( 3 ),P( 4 ));
553 double L4 = getDistance(P( 4 ),P( 1 ));
554 double L5 = getDistance(P( 1 ),P( 5 ));
555 double L6 = getDistance(P( 2 ),P( 5 ));
556 double L7 = getDistance(P( 3 ),P( 5 ));
557 double L8 = getDistance(P( 4 ),P( 5 ));
558 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
559 aVal = Max(aVal,Max(L7,L8));
562 case SMDSEntity_Penta: { // pentas
563 double L1 = getDistance(P( 1 ),P( 2 ));
564 double L2 = getDistance(P( 2 ),P( 3 ));
565 double L3 = getDistance(P( 3 ),P( 1 ));
566 double L4 = getDistance(P( 4 ),P( 5 ));
567 double L5 = getDistance(P( 5 ),P( 6 ));
568 double L6 = getDistance(P( 6 ),P( 4 ));
569 double L7 = getDistance(P( 1 ),P( 4 ));
570 double L8 = getDistance(P( 2 ),P( 5 ));
571 double L9 = getDistance(P( 3 ),P( 6 ));
572 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
573 aVal = Max(aVal,Max(Max(L7,L8),L9));
576 case SMDSEntity_Hexa: { // hexas
577 double L1 = getDistance(P( 1 ),P( 2 ));
578 double L2 = getDistance(P( 2 ),P( 3 ));
579 double L3 = getDistance(P( 3 ),P( 4 ));
580 double L4 = getDistance(P( 4 ),P( 1 ));
581 double L5 = getDistance(P( 5 ),P( 6 ));
582 double L6 = getDistance(P( 6 ),P( 7 ));
583 double L7 = getDistance(P( 7 ),P( 8 ));
584 double L8 = getDistance(P( 8 ),P( 5 ));
585 double L9 = getDistance(P( 1 ),P( 5 ));
586 double L10= getDistance(P( 2 ),P( 6 ));
587 double L11= getDistance(P( 3 ),P( 7 ));
588 double L12= getDistance(P( 4 ),P( 8 ));
589 double D1 = getDistance(P( 1 ),P( 7 ));
590 double D2 = getDistance(P( 2 ),P( 8 ));
591 double D3 = getDistance(P( 3 ),P( 5 ));
592 double D4 = getDistance(P( 4 ),P( 6 ));
593 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
594 aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
595 aVal = Max(aVal,Max(L11,L12));
596 aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
599 case SMDSEntity_Hexagonal_Prism: { // hexagonal prism
600 for ( int i1 = 1; i1 < 12; ++i1 )
601 for ( int i2 = i1+1; i1 <= 12; ++i1 )
602 aVal = Max( aVal, getDistance(P( i1 ),P( i2 )));
605 case SMDSEntity_Quad_Tetra: { // quadratic tetras
606 double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
607 double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
608 double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
609 double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
610 double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
611 double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
612 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
615 case SMDSEntity_Quad_Pyramid: { // quadratic pyramids
616 double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
617 double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
618 double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
619 double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
620 double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
621 double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
622 double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
623 double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
624 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
625 aVal = Max(aVal,Max(L7,L8));
628 case SMDSEntity_Quad_Penta:
629 case SMDSEntity_BiQuad_Penta: { // quadratic pentas
630 double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
631 double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
632 double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
633 double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
634 double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
635 double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
636 double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
637 double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
638 double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
639 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
640 aVal = Max(aVal,Max(Max(L7,L8),L9));
643 case SMDSEntity_Quad_Hexa:
644 case SMDSEntity_TriQuad_Hexa: { // quadratic hexas
645 double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
646 double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
647 double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
648 double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
649 double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
650 double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
651 double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
652 double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
653 double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
654 double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
655 double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
656 double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
657 double D1 = getDistance(P( 1 ),P( 7 ));
658 double D2 = getDistance(P( 2 ),P( 8 ));
659 double D3 = getDistance(P( 3 ),P( 5 ));
660 double D4 = getDistance(P( 4 ),P( 6 ));
661 aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
662 aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
663 aVal = Max(aVal,Max(L11,L12));
664 aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
667 case SMDSEntity_Quad_Polyhedra:
668 case SMDSEntity_Polyhedra: { // polys
669 // get the maximum distance between all pairs of nodes
670 for( int i = 1; i <= len; i++ ) {
671 for( int j = 1; j <= len; j++ ) {
672 if( j > i ) { // optimization of the loop
673 double D = getDistance( P(i), P(j) );
674 aVal = Max( aVal, D );
680 case SMDSEntity_Node:
682 case SMDSEntity_Edge:
683 case SMDSEntity_Quad_Edge:
684 case SMDSEntity_Triangle:
685 case SMDSEntity_Quad_Triangle:
686 case SMDSEntity_BiQuad_Triangle:
687 case SMDSEntity_Quadrangle:
688 case SMDSEntity_Quad_Quadrangle:
689 case SMDSEntity_BiQuad_Quadrangle:
690 case SMDSEntity_Polygon:
691 case SMDSEntity_Quad_Polygon:
692 case SMDSEntity_Ball:
693 case SMDSEntity_Last: return 0;
694 } // switch ( aType )
696 if( myPrecision >= 0 )
698 double prec = pow( 10., (double)myPrecision );
699 aVal = floor( aVal * prec + 0.5 ) / prec;
706 double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const
711 SMDSAbs_ElementType MaxElementLength3D::GetType() const
713 return SMDSAbs_Volume;
716 //=======================================================================
719 Description : Functor for calculation of minimum angle
721 //================================================================================
723 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
730 aMaxCos2 = getCos2( P( P.size() ), P( 1 ), P( 2 ));
731 aMaxCos2 = Max( aMaxCos2, getCos2( P( P.size()-1 ), P( P.size() ), P( 1 )));
733 for ( size_t i = 2; i < P.size(); i++ )
735 double A0 = getCos2( P( i-1 ), P( i ), P( i+1 ) );
736 aMaxCos2 = Max( aMaxCos2, A0 );
739 return 0; // all nodes coincide
741 double cos = sqrt( aMaxCos2 );
742 if ( cos >= 1 ) return 0;
743 return acos( cos ) * 180.0 / M_PI;
746 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
748 //const double aBestAngle = PI / nbNodes;
749 const double aBestAngle = 180.0 - ( 360.0 / double(nbNodes) );
750 return ( fabs( aBestAngle - Value ));
753 SMDSAbs_ElementType MinimumAngle::GetType() const
759 //================================================================================
762 Description : Functor for calculating aspect ratio
764 //================================================================================
766 double AspectRatio::GetValue( long theId )
769 myCurrElement = myMesh->FindElement( theId );
771 if ( GetPoints( myCurrElement, P ))
772 aVal = Round( GetValue( P ));
776 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
778 // According to "Mesh quality control" by Nadir Bouhamau referring to
779 // Pascal Jean Frey and Paul-Louis George. Maillages, applications aux elements finis.
780 // Hermes Science publications, Paris 1999 ISBN 2-7462-0024-4
783 int nbNodes = P.size();
788 // Compute aspect ratio
790 if ( nbNodes == 3 ) {
791 // Compute lengths of the sides
792 double aLen1 = getDistance( P( 1 ), P( 2 ));
793 double aLen2 = getDistance( P( 2 ), P( 3 ));
794 double aLen3 = getDistance( P( 3 ), P( 1 ));
795 // Q = alfa * h * p / S, where
797 // alfa = sqrt( 3 ) / 6
798 // h - length of the longest edge
799 // p - half perimeter
800 // S - triangle surface
801 const double alfa = sqrt( 3. ) / 6.;
802 double maxLen = Max( aLen1, Max( aLen2, aLen3 ));
803 double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.;
804 double anArea = getArea( P( 1 ), P( 2 ), P( 3 ));
805 if ( anArea <= theEps )
807 return alfa * maxLen * half_perimeter / anArea;
809 else if ( nbNodes == 6 ) { // quadratic triangles
810 // Compute lengths of the sides
811 double aLen1 = getDistance( P( 1 ), P( 3 ));
812 double aLen2 = getDistance( P( 3 ), P( 5 ));
813 double aLen3 = getDistance( P( 5 ), P( 1 ));
814 // algo same as for the linear triangle
815 const double alfa = sqrt( 3. ) / 6.;
816 double maxLen = Max( aLen1, Max( aLen2, aLen3 ));
817 double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.;
818 double anArea = getArea( P( 1 ), P( 3 ), P( 5 ));
819 if ( anArea <= theEps )
821 return alfa * maxLen * half_perimeter / anArea;
823 else if( nbNodes == 4 ) { // quadrangle
824 // Compute lengths of the sides
826 aLen[0] = getDistance( P(1), P(2) );
827 aLen[1] = getDistance( P(2), P(3) );
828 aLen[2] = getDistance( P(3), P(4) );
829 aLen[3] = getDistance( P(4), P(1) );
830 // Compute lengths of the diagonals
832 aDia[0] = getDistance( P(1), P(3) );
833 aDia[1] = getDistance( P(2), P(4) );
834 // Compute areas of all triangles which can be built
835 // taking three nodes of the quadrangle
837 anArea[0] = getArea( P(1), P(2), P(3) );
838 anArea[1] = getArea( P(1), P(2), P(4) );
839 anArea[2] = getArea( P(1), P(3), P(4) );
840 anArea[3] = getArea( P(2), P(3), P(4) );
841 // Q = alpha * L * C1 / C2, where
843 // alpha = sqrt( 1/32 )
844 // L = max( L1, L2, L3, L4, D1, D2 )
845 // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 )
846 // C2 = min( S1, S2, S3, S4 )
847 // Li - lengths of the edges
848 // Di - lengths of the diagonals
849 // Si - areas of the triangles
850 const double alpha = sqrt( 1 / 32. );
851 double L = Max( aLen[ 0 ],
855 Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
856 double C1 = sqrt( aLen[0] * aLen[0] +
860 double C2 = Min( anArea[ 0 ],
862 Min( anArea[ 2 ], anArea[ 3 ] ) ) );
865 return alpha * L * C1 / C2;
867 else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle
868 // Compute lengths of the sides
870 aLen[0] = getDistance( P(1), P(3) );
871 aLen[1] = getDistance( P(3), P(5) );
872 aLen[2] = getDistance( P(5), P(7) );
873 aLen[3] = getDistance( P(7), P(1) );
874 // Compute lengths of the diagonals
876 aDia[0] = getDistance( P(1), P(5) );
877 aDia[1] = getDistance( P(3), P(7) );
878 // Compute areas of all triangles which can be built
879 // taking three nodes of the quadrangle
881 anArea[0] = getArea( P(1), P(3), P(5) );
882 anArea[1] = getArea( P(1), P(3), P(7) );
883 anArea[2] = getArea( P(1), P(5), P(7) );
884 anArea[3] = getArea( P(3), P(5), P(7) );
885 // Q = alpha * L * C1 / C2, where
887 // alpha = sqrt( 1/32 )
888 // L = max( L1, L2, L3, L4, D1, D2 )
889 // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 )
890 // C2 = min( S1, S2, S3, S4 )
891 // Li - lengths of the edges
892 // Di - lengths of the diagonals
893 // Si - areas of the triangles
894 const double alpha = sqrt( 1 / 32. );
895 double L = Max( aLen[ 0 ],
899 Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
900 double C1 = sqrt( aLen[0] * aLen[0] +
904 double C2 = Min( anArea[ 0 ],
906 Min( anArea[ 2 ], anArea[ 3 ] ) ) );
909 return alpha * L * C1 / C2;
914 bool AspectRatio::IsApplicable( const SMDS_MeshElement* element ) const
916 return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
919 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
921 // the aspect ratio is in the range [1.0,infinity]
922 // < 1.0 = very bad, zero area
925 return ( Value < 0.9 ) ? 1000 : Value / 1000.;
928 SMDSAbs_ElementType AspectRatio::GetType() const
934 //================================================================================
936 Class : AspectRatio3D
937 Description : Functor for calculating aspect ratio
939 //================================================================================
943 inline double getHalfPerimeter(double theTria[3]){
944 return (theTria[0] + theTria[1] + theTria[2])/2.0;
947 inline double getArea(double theHalfPerim, double theTria[3]){
948 return sqrt(theHalfPerim*
949 (theHalfPerim-theTria[0])*
950 (theHalfPerim-theTria[1])*
951 (theHalfPerim-theTria[2]));
954 inline double getVolume(double theLen[6]){
955 double a2 = theLen[0]*theLen[0];
956 double b2 = theLen[1]*theLen[1];
957 double c2 = theLen[2]*theLen[2];
958 double d2 = theLen[3]*theLen[3];
959 double e2 = theLen[4]*theLen[4];
960 double f2 = theLen[5]*theLen[5];
961 double P = 4.0*a2*b2*d2;
962 double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
963 double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
964 return sqrt(P-Q+R)/12.0;
967 inline double getVolume2(double theLen[6]){
968 double a2 = theLen[0]*theLen[0];
969 double b2 = theLen[1]*theLen[1];
970 double c2 = theLen[2]*theLen[2];
971 double d2 = theLen[3]*theLen[3];
972 double e2 = theLen[4]*theLen[4];
973 double f2 = theLen[5]*theLen[5];
975 double P = a2*e2*(b2+c2+d2+f2-a2-e2);
976 double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
977 double R = c2*d2*(a2+b2+e2+f2-c2-d2);
978 double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
980 return sqrt(P+Q+R-S)/12.0;
983 inline double getVolume(const TSequenceOfXYZ& P){
984 gp_Vec aVec1( P( 2 ) - P( 1 ) );
985 gp_Vec aVec2( P( 3 ) - P( 1 ) );
986 gp_Vec aVec3( P( 4 ) - P( 1 ) );
987 gp_Vec anAreaVec( aVec1 ^ aVec2 );
988 return fabs(aVec3 * anAreaVec) / 6.0;
991 inline double getMaxHeight(double theLen[6])
993 double aHeight = std::max(theLen[0],theLen[1]);
994 aHeight = std::max(aHeight,theLen[2]);
995 aHeight = std::max(aHeight,theLen[3]);
996 aHeight = std::max(aHeight,theLen[4]);
997 aHeight = std::max(aHeight,theLen[5]);
1001 //================================================================================
1003 * \brief Standard quality of a tetrahedron but not normalized
1005 //================================================================================
1007 double tetQualityByHomardMethod( const gp_XYZ & p1,
1013 edgeVec[0] = ( p1 - p2 );
1014 edgeVec[1] = ( p2 - p3 );
1015 edgeVec[2] = ( p3 - p1 );
1016 edgeVec[3] = ( p4 - p1 );
1017 edgeVec[4] = ( p4 - p2 );
1018 edgeVec[5] = ( p4 - p3 );
1020 double maxEdgeLen2 = edgeVec[0].SquareModulus();
1021 maxEdgeLen2 = Max( maxEdgeLen2, edgeVec[1].SquareModulus() );
1022 maxEdgeLen2 = Max( maxEdgeLen2, edgeVec[2].SquareModulus() );
1023 maxEdgeLen2 = Max( maxEdgeLen2, edgeVec[3].SquareModulus() );
1024 maxEdgeLen2 = Max( maxEdgeLen2, edgeVec[4].SquareModulus() );
1025 maxEdgeLen2 = Max( maxEdgeLen2, edgeVec[5].SquareModulus() );
1026 double maxEdgeLen = Sqrt( maxEdgeLen2 );
1028 gp_XYZ cross01 = edgeVec[0] ^ edgeVec[1];
1029 double sumArea = ( cross01 ).Modulus(); // actually double area
1030 sumArea += ( edgeVec[0] ^ edgeVec[3] ).Modulus();
1031 sumArea += ( edgeVec[1] ^ edgeVec[4] ).Modulus();
1032 sumArea += ( edgeVec[2] ^ edgeVec[5] ).Modulus();
1034 double sixVolume = Abs( cross01 * edgeVec[4] ); // 6 * volume
1035 double quality = maxEdgeLen * sumArea / sixVolume; // not normalized!!!
1039 //================================================================================
1041 * \brief HOMARD method of hexahedron quality
1042 * 1. Decompose the hexa into 24 tetra: each face is splitted into 4 triangles by
1043 * adding the diagonals and every triangle is connected to the center of the hexa.
1044 * 2. Compute the quality of every tetra with the same formula as for the standard quality,
1045 * except that the factor for the normalization is not the same because the final goal
1046 * is to have a quality equal to 1 for a perfect cube. So the formula is:
1047 * qual = max(lengthes of 6 edges) * (sum of surfaces of 4 faces) / (7.6569*6*volume)
1048 * 3. The quality of the hexa is the highest value of the qualities of the 24 tetra
1050 //================================================================================
1052 double hexQualityByHomardMethod( const TSequenceOfXYZ& P )
1054 gp_XYZ quadCenter[6];
1055 quadCenter[0] = ( P(1) + P(2) + P(3) + P(4) ) / 4.;
1056 quadCenter[1] = ( P(5) + P(6) + P(7) + P(8) ) / 4.;
1057 quadCenter[2] = ( P(1) + P(2) + P(6) + P(5) ) / 4.;
1058 quadCenter[3] = ( P(2) + P(3) + P(7) + P(6) ) / 4.;
1059 quadCenter[4] = ( P(3) + P(4) + P(8) + P(7) ) / 4.;
1060 quadCenter[5] = ( P(1) + P(4) + P(8) + P(5) ) / 4.;
1062 gp_XYZ hexCenter = ( P(1) + P(2) + P(3) + P(4) + P(5) + P(6) + P(7) + P(8) ) / 8.;
1064 // quad 1 ( 1 2 3 4 )
1065 double quality = tetQualityByHomardMethod( P(1), P(2), quadCenter[0], hexCenter );
1066 quality = Max( quality, tetQualityByHomardMethod( P(2), P(3), quadCenter[0], hexCenter ));
1067 quality = Max( quality, tetQualityByHomardMethod( P(3), P(4), quadCenter[0], hexCenter ));
1068 quality = Max( quality, tetQualityByHomardMethod( P(4), P(1), quadCenter[0], hexCenter ));
1069 // quad 2 ( 5 6 7 8 )
1070 quality = Max( quality, tetQualityByHomardMethod( P(5), P(6), quadCenter[1], hexCenter ));
1071 quality = Max( quality, tetQualityByHomardMethod( P(6), P(7), quadCenter[1], hexCenter ));
1072 quality = Max( quality, tetQualityByHomardMethod( P(7), P(8), quadCenter[1], hexCenter ));
1073 quality = Max( quality, tetQualityByHomardMethod( P(8), P(5), quadCenter[1], hexCenter ));
1074 // quad 3 ( 1 2 6 5 )
1075 quality = Max( quality, tetQualityByHomardMethod( P(1), P(2), quadCenter[2], hexCenter ));
1076 quality = Max( quality, tetQualityByHomardMethod( P(2), P(6), quadCenter[2], hexCenter ));
1077 quality = Max( quality, tetQualityByHomardMethod( P(6), P(5), quadCenter[2], hexCenter ));
1078 quality = Max( quality, tetQualityByHomardMethod( P(5), P(1), quadCenter[2], hexCenter ));
1079 // quad 4 ( 2 3 7 6 )
1080 quality = Max( quality, tetQualityByHomardMethod( P(2), P(3), quadCenter[3], hexCenter ));
1081 quality = Max( quality, tetQualityByHomardMethod( P(3), P(7), quadCenter[3], hexCenter ));
1082 quality = Max( quality, tetQualityByHomardMethod( P(7), P(6), quadCenter[3], hexCenter ));
1083 quality = Max( quality, tetQualityByHomardMethod( P(6), P(2), quadCenter[3], hexCenter ));
1084 // quad 5 ( 3 4 8 7 )
1085 quality = Max( quality, tetQualityByHomardMethod( P(3), P(4), quadCenter[4], hexCenter ));
1086 quality = Max( quality, tetQualityByHomardMethod( P(4), P(8), quadCenter[4], hexCenter ));
1087 quality = Max( quality, tetQualityByHomardMethod( P(8), P(7), quadCenter[4], hexCenter ));
1088 quality = Max( quality, tetQualityByHomardMethod( P(7), P(3), quadCenter[4], hexCenter ));
1089 // quad 6 ( 1 4 8 5 )
1090 quality = Max( quality, tetQualityByHomardMethod( P(1), P(4), quadCenter[5], hexCenter ));
1091 quality = Max( quality, tetQualityByHomardMethod( P(4), P(8), quadCenter[5], hexCenter ));
1092 quality = Max( quality, tetQualityByHomardMethod( P(8), P(5), quadCenter[5], hexCenter ));
1093 quality = Max( quality, tetQualityByHomardMethod( P(5), P(1), quadCenter[5], hexCenter ));
1095 return quality / 7.65685424949;
1099 double AspectRatio3D::GetValue( long theId )
1102 myCurrElement = myMesh->FindElement( theId );
1103 if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA )
1105 // Action from CoTech | ACTION 31.3:
1106 // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with
1107 // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH.
1108 vtkUnstructuredGrid* grid = const_cast<SMDS_Mesh*>( myMesh )->GetGrid();
1109 if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() ))
1110 aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell ));
1115 if ( GetPoints( myCurrElement, P ))
1116 aVal = Round( GetValue( P ));
1121 bool AspectRatio3D::IsApplicable( const SMDS_MeshElement* element ) const
1123 return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
1126 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
1128 double aQuality = 0.0;
1129 if(myCurrElement->IsPoly()) return aQuality;
1131 int nbNodes = P.size();
1133 if( myCurrElement->IsQuadratic() ) {
1134 if (nbNodes==10) nbNodes=4; // quadratic tetrahedron
1135 else if(nbNodes==13) nbNodes=5; // quadratic pyramid
1136 else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
1137 else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
1138 else if(nbNodes==27) nbNodes=8; // tri-quadratic hexahedron
1139 else return aQuality;
1145 getDistance(P( 1 ),P( 2 )), // a
1146 getDistance(P( 2 ),P( 3 )), // b
1147 getDistance(P( 3 ),P( 1 )), // c
1148 getDistance(P( 2 ),P( 4 )), // d
1149 getDistance(P( 3 ),P( 4 )), // e
1150 getDistance(P( 1 ),P( 4 )) // f
1152 double aTria[4][3] = {
1153 {aLen[0],aLen[1],aLen[2]}, // abc
1154 {aLen[0],aLen[3],aLen[5]}, // adf
1155 {aLen[1],aLen[3],aLen[4]}, // bde
1156 {aLen[2],aLen[4],aLen[5]} // cef
1158 double aSumArea = 0.0;
1159 double aHalfPerimeter = getHalfPerimeter(aTria[0]);
1160 double anArea = getArea(aHalfPerimeter,aTria[0]);
1162 aHalfPerimeter = getHalfPerimeter(aTria[1]);
1163 anArea = getArea(aHalfPerimeter,aTria[1]);
1165 aHalfPerimeter = getHalfPerimeter(aTria[2]);
1166 anArea = getArea(aHalfPerimeter,aTria[2]);
1168 aHalfPerimeter = getHalfPerimeter(aTria[3]);
1169 anArea = getArea(aHalfPerimeter,aTria[3]);
1171 double aVolume = getVolume(P);
1172 //double aVolume = getVolume(aLen);
1173 double aHeight = getMaxHeight(aLen);
1174 static double aCoeff = sqrt(2.0)/12.0;
1175 if ( aVolume > DBL_MIN )
1176 aQuality = aCoeff*aHeight*aSumArea/aVolume;
1181 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
1182 aQuality = GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4]));
1185 gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
1186 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1189 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
1190 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1193 gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
1194 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1200 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
1201 aQuality = GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4]));
1204 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
1205 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1208 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
1209 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1212 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1213 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1216 gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
1217 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1220 gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
1221 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1227 return hexQualityByHomardMethod( P ); // bos #23982
1231 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
1232 aQuality = GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4]));
1235 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
1236 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1239 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
1240 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1243 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
1244 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1247 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
1248 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1251 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
1252 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1255 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
1256 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1259 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
1260 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1263 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
1264 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1267 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
1268 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1271 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
1272 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1275 gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
1276 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1279 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
1280 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1283 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
1284 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1287 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
1288 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1291 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
1292 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1295 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
1296 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1299 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
1300 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1303 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
1304 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1307 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
1308 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1311 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
1312 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1315 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1316 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1319 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
1320 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1323 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
1324 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1327 gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
1328 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1331 gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
1332 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1335 gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
1336 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1339 gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
1340 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1343 gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
1344 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1347 gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
1348 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1351 gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
1352 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1355 gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
1356 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1359 gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
1360 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
1366 gp_XYZ aXYZ[8] = {P( 1 ),P( 2 ),P( 4 ),P( 5 ),P( 7 ),P( 8 ),P( 10 ),P( 11 )};
1367 aQuality = GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8]));
1370 gp_XYZ aXYZ[8] = {P( 2 ),P( 3 ),P( 5 ),P( 6 ),P( 8 ),P( 9 ),P( 11 ),P( 12 )};
1371 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1374 gp_XYZ aXYZ[8] = {P( 3 ),P( 4 ),P( 6 ),P( 1 ),P( 9 ),P( 10 ),P( 12 ),P( 7 )};
1375 aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality);
1378 } // switch(nbNodes)
1380 if ( nbNodes > 4 ) {
1381 // evaluate aspect ratio of quadrangle faces
1382 AspectRatio aspect2D;
1383 SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes );
1384 int nbFaces = SMDS_VolumeTool::NbFaces( type );
1385 TSequenceOfXYZ points(4);
1386 for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume
1387 if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 )
1389 const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true );
1390 for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadrangle face
1391 points( p + 1 ) = P( pInd[ p ] + 1 );
1392 aQuality = std::max( aQuality, aspect2D.GetValue( points ));
1398 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
1400 // the aspect ratio is in the range [1.0,infinity]
1403 return Value / 1000.;
1406 SMDSAbs_ElementType AspectRatio3D::GetType() const
1408 return SMDSAbs_Volume;
1412 //================================================================================
1415 Description : Functor for calculating warping
1417 //================================================================================
1419 bool Warping::IsApplicable( const SMDS_MeshElement* element ) const
1421 return NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4;
1424 double Warping::GetValue( const TSequenceOfXYZ& P )
1426 return ComputeValue(P);
1429 double Warping::ComputeA( const gp_XYZ& thePnt1,
1430 const gp_XYZ& thePnt2,
1431 const gp_XYZ& thePnt3,
1432 const gp_XYZ& theG ) const
1434 double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
1435 double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
1436 double L = Min( aLen1, aLen2 ) * 0.5;
1440 gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG;
1441 gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG;
1442 gp_XYZ N = GI.Crossed( GJ );
1444 if ( N.Modulus() < gp::Resolution() )
1449 double H = ( thePnt2 - theG ).Dot( N );
1450 return asin( fabs( H / L ) ) * 180. / M_PI;
1453 double Warping::ComputeValue(const TSequenceOfXYZ& thePoints) const
1455 if (thePoints.size() != 4)
1458 gp_XYZ G = (thePoints(1) + thePoints(2) + thePoints(3) + thePoints(4)) / 4.;
1460 double A1 = ComputeA(thePoints(1), thePoints(2), thePoints(3), G);
1461 double A2 = ComputeA(thePoints(2), thePoints(3), thePoints(4), G);
1462 double A3 = ComputeA(thePoints(3), thePoints(4), thePoints(1), G);
1463 double A4 = ComputeA(thePoints(4), thePoints(1), thePoints(2), G);
1465 double val = Max(Max(A1, A2), Max(A3, A4));
1467 const double eps = 0.1; // val is in degrees
1469 return val < eps ? 0. : val;
1472 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
1474 // the warp is in the range [0.0,PI/2]
1475 // 0.0 = good (no warp)
1476 // PI/2 = bad (face pliee)
1480 SMDSAbs_ElementType Warping::GetType() const
1482 return SMDSAbs_Face;
1486 //================================================================================
1489 Description : Functor for calculating warping
1491 //================================================================================
1493 bool Warping3D::IsApplicable(const SMDS_MeshElement* element) const
1495 return NumericalFunctor::IsApplicable(element);//&& element->NbNodes() == 4;
1498 double Warping3D::GetValue(long theId)
1501 myCurrElement = myMesh->FindElement(theId);
1505 ProcessVolumeELement(aValues);
1506 for (const auto& aValue: aValues)
1508 aVal = Max(aVal, aValue.myWarp);
1514 double Warping3D::GetValue(const TSequenceOfXYZ& P)
1516 return ComputeValue(P);
1519 SMDSAbs_ElementType Warping3D::GetType() const
1521 return SMDSAbs_Volume;
1524 bool Warping3D::Value::operator<(const Warping3D::Value& x) const
1526 if (myPntIds.size() != x.myPntIds.size())
1527 return myPntIds.size() < x.myPntIds.size();
1529 for (int anInd = 0; anInd < myPntIds.size(); ++anInd)
1530 if (myPntIds[anInd] != x.myPntIds[anInd])
1531 return myPntIds[anInd] != x.myPntIds[anInd];
1536 // Compute value on each face of volume
1537 void Warping3D::ProcessVolumeELement(WValues& theValues)
1539 SMDS_VolumeTool aVTool(myCurrElement);
1541 for (int aFaceID = 0; aFaceID < aVTool.NbFaces(); ++aFaceID)
1543 TSequenceOfXYZ aPoints;
1544 std::set<const SMDS_MeshNode*> aNodes;
1545 std::vector<long> aNodeIds;
1546 const SMDS_MeshNode** aNodesPtr = aVTool.GetFaceNodes(aFaceID);
1550 for (int i = 0; i < aVTool.NbFaceNodes(aFaceID); ++i)
1552 aNodesPtr[i]->GetXYZ(aCoord);
1553 aPoints.push_back(gp_XYZ{ aCoord[0], aCoord[1], aCoord[2] });
1554 aNodeIds.push_back(aNodesPtr[i]->GetID());
1556 double aWarp = GetValue(aPoints);
1557 Value aVal{ aWarp, aNodeIds };
1559 theValues.push_back(aVal);
1564 void Warping3D::GetValues(WValues& theValues)
1566 for (SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); anIter->more(); )
1568 myCurrElement = anIter->next();
1569 ProcessVolumeELement(theValues);
1573 //================================================================================
1576 Description : Functor for calculating taper
1578 //================================================================================
1580 bool Taper::IsApplicable( const SMDS_MeshElement* element ) const
1582 return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4 );
1585 double Taper::GetValue( const TSequenceOfXYZ& P )
1587 if ( P.size() != 4 )
1591 double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) );
1592 double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) );
1593 double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) );
1594 double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) );
1596 double JA = 0.25 * ( J1 + J2 + J3 + J4 );
1600 double T1 = fabs( ( J1 - JA ) / JA );
1601 double T2 = fabs( ( J2 - JA ) / JA );
1602 double T3 = fabs( ( J3 - JA ) / JA );
1603 double T4 = fabs( ( J4 - JA ) / JA );
1605 double val = Max( Max( T1, T2 ), Max( T3, T4 ) );
1607 const double eps = 0.01;
1609 return val < eps ? 0. : val;
1612 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
1614 // the taper is in the range [0.0,1.0]
1615 // 0.0 = good (no taper)
1616 // 1.0 = bad (les cotes opposes sont allignes)
1620 SMDSAbs_ElementType Taper::GetType() const
1622 return SMDSAbs_Face;
1625 //================================================================================
1628 Description : Functor for calculating skew in degrees
1630 //================================================================================
1632 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
1634 gp_XYZ p12 = ( p2 + p1 ) / 2.;
1635 gp_XYZ p23 = ( p3 + p2 ) / 2.;
1636 gp_XYZ p31 = ( p3 + p1 ) / 2.;
1638 gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
1640 return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
1643 bool Skew::IsApplicable( const SMDS_MeshElement* element ) const
1645 return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() <= 4 );
1648 double Skew::GetValue( const TSequenceOfXYZ& P )
1650 if ( P.size() != 3 && P.size() != 4 )
1654 const double PI2 = M_PI / 2.;
1655 if ( P.size() == 3 )
1657 double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
1658 double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
1659 double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
1661 return Max( A0, Max( A1, A2 ) ) * 180. / M_PI;
1665 gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2.;
1666 gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2.;
1667 gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2.;
1668 gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2.;
1670 gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
1671 double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
1672 ? 0. : fabs( PI2 - v1.Angle( v2 ) );
1674 double val = A * 180. / M_PI;
1676 const double eps = 0.1; // val is in degrees
1678 return val < eps ? 0. : val;
1682 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
1684 // the skew is in the range [0.0,PI/2].
1690 SMDSAbs_ElementType Skew::GetType() const
1692 return SMDSAbs_Face;
1696 //================================================================================
1699 Description : Functor for calculating area
1701 //================================================================================
1703 double Area::GetValue( const TSequenceOfXYZ& P )
1708 gp_Vec aVec1( P(2) - P(1) );
1709 gp_Vec aVec2( P(3) - P(1) );
1710 gp_Vec SumVec = aVec1 ^ aVec2;
1712 for (size_t i=4; i<=P.size(); i++)
1714 gp_Vec aVec1( P(i-1) - P(1) );
1715 gp_Vec aVec2( P(i ) - P(1) );
1716 gp_Vec tmp = aVec1 ^ aVec2;
1719 val = SumVec.Magnitude() * 0.5;
1724 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
1726 // meaningless as it is not a quality control functor
1730 SMDSAbs_ElementType Area::GetType() const
1732 return SMDSAbs_Face;
1735 //================================================================================
1738 Description : Functor for calculating length of edge
1740 //================================================================================
1742 double Length::GetValue( const TSequenceOfXYZ& P )
1744 switch ( P.size() ) {
1745 case 2: return getDistance( P( 1 ), P( 2 ) );
1746 case 3: return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) );
1751 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
1753 // meaningless as it is not quality control functor
1757 SMDSAbs_ElementType Length::GetType() const
1759 return SMDSAbs_Edge;
1762 //================================================================================
1765 Description : Functor for calculating minimal length of element edge
1767 //================================================================================
1769 Length3D::Length3D():
1770 Length2D ( SMDSAbs_Volume )
1774 //================================================================================
1777 Description : Functor for calculating minimal length of element edge
1779 //================================================================================
1781 Length2D::Length2D( SMDSAbs_ElementType type ):
1786 bool Length2D::IsApplicable( const SMDS_MeshElement* element ) const
1788 return ( NumericalFunctor::IsApplicable( element ) &&
1789 element->GetEntityType() != SMDSEntity_Polyhedra );
1792 double Length2D::GetValue( const TSequenceOfXYZ& P )
1796 SMDSAbs_EntityType aType = P.getElementEntity();
1799 case SMDSEntity_Edge:
1801 aVal = getDistance( P( 1 ), P( 2 ) );
1803 case SMDSEntity_Quad_Edge:
1804 if (len == 3) // quadratic edge
1805 aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
1807 case SMDSEntity_Triangle:
1808 if (len == 3){ // triangles
1809 double L1 = getDistance(P( 1 ),P( 2 ));
1810 double L2 = getDistance(P( 2 ),P( 3 ));
1811 double L3 = getDistance(P( 3 ),P( 1 ));
1812 aVal = Min(L1,Min(L2,L3));
1815 case SMDSEntity_Quadrangle:
1816 if (len == 4){ // quadrangles
1817 double L1 = getDistance(P( 1 ),P( 2 ));
1818 double L2 = getDistance(P( 2 ),P( 3 ));
1819 double L3 = getDistance(P( 3 ),P( 4 ));
1820 double L4 = getDistance(P( 4 ),P( 1 ));
1821 aVal = Min(Min(L1,L2),Min(L3,L4));
1824 case SMDSEntity_Quad_Triangle:
1825 case SMDSEntity_BiQuad_Triangle:
1826 if (len >= 6){ // quadratic triangles
1827 double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1828 double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1829 double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
1830 aVal = Min(L1,Min(L2,L3));
1833 case SMDSEntity_Quad_Quadrangle:
1834 case SMDSEntity_BiQuad_Quadrangle:
1835 if (len >= 8){ // quadratic quadrangles
1836 double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
1837 double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
1838 double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
1839 double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
1840 aVal = Min(Min(L1,L2),Min(L3,L4));
1843 case SMDSEntity_Tetra:
1844 if (len == 4){ // tetrahedra
1845 double L1 = getDistance(P( 1 ),P( 2 ));
1846 double L2 = getDistance(P( 2 ),P( 3 ));
1847 double L3 = getDistance(P( 3 ),P( 1 ));
1848 double L4 = getDistance(P( 1 ),P( 4 ));
1849 double L5 = getDistance(P( 2 ),P( 4 ));
1850 double L6 = getDistance(P( 3 ),P( 4 ));
1851 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1854 case SMDSEntity_Pyramid:
1855 if (len == 5){ // pyramid
1856 double L1 = getDistance(P( 1 ),P( 2 ));
1857 double L2 = getDistance(P( 2 ),P( 3 ));
1858 double L3 = getDistance(P( 3 ),P( 4 ));
1859 double L4 = getDistance(P( 4 ),P( 1 ));
1860 double L5 = getDistance(P( 1 ),P( 5 ));
1861 double L6 = getDistance(P( 2 ),P( 5 ));
1862 double L7 = getDistance(P( 3 ),P( 5 ));
1863 double L8 = getDistance(P( 4 ),P( 5 ));
1865 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1866 aVal = Min(aVal,Min(L7,L8));
1869 case SMDSEntity_Penta:
1870 if (len == 6) { // pentahedron
1871 double L1 = getDistance(P( 1 ),P( 2 ));
1872 double L2 = getDistance(P( 2 ),P( 3 ));
1873 double L3 = getDistance(P( 3 ),P( 1 ));
1874 double L4 = getDistance(P( 4 ),P( 5 ));
1875 double L5 = getDistance(P( 5 ),P( 6 ));
1876 double L6 = getDistance(P( 6 ),P( 4 ));
1877 double L7 = getDistance(P( 1 ),P( 4 ));
1878 double L8 = getDistance(P( 2 ),P( 5 ));
1879 double L9 = getDistance(P( 3 ),P( 6 ));
1881 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1882 aVal = Min(aVal,Min(Min(L7,L8),L9));
1885 case SMDSEntity_Hexa:
1886 if (len == 8){ // hexahedron
1887 double L1 = getDistance(P( 1 ),P( 2 ));
1888 double L2 = getDistance(P( 2 ),P( 3 ));
1889 double L3 = getDistance(P( 3 ),P( 4 ));
1890 double L4 = getDistance(P( 4 ),P( 1 ));
1891 double L5 = getDistance(P( 5 ),P( 6 ));
1892 double L6 = getDistance(P( 6 ),P( 7 ));
1893 double L7 = getDistance(P( 7 ),P( 8 ));
1894 double L8 = getDistance(P( 8 ),P( 5 ));
1895 double L9 = getDistance(P( 1 ),P( 5 ));
1896 double L10= getDistance(P( 2 ),P( 6 ));
1897 double L11= getDistance(P( 3 ),P( 7 ));
1898 double L12= getDistance(P( 4 ),P( 8 ));
1900 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1901 aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1902 aVal = Min(aVal,Min(L11,L12));
1905 case SMDSEntity_Quad_Tetra:
1906 if (len == 10){ // quadratic tetrahedron
1907 double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
1908 double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
1909 double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
1910 double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1911 double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
1912 double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
1913 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1916 case SMDSEntity_Quad_Pyramid:
1917 if (len == 13){ // quadratic pyramid
1918 double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
1919 double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
1920 double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
1921 double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1922 double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1923 double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
1924 double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
1925 double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
1926 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1927 aVal = Min(aVal,Min(L7,L8));
1930 case SMDSEntity_Quad_Penta:
1931 case SMDSEntity_BiQuad_Penta:
1932 if (len >= 15){ // quadratic pentahedron
1933 double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
1934 double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
1935 double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
1936 double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
1937 double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
1938 double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
1939 double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
1940 double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
1941 double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
1942 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1943 aVal = Min(aVal,Min(Min(L7,L8),L9));
1946 case SMDSEntity_Quad_Hexa:
1947 case SMDSEntity_TriQuad_Hexa:
1948 if (len >= 20) { // quadratic hexahedron
1949 double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
1950 double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
1951 double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
1952 double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
1953 double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
1954 double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
1955 double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
1956 double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
1957 double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
1958 double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
1959 double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
1960 double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
1961 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
1962 aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
1963 aVal = Min(aVal,Min(L11,L12));
1966 case SMDSEntity_Polygon:
1968 aVal = getDistance( P(1), P( P.size() ));
1969 for ( size_t i = 1; i < P.size(); ++i )
1970 aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
1973 case SMDSEntity_Quad_Polygon:
1975 aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
1976 for ( size_t i = 1; i < P.size()-1; i += 2 )
1977 aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
1980 case SMDSEntity_Hexagonal_Prism:
1981 if (len == 12) { // hexagonal prism
1982 double L1 = getDistance(P( 1 ),P( 2 ));
1983 double L2 = getDistance(P( 2 ),P( 3 ));
1984 double L3 = getDistance(P( 3 ),P( 4 ));
1985 double L4 = getDistance(P( 4 ),P( 5 ));
1986 double L5 = getDistance(P( 5 ),P( 6 ));
1987 double L6 = getDistance(P( 6 ),P( 1 ));
1989 double L7 = getDistance(P( 7 ), P( 8 ));
1990 double L8 = getDistance(P( 8 ), P( 9 ));
1991 double L9 = getDistance(P( 9 ), P( 10 ));
1992 double L10= getDistance(P( 10 ),P( 11 ));
1993 double L11= getDistance(P( 11 ),P( 12 ));
1994 double L12= getDistance(P( 12 ),P( 7 ));
1996 double L13 = getDistance(P( 1 ),P( 7 ));
1997 double L14 = getDistance(P( 2 ),P( 8 ));
1998 double L15 = getDistance(P( 3 ),P( 9 ));
1999 double L16 = getDistance(P( 4 ),P( 10 ));
2000 double L17 = getDistance(P( 5 ),P( 11 ));
2001 double L18 = getDistance(P( 6 ),P( 12 ));
2002 aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
2003 aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
2004 aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
2007 case SMDSEntity_Polyhedra:
2019 if ( myPrecision >= 0 )
2021 double prec = pow( 10., (double)( myPrecision ) );
2022 aVal = floor( aVal * prec + 0.5 ) / prec;
2028 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2030 // meaningless as it is not a quality control functor
2034 SMDSAbs_ElementType Length2D::GetType() const
2039 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
2042 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
2043 if(thePntId1 > thePntId2){
2044 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
2048 bool Length2D::Value::operator<(const Length2D::Value& x) const
2050 if(myPntId[0] < x.myPntId[0]) return true;
2051 if(myPntId[0] == x.myPntId[0])
2052 if(myPntId[1] < x.myPntId[1]) return true;
2056 void Length2D::GetValues(TValues& theValues)
2058 if ( myType == SMDSAbs_Face )
2060 for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
2062 const SMDS_MeshFace* anElem = anIter->next();
2063 if ( anElem->IsQuadratic() )
2065 // use special nodes iterator
2066 SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
2067 smIdType aNodeId[4] = { 0,0,0,0 };
2071 if ( anIter->more() )
2073 const SMDS_MeshNode* aNode = anIter->next();
2074 P[0] = P[1] = SMESH_NodeXYZ( aNode );
2075 aNodeId[0] = aNodeId[1] = aNode->GetID();
2078 for ( ; anIter->more(); )
2080 const SMDS_MeshNode* N1 = anIter->next();
2081 P[2] = SMESH_NodeXYZ( N1 );
2082 aNodeId[2] = N1->GetID();
2083 aLength = P[1].Distance(P[2]);
2084 if(!anIter->more()) break;
2085 const SMDS_MeshNode* N2 = anIter->next();
2086 P[3] = SMESH_NodeXYZ( N2 );
2087 aNodeId[3] = N2->GetID();
2088 aLength += P[2].Distance(P[3]);
2089 Value aValue1(aLength,aNodeId[1],aNodeId[2]);
2090 Value aValue2(aLength,aNodeId[2],aNodeId[3]);
2092 aNodeId[1] = aNodeId[3];
2093 theValues.insert(aValue1);
2094 theValues.insert(aValue2);
2096 aLength += P[2].Distance(P[0]);
2097 Value aValue1(aLength,aNodeId[1],aNodeId[2]);
2098 Value aValue2(aLength,aNodeId[2],aNodeId[0]);
2099 theValues.insert(aValue1);
2100 theValues.insert(aValue2);
2103 SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
2104 smIdType aNodeId[2] = {0,0};
2108 const SMDS_MeshElement* aNode;
2109 if ( aNodesIter->more())
2111 aNode = aNodesIter->next();
2112 P[0] = P[1] = SMESH_NodeXYZ( aNode );
2113 aNodeId[0] = aNodeId[1] = aNode->GetID();
2116 for( ; aNodesIter->more(); )
2118 aNode = aNodesIter->next();
2119 smIdType anId = aNode->GetID();
2121 P[2] = SMESH_NodeXYZ( aNode );
2123 aLength = P[1].Distance(P[2]);
2125 Value aValue(aLength,aNodeId[1],anId);
2128 theValues.insert(aValue);
2131 aLength = P[0].Distance(P[1]);
2133 Value aValue(aLength,aNodeId[0],aNodeId[1]);
2134 theValues.insert(aValue);
2144 //================================================================================
2146 Class : Deflection2D
2147 Description : computes distance between a face center and an underlying surface
2149 //================================================================================
2151 double Deflection2D::GetValue( const TSequenceOfXYZ& P )
2153 if ( myMesh && P.getElement() )
2155 // get underlying surface
2156 if ( myShapeIndex != P.getElement()->getshapeId() )
2158 mySurface.Nullify();
2159 myShapeIndex = P.getElement()->getshapeId();
2160 const TopoDS_Shape& S =
2161 static_cast< const SMESHDS_Mesh* >( myMesh )->IndexToShape( myShapeIndex );
2162 if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
2164 mySurface = new ShapeAnalysis_Surface( BRep_Tool::Surface( TopoDS::Face( S )));
2166 GeomLib_IsPlanarSurface isPlaneCheck( mySurface->Surface() );
2167 if ( isPlaneCheck.IsPlanar() )
2168 myPlane.reset( new gp_Pln( isPlaneCheck.Plan() ));
2173 // project gravity center to the surface
2174 if ( !mySurface.IsNull() )
2179 for ( size_t i = 0; i < P.size(); ++i )
2183 if ( SMDS_FacePositionPtr fPos = P.getElement()->GetNode( i )->GetPosition() )
2185 uv.ChangeCoord(1) += fPos->GetUParameter();
2186 uv.ChangeCoord(2) += fPos->GetVParameter();
2191 if ( nbUV ) uv /= nbUV;
2193 double maxLen = MaxElementLength2D().GetValue( P );
2194 double tol = 1e-3 * maxLen;
2198 dist = myPlane->Distance( gc );
2204 if ( uv.X() != 0 && uv.Y() != 0 ) // faster way
2205 mySurface->NextValueOfUV( uv, gc, tol, 0.5 * maxLen );
2207 mySurface->ValueOfUV( gc, tol );
2208 dist = mySurface->Gap();
2210 return Round( dist );
2216 void Deflection2D::SetMesh( const SMDS_Mesh* theMesh )
2218 NumericalFunctor::SetMesh( dynamic_cast<const SMESHDS_Mesh* >( theMesh ));
2219 myShapeIndex = -100;
2223 SMDSAbs_ElementType Deflection2D::GetType() const
2225 return SMDSAbs_Face;
2228 double Deflection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2230 // meaningless as it is not quality control functor
2234 //================================================================================
2236 Class : MultiConnection
2237 Description : Functor for calculating number of faces conneted to the edge
2239 //================================================================================
2241 double MultiConnection::GetValue( const TSequenceOfXYZ& /*P*/ )
2245 double MultiConnection::GetValue( long theId )
2247 return getNbMultiConnection( myMesh, theId );
2250 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
2252 // meaningless as it is not quality control functor
2256 SMDSAbs_ElementType MultiConnection::GetType() const
2258 return SMDSAbs_Edge;
2261 //================================================================================
2263 Class : MultiConnection2D
2264 Description : Functor for calculating number of faces conneted to the edge
2266 //================================================================================
2268 double MultiConnection2D::GetValue( const TSequenceOfXYZ& /*P*/ )
2273 double MultiConnection2D::GetValue( long theElementId )
2277 const SMDS_MeshElement* aFaceElem = myMesh->FindElement(theElementId);
2278 SMDSAbs_ElementType aType = aFaceElem->GetType();
2283 int i = 0, len = aFaceElem->NbNodes();
2284 SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
2287 const SMDS_MeshNode *aNode, *aNode0 = 0;
2288 NCollection_Map< smIdType, smIdHasher > aMap, aMapPrev;
2290 for (i = 0; i <= len; i++) {
2295 if (anIter->more()) {
2296 aNode = (SMDS_MeshNode*)anIter->next();
2304 if (i == 0) aNode0 = aNode;
2306 SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
2307 while (anElemIter->more()) {
2308 const SMDS_MeshElement* anElem = anElemIter->next();
2309 if (anElem != 0 && anElem->GetType() == SMDSAbs_Face) {
2310 smIdType anId = anElem->GetID();
2313 if (aMapPrev.Contains(anId)) {
2318 aResult = Max(aResult, aNb);
2329 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
2331 // meaningless as it is not quality control functor
2335 SMDSAbs_ElementType MultiConnection2D::GetType() const
2337 return SMDSAbs_Face;
2340 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
2342 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
2343 if(thePntId1 > thePntId2){
2344 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
2348 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const
2350 if(myPntId[0] < x.myPntId[0]) return true;
2351 if(myPntId[0] == x.myPntId[0])
2352 if(myPntId[1] < x.myPntId[1]) return true;
2356 void MultiConnection2D::GetValues(MValues& theValues)
2358 if ( !myMesh ) return;
2359 for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
2361 const SMDS_MeshFace* anElem = anIter->next();
2362 SMDS_NodeIteratorPtr aNodesIter = anElem->interlacedNodesIterator();
2364 const SMDS_MeshNode* aNode1 = anElem->GetNode( anElem->NbNodes() - 1 );
2365 const SMDS_MeshNode* aNode2;
2366 for ( ; aNodesIter->more(); )
2368 aNode2 = aNodesIter->next();
2370 Value aValue ( aNode1->GetID(), aNode2->GetID() );
2371 MValues::iterator aItr = theValues.insert( std::make_pair( aValue, 0 )).first;
2379 //================================================================================
2381 Class : BallDiameter
2382 Description : Functor returning diameter of a ball element
2384 //================================================================================
2386 double BallDiameter::GetValue( long theId )
2388 double diameter = 0;
2390 if ( const SMDS_BallElement* ball =
2391 myMesh->DownCast< SMDS_BallElement >( myMesh->FindElement( theId )))
2393 diameter = ball->GetDiameter();
2398 double BallDiameter::GetBadRate( double Value, int /*nbNodes*/ ) const
2400 // meaningless as it is not a quality control functor
2404 SMDSAbs_ElementType BallDiameter::GetType() const
2406 return SMDSAbs_Ball;
2409 //================================================================================
2411 Class : NodeConnectivityNumber
2412 Description : Functor returning number of elements connected to a node
2414 //================================================================================
2416 double NodeConnectivityNumber::GetValue( long theId )
2420 if ( const SMDS_MeshNode* node = myMesh->FindNode( theId ))
2422 SMDSAbs_ElementType type;
2423 if ( myMesh->NbVolumes() > 0 )
2424 type = SMDSAbs_Volume;
2425 else if ( myMesh->NbFaces() > 0 )
2426 type = SMDSAbs_Face;
2427 else if ( myMesh->NbEdges() > 0 )
2428 type = SMDSAbs_Edge;
2431 nb = node->NbInverseElements( type );
2436 double NodeConnectivityNumber::GetBadRate( double Value, int /*nbNodes*/ ) const
2441 SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
2443 return SMDSAbs_Node;
2446 //================================================================================
2448 Class : ScaledJacobian
2449 Description : Functor returning the ScaledJacobian for volumetric elements
2451 //================================================================================
2453 double ScaledJacobian::GetValue( long theElementId )
2455 if ( theElementId && myMesh ) {
2456 SMDS_VolumeTool aVolumeTool;
2457 if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
2458 return aVolumeTool.GetScaledJacobian();
2463 //VTK version not used because lack of implementation for HEXAGONAL_PRISM.
2464 //Several mesh quality measures implemented in vtkMeshQuality can be accessed left here as reference
2466 myCurrElement = myMesh->FindElement( theElementId );
2467 if ( myCurrElement )
2469 VTKCellType cellType = myCurrElement->GetVtkType();
2470 vtkUnstructuredGrid* grid = const_cast<SMDS_Mesh*>( myMesh )->GetGrid();
2471 vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() );
2474 case VTK_QUADRATIC_TETRA:
2476 aVal = Round( vtkMeshQuality::TetScaledJacobian( avtkCell ));
2478 case VTK_QUADRATIC_HEXAHEDRON:
2479 case VTK_HEXAHEDRON:
2480 aVal = Round( vtkMeshQuality::HexScaledJacobian( avtkCell ));
2482 case VTK_QUADRATIC_WEDGE:
2483 case VTK_WEDGE: //Pentahedron
2484 aVal = Round( vtkMeshQuality::WedgeScaledJacobian( avtkCell ));
2486 case VTK_QUADRATIC_PYRAMID:
2488 aVal = Round( vtkMeshQuality::PyramidScaledJacobian( avtkCell ));
2490 case VTK_HEXAGONAL_PRISM:
2491 case VTK_POLYHEDRON:
2500 double ScaledJacobian::GetBadRate( double Value, int /*nbNodes*/ ) const
2505 SMDSAbs_ElementType ScaledJacobian::GetType() const
2507 return SMDSAbs_Volume;
2514 //================================================================================
2516 Class : BadOrientedVolume
2517 Description : Predicate bad oriented volumes
2519 //================================================================================
2521 BadOrientedVolume::BadOrientedVolume()
2526 void BadOrientedVolume::SetMesh( const SMDS_Mesh* theMesh )
2531 bool BadOrientedVolume::IsSatisfy( long theId )
2536 SMDS_VolumeTool vTool( myMesh->FindElement( theId ));
2539 if ( vTool.IsPoly() )
2542 for ( int i = 0; i < vTool.NbFaces() && isOk; ++i )
2543 isOk = vTool.IsFaceExternal( i );
2547 isOk = vTool.IsForward();
2552 SMDSAbs_ElementType BadOrientedVolume::GetType() const
2554 return SMDSAbs_Volume;
2558 Class : BareBorderVolume
2561 bool BareBorderVolume::IsSatisfy(long theElementId )
2563 SMDS_VolumeTool myTool;
2564 if ( myTool.Set( myMesh->FindElement(theElementId)))
2566 for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
2567 if ( myTool.IsFreeFace( iF ))
2569 const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
2570 std::vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF));
2571 if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
2578 //================================================================================
2580 Class : BareBorderFace
2582 //================================================================================
2584 bool BareBorderFace::IsSatisfy(long theElementId )
2587 if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
2589 if ( face->GetType() == SMDSAbs_Face )
2591 int nbN = face->NbCornerNodes();
2592 for ( int i = 0; i < nbN && !ok; ++i )
2594 // check if a link is shared by another face
2595 const SMDS_MeshNode* n1 = face->GetNode( i );
2596 const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
2597 SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
2598 bool isShared = false;
2599 while ( !isShared && fIt->more() )
2601 const SMDS_MeshElement* f = fIt->next();
2602 isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
2606 const int iQuad = face->IsQuadratic();
2607 myLinkNodes.resize( 2 + iQuad);
2608 myLinkNodes[0] = n1;
2609 myLinkNodes[1] = n2;
2611 myLinkNodes[2] = face->GetNode( i+nbN );
2612 ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false);
2620 //================================================================================
2622 Class : OverConstrainedVolume
2624 //================================================================================
2626 bool OverConstrainedVolume::IsSatisfy(long theElementId )
2628 // An element is over-constrained if all its nodes are on the boundary.
2629 // A node is on the boundary if it is connected to one or more faces.
2630 SMDS_VolumeTool myTool;
2631 if (myTool.Set(myMesh->FindElement(theElementId)))
2633 auto nodes = myTool.GetNodes();
2635 for (int i = 0; i < myTool.NbNodes(); ++i)
2637 auto node = nodes[i];
2638 if (node->NbInverseElements(SMDSAbs_Face) == 0)
2648 //================================================================================
2650 Class : OverConstrainedFace
2652 //================================================================================
2654 bool OverConstrainedFace::IsSatisfy(long theElementId )
2656 // An element is over-constrained if all its nodes are on the boundary.
2657 // A node is on the boundary if it is connected to one or more faces.
2658 if (const SMDS_MeshElement *face = myMesh->FindElement(theElementId))
2659 if (face->GetType() == SMDSAbs_Face)
2661 int nbN = face->NbCornerNodes();
2662 for (int i = 0; i < nbN; ++i)
2664 const SMDS_MeshNode *n1 = face->GetNode(i);
2665 if (n1->NbInverseElements(SMDSAbs_Edge) == 0)
2673 //================================================================================
2675 Class : CoincidentNodes
2676 Description : Predicate of Coincident nodes
2678 //================================================================================
2680 CoincidentNodes::CoincidentNodes()
2685 bool CoincidentNodes::IsSatisfy( long theElementId )
2687 return myCoincidentIDs.Contains( theElementId );
2690 SMDSAbs_ElementType CoincidentNodes::GetType() const
2692 return SMDSAbs_Node;
2695 void CoincidentNodes::SetTolerance( const double theToler )
2697 if ( myToler != theToler )
2704 void CoincidentNodes::SetMesh( const SMDS_Mesh* theMesh )
2706 myMeshModifTracer.SetMesh( theMesh );
2707 if ( myMeshModifTracer.IsMeshModified() )
2709 TIDSortedNodeSet nodesToCheck;
2710 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
2711 while ( nIt->more() )
2712 nodesToCheck.insert( nodesToCheck.end(), nIt->next() );
2714 std::list< std::list< const SMDS_MeshNode*> > nodeGroups;
2715 SMESH_OctreeNode::FindCoincidentNodes ( nodesToCheck, &nodeGroups, myToler );
2717 myCoincidentIDs.Clear();
2718 std::list< std::list< const SMDS_MeshNode*> >::iterator groupIt = nodeGroups.begin();
2719 for ( ; groupIt != nodeGroups.end(); ++groupIt )
2721 std::list< const SMDS_MeshNode*>& coincNodes = *groupIt;
2722 std::list< const SMDS_MeshNode*>::iterator n = coincNodes.begin();
2723 for ( ; n != coincNodes.end(); ++n )
2724 myCoincidentIDs.Add( (*n)->GetID() );
2729 //================================================================================
2731 Class : CoincidentElements
2732 Description : Predicate of Coincident Elements
2733 Note : This class is suitable only for visualization of Coincident Elements
2735 //================================================================================
2737 CoincidentElements::CoincidentElements()
2742 void CoincidentElements::SetMesh( const SMDS_Mesh* theMesh )
2747 bool CoincidentElements::IsSatisfy( long theElementId )
2749 if ( !myMesh ) return false;
2751 if ( const SMDS_MeshElement* e = myMesh->FindElement( theElementId ))
2753 if ( e->GetType() != GetType() ) return false;
2754 std::set< const SMDS_MeshNode* > elemNodes( e->begin_nodes(), e->end_nodes() );
2755 const int nbNodes = e->NbNodes();
2756 SMDS_ElemIteratorPtr invIt = (*elemNodes.begin())->GetInverseElementIterator( GetType() );
2757 while ( invIt->more() )
2759 const SMDS_MeshElement* e2 = invIt->next();
2760 if ( e2 == e || e2->NbNodes() != nbNodes ) continue;
2762 bool sameNodes = true;
2763 for ( size_t i = 0; i < elemNodes.size() && sameNodes; ++i )
2764 sameNodes = ( elemNodes.count( e2->GetNode( i )));
2772 SMDSAbs_ElementType CoincidentElements1D::GetType() const
2774 return SMDSAbs_Edge;
2776 SMDSAbs_ElementType CoincidentElements2D::GetType() const
2778 return SMDSAbs_Face;
2780 SMDSAbs_ElementType CoincidentElements3D::GetType() const
2782 return SMDSAbs_Volume;
2786 //================================================================================
2789 Description : Predicate for free borders
2791 //================================================================================
2793 FreeBorders::FreeBorders()
2798 void FreeBorders::SetMesh( const SMDS_Mesh* theMesh )
2803 bool FreeBorders::IsSatisfy( long theId )
2805 return getNbMultiConnection( myMesh, theId ) == 1;
2808 SMDSAbs_ElementType FreeBorders::GetType() const
2810 return SMDSAbs_Edge;
2814 //================================================================================
2817 Description : Predicate for free Edges
2819 //================================================================================
2821 FreeEdges::FreeEdges()
2826 void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
2831 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const smIdType theFaceId )
2833 SMDS_ElemIteratorPtr anElemIter = theNodes[ 0 ]->GetInverseElementIterator(SMDSAbs_Face);
2834 while( anElemIter->more() )
2836 if ( const SMDS_MeshElement* anElem = anElemIter->next())
2838 const smIdType anId = anElem->GetID();
2839 if ( anId != theFaceId && anElem->GetNodeIndex( theNodes[1] ) >= 0 )
2846 bool FreeEdges::IsSatisfy( long theId )
2851 const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2852 if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
2855 SMDS_NodeIteratorPtr anIter = aFace->interlacedNodesIterator();
2859 int i = 0, nbNodes = aFace->NbNodes();
2860 std::vector <const SMDS_MeshNode*> aNodes( nbNodes+1 );
2861 while( anIter->more() )
2862 if ( ! ( aNodes[ i++ ] = anIter->next() ))
2864 aNodes[ nbNodes ] = aNodes[ 0 ];
2866 for ( i = 0; i < nbNodes; i++ )
2867 if ( IsFreeEdge( &aNodes[ i ], theId ) )
2873 SMDSAbs_ElementType FreeEdges::GetType() const
2875 return SMDSAbs_Face;
2878 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
2881 myPntId[0] = thePntId1; myPntId[1] = thePntId2;
2882 if(thePntId1 > thePntId2){
2883 myPntId[1] = thePntId1; myPntId[0] = thePntId2;
2887 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
2888 if(myPntId[0] < x.myPntId[0]) return true;
2889 if(myPntId[0] == x.myPntId[0])
2890 if(myPntId[1] < x.myPntId[1]) return true;
2894 inline void UpdateBorders(const FreeEdges::Border& theBorder,
2895 FreeEdges::TBorders& theRegistry,
2896 FreeEdges::TBorders& theContainer)
2898 if(theRegistry.find(theBorder) == theRegistry.end()){
2899 theRegistry.insert(theBorder);
2900 theContainer.insert(theBorder);
2902 theContainer.erase(theBorder);
2906 void FreeEdges::GetBoreders(TBorders& theBorders)
2909 for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
2911 const SMDS_MeshFace* anElem = anIter->next();
2912 long anElemId = anElem->GetID();
2913 SMDS_NodeIteratorPtr aNodesIter = anElem->interlacedNodesIterator();
2914 if ( !aNodesIter->more() ) continue;
2915 long aNodeId[2] = {0,0};
2916 aNodeId[0] = anElem->GetNode( anElem->NbNodes()-1 )->GetID();
2917 for ( ; aNodesIter->more(); )
2919 aNodeId[1] = aNodesIter->next()->GetID();
2920 Border aBorder( anElemId, aNodeId[0], aNodeId[1] );
2921 UpdateBorders( aBorder, aRegistry, theBorders );
2922 aNodeId[0] = aNodeId[1];
2927 //================================================================================
2930 Description : Predicate for free nodes
2932 //================================================================================
2934 FreeNodes::FreeNodes()
2939 void FreeNodes::SetMesh( const SMDS_Mesh* theMesh )
2944 bool FreeNodes::IsSatisfy( long theNodeId )
2946 const SMDS_MeshNode* aNode = myMesh->FindNode( theNodeId );
2950 return (aNode->NbInverseElements() < 1);
2953 SMDSAbs_ElementType FreeNodes::GetType() const
2955 return SMDSAbs_Node;
2959 //================================================================================
2962 Description : Predicate for free faces
2964 //================================================================================
2966 FreeFaces::FreeFaces()
2971 void FreeFaces::SetMesh( const SMDS_Mesh* theMesh )
2976 bool FreeFaces::IsSatisfy( long theId )
2978 if (!myMesh) return false;
2979 // check that faces nodes refers to less than two common volumes
2980 const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
2981 if ( !aFace || aFace->GetType() != SMDSAbs_Face )
2984 int nbNode = aFace->NbNodes();
2986 // collect volumes to check that number of volumes with count equal nbNode not less than 2
2987 typedef std::map< SMDS_MeshElement*, int > TMapOfVolume; // map of volume counters
2988 typedef std::map< SMDS_MeshElement*, int >::iterator TItrMapOfVolume; // iterator
2989 TMapOfVolume mapOfVol;
2991 SMDS_ElemIteratorPtr nodeItr = aFace->nodesIterator();
2992 while ( nodeItr->more() )
2994 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
2995 if ( !aNode ) continue;
2996 SMDS_ElemIteratorPtr volItr = aNode->GetInverseElementIterator(SMDSAbs_Volume);
2997 while ( volItr->more() )
2999 SMDS_MeshElement* aVol = (SMDS_MeshElement*)volItr->next();
3000 TItrMapOfVolume itr = mapOfVol.insert( std::make_pair( aVol, 0 )).first;
3005 TItrMapOfVolume volItr = mapOfVol.begin();
3006 TItrMapOfVolume volEnd = mapOfVol.end();
3007 for ( ; volItr != volEnd; ++volItr )
3008 if ( (*volItr).second >= nbNode )
3010 // face is not free if number of volumes constructed on their nodes more than one
3014 SMDSAbs_ElementType FreeFaces::GetType() const
3016 return SMDSAbs_Face;
3019 //================================================================================
3021 Class : LinearOrQuadratic
3022 Description : Predicate to verify whether a mesh element is linear
3024 //================================================================================
3026 LinearOrQuadratic::LinearOrQuadratic()
3031 void LinearOrQuadratic::SetMesh( const SMDS_Mesh* theMesh )
3036 bool LinearOrQuadratic::IsSatisfy( long theId )
3038 if (!myMesh) return false;
3039 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3040 if ( !anElem || (myType != SMDSAbs_All && anElem->GetType() != myType) )
3042 return (!anElem->IsQuadratic());
3045 void LinearOrQuadratic::SetType( SMDSAbs_ElementType theType )
3050 SMDSAbs_ElementType LinearOrQuadratic::GetType() const
3055 //================================================================================
3058 Description : Functor for check color of group to which mesh element belongs to
3060 //================================================================================
3062 GroupColor::GroupColor()
3066 bool GroupColor::IsSatisfy( long theId )
3068 return myIDs.count( theId );
3071 void GroupColor::SetType( SMDSAbs_ElementType theType )
3076 SMDSAbs_ElementType GroupColor::GetType() const
3081 static bool isEqual( const Quantity_Color& theColor1,
3082 const Quantity_Color& theColor2 )
3084 // tolerance to compare colors
3085 const double tol = 5*1e-3;
3086 return ( fabs( theColor1.Red() - theColor2.Red() ) < tol &&
3087 fabs( theColor1.Green() - theColor2.Green() ) < tol &&
3088 fabs( theColor1.Blue() - theColor2.Blue() ) < tol );
3091 void GroupColor::SetMesh( const SMDS_Mesh* theMesh )
3095 const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
3099 int nbGrp = aMesh->GetNbGroups();
3103 // iterates on groups and find necessary elements ids
3104 const std::set<SMESHDS_GroupBase*>& aGroups = aMesh->GetGroups();
3105 std::set<SMESHDS_GroupBase*>::const_iterator GrIt = aGroups.begin();
3106 for (; GrIt != aGroups.end(); GrIt++)
3108 SMESHDS_GroupBase* aGrp = (*GrIt);
3111 // check type and color of group
3112 if ( !isEqual( myColor, aGrp->GetColor() ))
3115 // IPAL52867 (prevent infinite recursion via GroupOnFilter)
3116 if ( SMESHDS_GroupOnFilter * gof = dynamic_cast< SMESHDS_GroupOnFilter* >( aGrp ))
3117 if ( gof->GetPredicate().get() == this )
3120 SMDSAbs_ElementType aGrpElType = (SMDSAbs_ElementType)aGrp->GetType();
3121 if ( myType == aGrpElType || (myType == SMDSAbs_All && aGrpElType != SMDSAbs_Node) ) {
3122 // add elements IDS into control
3123 smIdType aSize = aGrp->Extent();
3124 for (smIdType i = 0; i < aSize; i++)
3125 myIDs.insert( aGrp->GetID(i+1) );
3130 void GroupColor::SetColorStr( const TCollection_AsciiString& theStr )
3132 Kernel_Utils::Localizer loc;
3133 TCollection_AsciiString aStr = theStr;
3134 aStr.RemoveAll( ' ' );
3135 aStr.RemoveAll( '\t' );
3136 for ( int aPos = aStr.Search( ";;" ); aPos != -1; aPos = aStr.Search( ";;" ) )
3137 aStr.Remove( aPos, 2 );
3138 Standard_Real clr[3];
3139 clr[0] = clr[1] = clr[2] = 0.;
3140 for ( int i = 0; i < 3; i++ ) {
3141 TCollection_AsciiString tmpStr = aStr.Token( ";", i+1 );
3142 if ( !tmpStr.IsEmpty() && tmpStr.IsRealValue() )
3143 clr[i] = tmpStr.RealValue();
3145 myColor = Quantity_Color( clr[0], clr[1], clr[2], Quantity_TOC_RGB );
3148 //=======================================================================
3149 // name : GetRangeStr
3150 // Purpose : Get range as a string.
3151 // Example: "1,2,3,50-60,63,67,70-"
3152 //=======================================================================
3154 void GroupColor::GetColorStr( TCollection_AsciiString& theResStr ) const
3157 theResStr += TCollection_AsciiString( myColor.Red() );
3158 theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Green() );
3159 theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Blue() );
3162 //================================================================================
3164 Class : ElemGeomType
3165 Description : Predicate to check element geometry type
3167 //================================================================================
3169 ElemGeomType::ElemGeomType()
3172 myType = SMDSAbs_All;
3173 myGeomType = SMDSGeom_TRIANGLE;
3176 void ElemGeomType::SetMesh( const SMDS_Mesh* theMesh )
3181 bool ElemGeomType::IsSatisfy( long theId )
3183 if (!myMesh) return false;
3184 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3187 const SMDSAbs_ElementType anElemType = anElem->GetType();
3188 if ( myType != SMDSAbs_All && anElemType != myType )
3190 bool isOk = ( anElem->GetGeomType() == myGeomType );
3194 void ElemGeomType::SetType( SMDSAbs_ElementType theType )
3199 SMDSAbs_ElementType ElemGeomType::GetType() const
3204 void ElemGeomType::SetGeomType( SMDSAbs_GeometryType theType )
3206 myGeomType = theType;
3209 SMDSAbs_GeometryType ElemGeomType::GetGeomType() const
3214 //================================================================================
3216 Class : ElemEntityType
3217 Description : Predicate to check element entity type
3219 //================================================================================
3221 ElemEntityType::ElemEntityType():
3223 myType( SMDSAbs_All ),
3224 myEntityType( SMDSEntity_0D )
3228 void ElemEntityType::SetMesh( const SMDS_Mesh* theMesh )
3233 bool ElemEntityType::IsSatisfy( long theId )
3235 if ( !myMesh ) return false;
3236 if ( myType == SMDSAbs_Node )
3237 return myMesh->FindNode( theId );
3238 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3240 myEntityType == anElem->GetEntityType() );
3243 void ElemEntityType::SetType( SMDSAbs_ElementType theType )
3248 SMDSAbs_ElementType ElemEntityType::GetType() const
3253 void ElemEntityType::SetElemEntityType( SMDSAbs_EntityType theEntityType )
3255 myEntityType = theEntityType;
3258 SMDSAbs_EntityType ElemEntityType::GetElemEntityType() const
3260 return myEntityType;
3263 //================================================================================
3265 * \brief Class ConnectedElements
3267 //================================================================================
3269 ConnectedElements::ConnectedElements():
3270 myNodeID(0), myType( SMDSAbs_All ), myOkIDsReady( false ) {}
3272 SMDSAbs_ElementType ConnectedElements::GetType() const
3275 smIdType ConnectedElements::GetNode() const
3276 { return myXYZ.empty() ? myNodeID : 0; } // myNodeID can be found by myXYZ
3278 std::vector<double> ConnectedElements::GetPoint() const
3281 void ConnectedElements::clearOkIDs()
3282 { myOkIDsReady = false; myOkIDs.clear(); }
3284 void ConnectedElements::SetType( SMDSAbs_ElementType theType )
3286 if ( myType != theType || myMeshModifTracer.IsMeshModified() )
3291 void ConnectedElements::SetMesh( const SMDS_Mesh* theMesh )
3293 myMeshModifTracer.SetMesh( theMesh );
3294 if ( myMeshModifTracer.IsMeshModified() )
3297 if ( !myXYZ.empty() )
3298 SetPoint( myXYZ[0], myXYZ[1], myXYZ[2] ); // find a node near myXYZ it in a new mesh
3302 void ConnectedElements::SetNode( smIdType nodeID )
3307 bool isSameDomain = false;
3308 if ( myOkIDsReady && myMeshModifTracer.GetMesh() && !myMeshModifTracer.IsMeshModified() )
3309 if ( const SMDS_MeshNode* n = myMeshModifTracer.GetMesh()->FindNode( myNodeID ))
3311 SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( myType );
3312 while ( !isSameDomain && eIt->more() )
3313 isSameDomain = IsSatisfy( eIt->next()->GetID() );
3315 if ( !isSameDomain )
3319 void ConnectedElements::SetPoint( double x, double y, double z )
3327 bool isSameDomain = false;
3329 // find myNodeID by myXYZ if possible
3330 if ( myMeshModifTracer.GetMesh() )
3332 SMESHUtils::Deleter<SMESH_ElementSearcher> searcher
3333 ( SMESH_MeshAlgos::GetElementSearcher( (SMDS_Mesh&) *myMeshModifTracer.GetMesh() ));
3335 std::vector< const SMDS_MeshElement* > foundElems;
3336 searcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_All, foundElems );
3338 if ( !foundElems.empty() )
3340 myNodeID = foundElems[0]->GetNode(0)->GetID();
3341 if ( myOkIDsReady && !myMeshModifTracer.IsMeshModified() )
3342 isSameDomain = IsSatisfy( foundElems[0]->GetID() );
3345 if ( !isSameDomain )
3349 bool ConnectedElements::IsSatisfy( long theElementId )
3351 // Here we do NOT check if the mesh has changed, we do it in Set...() only!!!
3353 if ( !myOkIDsReady )
3355 if ( !myMeshModifTracer.GetMesh() )
3357 const SMDS_MeshNode* node0 = myMeshModifTracer.GetMesh()->FindNode( myNodeID );
3361 std::list< const SMDS_MeshNode* > nodeQueue( 1, node0 );
3362 std::set< smIdType > checkedNodeIDs;
3364 // foreach node in nodeQueue:
3365 // foreach element sharing a node:
3366 // add ID of an element of myType to myOkIDs;
3367 // push all element nodes absent from checkedNodeIDs to nodeQueue;
3368 while ( !nodeQueue.empty() )
3370 const SMDS_MeshNode* node = nodeQueue.front();
3371 nodeQueue.pop_front();
3373 // loop on elements sharing the node
3374 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3375 while ( eIt->more() )
3377 // keep elements of myType
3378 const SMDS_MeshElement* element = eIt->next();
3379 if ( myType == SMDSAbs_All || element->GetType() == myType )
3380 myOkIDs.insert( myOkIDs.end(), element->GetID() );
3382 // enqueue nodes of the element
3383 SMDS_ElemIteratorPtr nIt = element->nodesIterator();
3384 while ( nIt->more() )
3386 const SMDS_MeshNode* n = static_cast< const SMDS_MeshNode* >( nIt->next() );
3387 if ( checkedNodeIDs.insert( n->GetID()).second )
3388 nodeQueue.push_back( n );
3392 if ( myType == SMDSAbs_Node )
3393 std::swap( myOkIDs, checkedNodeIDs );
3395 size_t totalNbElems = myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType );
3396 if ( myOkIDs.size() == totalNbElems )
3399 myOkIDsReady = true;
3402 return myOkIDs.empty() ? true : myOkIDs.count( theElementId );
3405 //================================================================================
3407 * \brief Class CoplanarFaces
3409 //================================================================================
3413 inline bool isLessAngle( const gp_Vec& v1, const gp_Vec& v2, const double cos )
3415 double dot = v1 * v2; // cos * |v1| * |v2|
3416 double l1 = v1.SquareMagnitude();
3417 double l2 = v2.SquareMagnitude();
3418 return (( dot * cos >= 0 ) &&
3419 ( dot * dot ) / l1 / l2 >= ( cos * cos ));
3422 CoplanarFaces::CoplanarFaces()
3423 : myFaceID(0), myToler(0)
3426 void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh )
3428 myMeshModifTracer.SetMesh( theMesh );
3429 if ( myMeshModifTracer.IsMeshModified() )
3431 // Build a set of coplanar face ids
3433 myCoplanarIDs.Clear();
3435 if ( !myMeshModifTracer.GetMesh() || !myFaceID || !myToler )
3438 const SMDS_MeshElement* face = myMeshModifTracer.GetMesh()->FindElement( myFaceID );
3439 if ( !face || face->GetType() != SMDSAbs_Face )
3443 gp_Vec myNorm = getNormale( static_cast<const SMDS_MeshFace*>(face), &normOK );
3447 const double cosTol = Cos( myToler * M_PI / 180. );
3448 NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks;
3450 std::list< std::pair< const SMDS_MeshElement*, gp_Vec > > faceQueue;
3451 faceQueue.push_back( std::make_pair( face, myNorm ));
3452 while ( !faceQueue.empty() )
3454 face = faceQueue.front().first;
3455 myNorm = faceQueue.front().second;
3456 faceQueue.pop_front();
3458 for ( int i = 0, nbN = face->NbCornerNodes(); i < nbN; ++i )
3460 const SMDS_MeshNode* n1 = face->GetNode( i );
3461 const SMDS_MeshNode* n2 = face->GetNode(( i+1 )%nbN);
3462 if ( !checkedLinks.Add( SMESH_TLink( n1, n2 )))
3464 SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator(SMDSAbs_Face);
3465 while ( fIt->more() )
3467 const SMDS_MeshElement* f = fIt->next();
3468 if ( f->GetNodeIndex( n2 ) > -1 )
3470 gp_Vec norm = getNormale( static_cast<const SMDS_MeshFace*>(f), &normOK );
3471 if (!normOK || isLessAngle( myNorm, norm, cosTol))
3473 myCoplanarIDs.Add( f->GetID() );
3474 faceQueue.push_back( std::make_pair( f, norm ));
3482 bool CoplanarFaces::IsSatisfy( long theElementId )
3484 return myCoplanarIDs.Contains( theElementId );
3489 *Description : Predicate for Range of Ids.
3490 * Range may be specified with two ways.
3491 * 1. Using AddToRange method
3492 * 2. With SetRangeStr method. Parameter of this method is a string
3493 * like as "1,2,3,50-60,63,67,70-"
3496 //=======================================================================
3497 // name : RangeOfIds
3498 // Purpose : Constructor
3499 //=======================================================================
3500 RangeOfIds::RangeOfIds()
3503 myType = SMDSAbs_All;
3506 //=======================================================================
3508 // Purpose : Set mesh
3509 //=======================================================================
3510 void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
3515 //=======================================================================
3516 // name : AddToRange
3517 // Purpose : Add ID to the range
3518 //=======================================================================
3519 bool RangeOfIds::AddToRange( long theEntityId )
3521 myIds.Add( theEntityId );
3525 //=======================================================================
3526 // name : GetRangeStr
3527 // Purpose : Get range as a string.
3528 // Example: "1,2,3,50-60,63,67,70-"
3529 //=======================================================================
3530 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
3535 NCollection_Sequence< std::string > aStrSeq;
3537 TIDsMap::Iterator anIter( myIds );
3538 for ( ; anIter.More(); anIter.Next() )
3540 smIdType anId = anIter.Key();
3541 SMESH_Comment aStr( anId );
3542 anIntSeq.Append( anId );
3543 aStrSeq.Append( aStr );
3546 for ( smIdType i = 1, n = myMin.size(); i <= n; i++ )
3548 smIdType aMinId = myMin[i];
3549 smIdType aMaxId = myMax[i];
3552 if ( aMinId != IntegerFirst() )
3557 if ( aMaxId != std::numeric_limits<smIdType>::max() )
3560 // find position of the string in result sequence and insert string in it
3561 if ( anIntSeq.Length() == 0 )
3563 anIntSeq.Append( aMinId );
3564 aStrSeq.Append( (const char*)aStr );
3568 if ( aMinId < anIntSeq.First() )
3570 anIntSeq.Prepend( aMinId );
3571 aStrSeq.Prepend( (const char*)aStr );
3573 else if ( aMinId > anIntSeq.Last() )
3575 anIntSeq.Append( aMinId );
3576 aStrSeq.Append( (const char*)aStr );
3579 for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
3580 if ( aMinId < anIntSeq( j ) )
3582 anIntSeq.InsertBefore( j, aMinId );
3583 aStrSeq.InsertBefore( j, (const char*)aStr );
3589 if ( aStrSeq.Length() == 0 )
3591 std::string aResStr;
3592 aResStr = aStrSeq( 1 );
3593 for ( int j = 2, k = aStrSeq.Length(); j <= k; j++ )
3596 aResStr += aStrSeq( j );
3598 theResStr = aResStr.c_str();
3601 //=======================================================================
3602 // name : SetRangeStr
3603 // Purpose : Define range with string
3604 // Example of entry string: "1,2,3,50-60,63,67,70-"
3605 //=======================================================================
3606 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
3612 TCollection_AsciiString aStr = theStr;
3613 for ( int i = 1; i <= aStr.Length(); ++i )
3615 char c = aStr.Value( i );
3616 if ( !isdigit( c ) && c != ',' && c != '-' )
3617 aStr.SetValue( i, ',');
3619 aStr.RemoveAll( ' ' );
3621 TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
3623 while ( tmpStr != "" )
3625 tmpStr = aStr.Token( ",", i++ );
3626 int aPos = tmpStr.Search( '-' );
3630 if ( tmpStr.IsIntegerValue() )
3631 myIds.Add( tmpStr.IntegerValue() );
3637 TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
3638 TCollection_AsciiString aMinStr = tmpStr;
3640 while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
3641 while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
3643 if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
3644 (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
3647 myMin.push_back( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
3648 myMax.push_back( aMaxStr.IsEmpty() ? IntegerLast() : aMaxStr.IntegerValue() );
3655 //=======================================================================
3657 // Purpose : Get type of supported entities
3658 //=======================================================================
3659 SMDSAbs_ElementType RangeOfIds::GetType() const
3664 //=======================================================================
3666 // Purpose : Set type of supported entities
3667 //=======================================================================
3668 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
3673 //=======================================================================
3675 // Purpose : Verify whether entity satisfies to this rpedicate
3676 //=======================================================================
3677 bool RangeOfIds::IsSatisfy( long theId )
3682 if ( myType == SMDSAbs_Node )
3684 if ( myMesh->FindNode( theId ) == 0 )
3689 const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
3690 if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
3694 if ( myIds.Contains( theId ) )
3697 for ( size_t i = 0; i < myMin.size(); i++ )
3698 if ( theId >= myMin[i] && theId <= myMax[i] )
3706 Description : Base class for comparators
3708 Comparator::Comparator():
3712 Comparator::~Comparator()
3715 void Comparator::SetMesh( const SMDS_Mesh* theMesh )
3718 myFunctor->SetMesh( theMesh );
3721 void Comparator::SetMargin( double theValue )
3723 myMargin = theValue;
3726 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
3728 myFunctor = theFunct;
3731 SMDSAbs_ElementType Comparator::GetType() const
3733 return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
3736 double Comparator::GetMargin()
3744 Description : Comparator "<"
3746 bool LessThan::IsSatisfy( long theId )
3748 return myFunctor && myFunctor->GetValue( theId ) < myMargin;
3754 Description : Comparator ">"
3756 bool MoreThan::IsSatisfy( long theId )
3758 return myFunctor && myFunctor->GetValue( theId ) > myMargin;
3764 Description : Comparator "="
3767 myToler(Precision::Confusion())
3770 bool EqualTo::IsSatisfy( long theId )
3772 return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
3775 void EqualTo::SetTolerance( double theToler )
3780 double EqualTo::GetTolerance()
3787 Description : Logical NOT predicate
3789 LogicalNOT::LogicalNOT()
3792 LogicalNOT::~LogicalNOT()
3795 bool LogicalNOT::IsSatisfy( long theId )
3797 return myPredicate && !myPredicate->IsSatisfy( theId );
3800 void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
3803 myPredicate->SetMesh( theMesh );
3806 void LogicalNOT::SetPredicate( PredicatePtr thePred )
3808 myPredicate = thePred;
3811 SMDSAbs_ElementType LogicalNOT::GetType() const
3813 return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
3818 Class : LogicalBinary
3819 Description : Base class for binary logical predicate
3821 LogicalBinary::LogicalBinary()
3824 LogicalBinary::~LogicalBinary()
3827 void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
3830 myPredicate1->SetMesh( theMesh );
3833 myPredicate2->SetMesh( theMesh );
3836 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
3838 myPredicate1 = thePredicate;
3841 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
3843 myPredicate2 = thePredicate;
3846 SMDSAbs_ElementType LogicalBinary::GetType() const
3848 if ( !myPredicate1 || !myPredicate2 )
3851 SMDSAbs_ElementType aType1 = myPredicate1->GetType();
3852 SMDSAbs_ElementType aType2 = myPredicate2->GetType();
3854 return aType1 == aType2 ? aType1 : SMDSAbs_All;
3860 Description : Logical AND
3862 bool LogicalAND::IsSatisfy( long theId )
3867 myPredicate1->IsSatisfy( theId ) &&
3868 myPredicate2->IsSatisfy( theId );
3874 Description : Logical OR
3876 bool LogicalOR::IsSatisfy( long theId )
3881 (myPredicate1->IsSatisfy( theId ) ||
3882 myPredicate2->IsSatisfy( theId ));
3891 // #include <tbb/parallel_for.h>
3892 // #include <tbb/enumerable_thread_specific.h>
3894 // namespace Parallel
3896 // typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq;
3900 // const SMDS_Mesh* myMesh;
3901 // PredicatePtr myPredicate;
3902 // TIdSeq & myOKIds;
3903 // Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ):
3904 // myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {}
3905 // void operator() ( const tbb::blocked_range<size_t>& r ) const
3907 // for ( size_t i = r.begin(); i != r.end(); ++i )
3908 // if ( myPredicate->IsSatisfy( i ))
3909 // myOKIds.local().push_back();
3921 void Filter::SetPredicate( PredicatePtr thePredicate )
3923 myPredicate = thePredicate;
3926 void Filter::GetElementsId( const SMDS_Mesh* theMesh,
3927 PredicatePtr thePredicate,
3928 TIdSequence& theSequence,
3929 SMDS_ElemIteratorPtr theElements )
3931 theSequence.clear();
3933 if ( !theMesh || !thePredicate )
3936 thePredicate->SetMesh( theMesh );
3939 theElements = theMesh->elementsIterator( thePredicate->GetType() );
3941 if ( theElements ) {
3942 while ( theElements->more() ) {
3943 const SMDS_MeshElement* anElem = theElements->next();
3944 if ( thePredicate->GetType() == SMDSAbs_All ||
3945 thePredicate->GetType() == anElem->GetType() )
3947 long anId = anElem->GetID();
3948 if ( thePredicate->IsSatisfy( anId ) )
3949 theSequence.push_back( anId );
3955 void Filter::GetElementsId( const SMDS_Mesh* theMesh,
3956 Filter::TIdSequence& theSequence,
3957 SMDS_ElemIteratorPtr theElements )
3959 GetElementsId(theMesh,myPredicate,theSequence,theElements);
3966 typedef std::set<SMDS_MeshFace*> TMapOfFacePtr;
3972 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
3973 SMDS_MeshNode* theNode2 )
3979 ManifoldPart::Link::~Link()
3985 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
3987 if ( myNode1 == theLink.myNode1 &&
3988 myNode2 == theLink.myNode2 )
3990 else if ( myNode1 == theLink.myNode2 &&
3991 myNode2 == theLink.myNode1 )
3997 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
3999 if(myNode1 < x.myNode1) return true;
4000 if(myNode1 == x.myNode1)
4001 if(myNode2 < x.myNode2) return true;
4005 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
4006 const ManifoldPart::Link& theLink2 )
4008 return theLink1.IsEqual( theLink2 );
4011 ManifoldPart::ManifoldPart()
4014 myAngToler = Precision::Angular();
4015 myIsOnlyManifold = true;
4018 ManifoldPart::~ManifoldPart()
4023 void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
4029 SMDSAbs_ElementType ManifoldPart::GetType() const
4030 { return SMDSAbs_Face; }
4032 bool ManifoldPart::IsSatisfy( long theElementId )
4034 return myMapIds.Contains( theElementId );
4037 void ManifoldPart::SetAngleTolerance( const double theAngToler )
4038 { myAngToler = theAngToler; }
4040 double ManifoldPart::GetAngleTolerance() const
4041 { return myAngToler; }
4043 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
4044 { myIsOnlyManifold = theIsOnly; }
4046 void ManifoldPart::SetStartElem( const long theStartId )
4047 { myStartElemId = theStartId; }
4049 bool ManifoldPart::process()
4052 myMapBadGeomIds.Clear();
4054 myAllFacePtr.clear();
4055 myAllFacePtrIntDMap.clear();
4059 // collect all faces into own map
4060 SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
4061 for (; anFaceItr->more(); )
4063 SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
4064 myAllFacePtr.push_back( aFacePtr );
4065 myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
4068 SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
4072 // the map of non manifold links and bad geometry
4073 TMapOfLink aMapOfNonManifold;
4074 TIDsMap aMapOfTreated;
4076 // begin cycle on faces from start index and run on vector till the end
4077 // and from begin to start index to cover whole vector
4078 const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
4079 bool isStartTreat = false;
4080 for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
4082 if ( fi == aStartIndx )
4083 isStartTreat = true;
4084 // as result next time when fi will be equal to aStartIndx
4086 SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
4087 if ( aMapOfTreated.Contains( aFacePtr->GetID()) )
4090 aMapOfTreated.Add( aFacePtr->GetID() );
4092 if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
4093 aMapOfNonManifold, aResFaces ) )
4095 TIDsMap::Iterator anItr( aResFaces );
4096 for ( ; anItr.More(); anItr.Next() )
4098 smIdType aFaceId = anItr.Key();
4099 aMapOfTreated.Add( aFaceId );
4100 myMapIds.Add( aFaceId );
4103 if ( fi == int( myAllFacePtr.size() - 1 ))
4105 } // end run on vector of faces
4106 return !myMapIds.IsEmpty();
4109 static void getLinks( const SMDS_MeshFace* theFace,
4110 ManifoldPart::TVectorOfLink& theLinks )
4112 int aNbNode = theFace->NbNodes();
4113 SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
4115 SMDS_MeshNode* aNode = 0;
4116 for ( ; aNodeItr->more() && i <= aNbNode; )
4119 SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
4123 SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
4125 ManifoldPart::Link aLink( aN1, aN2 );
4126 theLinks.push_back( aLink );
4130 bool ManifoldPart::findConnected
4131 ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
4132 SMDS_MeshFace* theStartFace,
4133 ManifoldPart::TMapOfLink& theNonManifold,
4134 TIDsMap& theResFaces )
4136 theResFaces.Clear();
4137 if ( !theAllFacePtrInt.size() )
4140 if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
4142 myMapBadGeomIds.Add( theStartFace->GetID() );
4146 ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
4147 ManifoldPart::TVectorOfLink aSeqOfBoundary;
4148 theResFaces.Add( theStartFace->GetID() );
4149 ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
4151 expandBoundary( aMapOfBoundary, aSeqOfBoundary,
4152 aDMapLinkFace, theNonManifold, theStartFace );
4154 bool isDone = false;
4155 while ( !isDone && aMapOfBoundary.size() != 0 )
4157 bool isToReset = false;
4158 ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
4159 for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
4161 ManifoldPart::Link aLink = *pLink;
4162 if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
4164 // each link could be treated only once
4165 aMapToSkip.insert( aLink );
4167 ManifoldPart::TVectorOfFacePtr aFaces;
4169 if ( myIsOnlyManifold &&
4170 (theNonManifold.find( aLink ) != theNonManifold.end()) )
4174 getFacesByLink( aLink, aFaces );
4175 // filter the element to keep only indicated elements
4176 ManifoldPart::TVectorOfFacePtr aFiltered;
4177 ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
4178 for ( ; pFace != aFaces.end(); ++pFace )
4180 SMDS_MeshFace* aFace = *pFace;
4181 if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
4182 aFiltered.push_back( aFace );
4185 if ( aFaces.size() < 2 ) // no neihgbour faces
4187 else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
4189 theNonManifold.insert( aLink );
4194 // compare normal with normals of neighbor element
4195 SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
4196 ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
4197 for ( ; pFace != aFaces.end(); ++pFace )
4199 SMDS_MeshFace* aNextFace = *pFace;
4200 if ( aPrevFace == aNextFace )
4202 smIdType anNextFaceID = aNextFace->GetID();
4203 if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
4204 // should not be with non manifold restriction. probably bad topology
4206 // check if face was treated and skipped
4207 if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
4208 !isInPlane( aPrevFace, aNextFace ) )
4210 // add new element to connected and extend the boundaries.
4211 theResFaces.Add( anNextFaceID );
4212 expandBoundary( aMapOfBoundary, aSeqOfBoundary,
4213 aDMapLinkFace, theNonManifold, aNextFace );
4217 isDone = !isToReset;
4220 return !theResFaces.IsEmpty();
4223 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
4224 const SMDS_MeshFace* theFace2 )
4226 gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
4227 gp_XYZ aNorm2XYZ = getNormale( theFace2 );
4228 if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
4230 myMapBadGeomIds.Add( theFace2->GetID() );
4233 if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
4239 void ManifoldPart::expandBoundary
4240 ( ManifoldPart::TMapOfLink& theMapOfBoundary,
4241 ManifoldPart::TVectorOfLink& theSeqOfBoundary,
4242 ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
4243 ManifoldPart::TMapOfLink& theNonManifold,
4244 SMDS_MeshFace* theNextFace ) const
4246 ManifoldPart::TVectorOfLink aLinks;
4247 getLinks( theNextFace, aLinks );
4248 int aNbLink = (int)aLinks.size();
4249 for ( int i = 0; i < aNbLink; i++ )
4251 ManifoldPart::Link aLink = aLinks[ i ];
4252 if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
4254 if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
4256 if ( myIsOnlyManifold )
4258 // remove from boundary
4259 theMapOfBoundary.erase( aLink );
4260 ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
4261 for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
4263 ManifoldPart::Link aBoundLink = *pLink;
4264 if ( aBoundLink.IsEqual( aLink ) )
4266 theSeqOfBoundary.erase( pLink );
4274 theMapOfBoundary.insert( aLink );
4275 theSeqOfBoundary.push_back( aLink );
4276 theDMapLinkFacePtr[ aLink ] = theNextFace;
4281 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
4282 ManifoldPart::TVectorOfFacePtr& theFaces ) const
4285 // take all faces that shared first node
4286 SMDS_ElemIteratorPtr anItr = theLink.myNode1->GetInverseElementIterator( SMDSAbs_Face );
4287 SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > faces( anItr ), facesEnd;
4288 std::set<const SMDS_MeshElement *> aSetOfFaces( faces, facesEnd );
4290 // take all faces that shared second node
4291 anItr = theLink.myNode2->GetInverseElementIterator( SMDSAbs_Face );
4292 // find the common part of two sets
4293 for ( ; anItr->more(); )
4295 const SMDS_MeshElement* aFace = anItr->next();
4296 if ( aSetOfFaces.count( aFace ))
4297 theFaces.push_back( (SMDS_MeshFace*) aFace );
4302 Class : BelongToMeshGroup
4303 Description : Verify whether a mesh element is included into a mesh group
4305 BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 )
4309 void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g )
4314 void BelongToMeshGroup::SetStoreName( const std::string& sn )
4319 void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh )
4321 if ( myGroup && myGroup->GetMesh() != theMesh )
4325 if ( !myGroup && !myStoreName.empty() )
4327 if ( const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh))
4329 const std::set<SMESHDS_GroupBase*>& grps = aMesh->GetGroups();
4330 std::set<SMESHDS_GroupBase*>::const_iterator g = grps.begin();
4331 for ( ; g != grps.end() && !myGroup; ++g )
4332 if ( *g && myStoreName == (*g)->GetStoreName() )
4338 myGroup->IsEmpty(); // make GroupOnFilter update its predicate
4342 bool BelongToMeshGroup::IsSatisfy( long theElementId )
4344 return myGroup ? myGroup->Contains( theElementId ) : false;
4347 SMDSAbs_ElementType BelongToMeshGroup::GetType() const
4349 return myGroup ? myGroup->GetType() : SMDSAbs_All;
4352 //================================================================================
4353 // ElementsOnSurface
4354 //================================================================================
4356 ElementsOnSurface::ElementsOnSurface()
4359 myType = SMDSAbs_All;
4361 myToler = Precision::Confusion();
4362 myUseBoundaries = false;
4365 ElementsOnSurface::~ElementsOnSurface()
4369 void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
4371 myMeshModifTracer.SetMesh( theMesh );
4372 if ( myMeshModifTracer.IsMeshModified())
4376 bool ElementsOnSurface::IsSatisfy( long theElementId )
4378 return myIds.Contains( theElementId );
4381 SMDSAbs_ElementType ElementsOnSurface::GetType() const
4384 void ElementsOnSurface::SetTolerance( const double theToler )
4386 if ( myToler != theToler )
4393 double ElementsOnSurface::GetTolerance() const
4396 void ElementsOnSurface::SetUseBoundaries( bool theUse )
4398 if ( myUseBoundaries != theUse ) {
4399 myUseBoundaries = theUse;
4400 SetSurface( mySurf, myType );
4404 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
4405 const SMDSAbs_ElementType theType )
4410 if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
4412 mySurf = TopoDS::Face( theShape );
4413 BRepAdaptor_Surface SA( mySurf, myUseBoundaries );
4415 u1 = SA.FirstUParameter(),
4416 u2 = SA.LastUParameter(),
4417 v1 = SA.FirstVParameter(),
4418 v2 = SA.LastVParameter();
4419 Handle(Geom_Surface) surf = BRep_Tool::Surface( mySurf );
4420 myProjector.Init( surf, u1,u2, v1,v2 );
4424 void ElementsOnSurface::process()
4427 if ( mySurf.IsNull() )
4430 if ( !myMeshModifTracer.GetMesh() )
4433 int nbElems = FromSmIdType<int>( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ));
4435 myIds.ReSize( nbElems );
4437 SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType );
4438 for(; anIter->more(); )
4439 process( anIter->next() );
4442 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
4444 SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
4445 bool isSatisfy = true;
4446 for ( ; aNodeItr->more(); )
4448 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
4449 if ( !isOnSurface( aNode ) )
4456 myIds.Add( theElemPtr->GetID() );
4459 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
4461 if ( mySurf.IsNull() )
4464 gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
4465 // double aToler2 = myToler * myToler;
4466 // if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
4468 // gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
4469 // if ( aPln.SquareDistance( aPnt ) > aToler2 )
4472 // else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
4474 // gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
4475 // double aRad = aCyl.Radius();
4476 // gp_Ax3 anAxis = aCyl.Position();
4477 // gp_XYZ aLoc = aCyl.Location().XYZ();
4478 // double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4479 // double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
4480 // if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
4485 myProjector.Perform( aPnt );
4486 bool isOn = ( myProjector.IsDone() && myProjector.LowerDistance() <= myToler );
4492 //================================================================================
4494 //================================================================================
4497 const int theIsCheckedFlag = 0x0000100;
4500 struct ElementsOnShape::Classifier
4502 Classifier(): mySolidClfr(0), myProjFace(0), myProjEdge(0), myFlags(0) { myU = myV = 1e100; }
4504 void Init(const TopoDS_Shape& s, double tol, const Bnd_B3d* box = 0 );
4505 bool IsOut(const gp_Pnt& p) { return SetChecked( true ), (this->*myIsOutFun)( p ); }
4506 TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); }
4507 const TopoDS_Shape& Shape() const { return myShape; }
4508 const Bnd_B3d* GetBndBox() const { return & myBox; }
4509 double Tolerance() const { return myTol; }
4510 bool IsChecked() { return myFlags & theIsCheckedFlag; }
4511 bool IsSetFlag( int flag ) const { return myFlags & flag; }
4512 void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); }
4513 void SetFlag ( int flag ) { myFlags |= flag; }
4514 void UnsetFlag( int flag ) { myFlags &= ~flag; }
4515 void GetParams( double & u, double & v ) const { u = myU; v = myV; }
4518 bool isOutOfSolid (const gp_Pnt& p);
4519 bool isOutOfBox (const gp_Pnt& p);
4520 bool isOutOfFace (const gp_Pnt& p);
4521 bool isOutOfEdge (const gp_Pnt& p);
4522 bool isOutOfVertex(const gp_Pnt& p);
4523 bool isOutOfNone (const gp_Pnt& /*p*/) { return true; }
4524 bool isBox (const TopoDS_Shape& s);
4526 TopoDS_Shape prepareSolid( const TopoDS_Shape& theSolid );
4528 bool (Classifier::* myIsOutFun)(const gp_Pnt& p);
4529 BRepClass3d_SolidClassifier* mySolidClfr;
4531 GeomAPI_ProjectPointOnSurf* myProjFace;
4532 GeomAPI_ProjectPointOnCurve* myProjEdge;
4534 TopoDS_Shape myShape;
4536 double myU, myV; // result of isOutOfFace() and isOutOfEdge()
4540 struct ElementsOnShape::OctreeClassifier : public SMESH_Octree
4542 OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers );
4543 OctreeClassifier( const OctreeClassifier* otherTree,
4544 const std::vector< ElementsOnShape::Classifier >& clsOther,
4545 std::vector< ElementsOnShape::Classifier >& cls );
4546 void GetClassifiersAtPoint( const gp_XYZ& p,
4547 std::vector< ElementsOnShape::Classifier* >& classifiers );
4551 OctreeClassifier() {}
4552 SMESH_Octree* newChild() const { return new OctreeClassifier; }
4553 void buildChildrenData();
4554 Bnd_B3d* buildRootBox();
4556 std::vector< ElementsOnShape::Classifier* > myClassifiers;
4560 ElementsOnShape::ElementsOnShape():
4562 myType(SMDSAbs_All),
4563 myToler(Precision::Confusion()),
4564 myAllNodesFlag(false)
4568 ElementsOnShape::~ElementsOnShape()
4573 Predicate* ElementsOnShape::clone() const
4575 size_t size = sizeof( *this );
4577 size += myOctree->GetSize();
4578 if ( !myClassifiers.empty() )
4579 size += sizeof( myClassifiers[0] ) * myClassifiers.size();
4580 if ( !myWorkClassifiers.empty() )
4581 size += sizeof( myWorkClassifiers[0] ) * myWorkClassifiers.size();
4582 if ( size > 1e+9 ) // 1G
4585 if (SALOME::VerbosityActivated())
4586 std::cout << "Avoid ElementsOnShape::clone(), too large: " << size << " bytes " << std::endl;
4591 ElementsOnShape* cln = new ElementsOnShape();
4592 cln->SetAllNodes ( myAllNodesFlag );
4593 cln->SetTolerance( myToler );
4594 cln->SetMesh ( myMeshModifTracer.GetMesh() );
4595 cln->myShape = myShape; // avoid creation of myClassifiers
4596 cln->SetShape ( myShape, myType );
4597 cln->myClassifiers.resize( myClassifiers.size() );
4598 for ( size_t i = 0; i < myClassifiers.size(); ++i )
4599 cln->myClassifiers[ i ].Init( BRepBuilderAPI_Copy( myClassifiers[ i ].Shape()),
4600 myToler, myClassifiers[ i ].GetBndBox() );
4601 if ( myOctree ) // copy myOctree
4603 cln->myOctree = new OctreeClassifier( myOctree, myClassifiers, cln->myClassifiers );
4608 SMDSAbs_ElementType ElementsOnShape::GetType() const
4613 void ElementsOnShape::SetTolerance (const double theToler)
4615 if (myToler != theToler)
4618 TopoDS_Shape s = myShape;
4620 SetShape( s, myType );
4624 double ElementsOnShape::GetTolerance() const
4629 void ElementsOnShape::SetAllNodes (bool theAllNodes)
4631 myAllNodesFlag = theAllNodes;
4634 void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh)
4636 myMeshModifTracer.SetMesh( theMesh );
4637 if ( myMeshModifTracer.IsMeshModified())
4639 size_t nbNodes = theMesh ? theMesh->NbNodes() : 0;
4640 if ( myNodeIsChecked.size() == nbNodes )
4642 std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4646 SMESHUtils::FreeVector( myNodeIsChecked );
4647 SMESHUtils::FreeVector( myNodeIsOut );
4648 myNodeIsChecked.resize( nbNodes, false );
4649 myNodeIsOut.resize( nbNodes );
4654 bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut )
4656 if ( n->GetID() >= (int) myNodeIsChecked.size() ||
4657 !myNodeIsChecked[ n->GetID() ])
4660 isOut = myNodeIsOut[ n->GetID() ];
4664 void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool isOut )
4666 if ( n->GetID() < (int) myNodeIsChecked.size() )
4668 myNodeIsChecked[ n->GetID() ] = true;
4669 myNodeIsOut [ n->GetID() ] = isOut;
4673 void ElementsOnShape::SetShape (const TopoDS_Shape& theShape,
4674 const SMDSAbs_ElementType theType)
4676 bool shapeChanges = ( myShape != theShape );
4679 if ( myShape.IsNull() ) return;
4683 // find most complex shapes
4684 TopTools_IndexedMapOfShape shapesMap;
4685 TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
4686 TopExp_Explorer sub;
4687 for ( int i = 0; i < 4; ++i )
4689 if ( shapesMap.IsEmpty() )
4690 for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() )
4691 shapesMap.Add( sub.Current() );
4693 for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() )
4694 shapesMap.Add( sub.Current() );
4698 myClassifiers.resize( shapesMap.Extent() );
4699 for ( int i = 0; i < shapesMap.Extent(); ++i )
4700 myClassifiers[ i ].Init( shapesMap( i+1 ), myToler );
4703 if ( theType == SMDSAbs_Node )
4705 SMESHUtils::FreeVector( myNodeIsChecked );
4706 SMESHUtils::FreeVector( myNodeIsOut );
4710 std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
4714 void ElementsOnShape::clearClassifiers()
4716 // for ( size_t i = 0; i < myClassifiers.size(); ++i )
4717 // delete myClassifiers[ i ];
4718 myClassifiers.clear();
4724 bool ElementsOnShape::IsSatisfy( long elemId )
4726 if ( myClassifiers.empty() )
4729 const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
4730 if ( myType == SMDSAbs_Node )
4731 return IsSatisfy( mesh->FindNode( elemId ));
4732 return IsSatisfy( mesh->FindElement( elemId ));
4735 bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
4740 bool isSatisfy = myAllNodesFlag, isNodeOut;
4742 gp_XYZ centerXYZ (0, 0, 0);
4744 if ( !myOctree && myClassifiers.size() > 5 )
4746 myWorkClassifiers.resize( myClassifiers.size() );
4747 for ( size_t i = 0; i < myClassifiers.size(); ++i )
4748 myWorkClassifiers[ i ] = & myClassifiers[ i ];
4749 myOctree = new OctreeClassifier( myWorkClassifiers );
4751 SMESHUtils::FreeVector( myWorkClassifiers );
4754 for ( int i = 0, nb = elem->NbNodes(); i < nb && (isSatisfy == myAllNodesFlag); ++i )
4756 SMESH_TNodeXYZ aPnt( elem->GetNode( i ));
4760 if ( !getNodeIsOut( aPnt._node, isNodeOut ))
4764 myWorkClassifiers.clear();
4765 myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4767 for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4768 myWorkClassifiers[i]->SetChecked( false );
4770 for ( size_t i = 0; i < myWorkClassifiers.size() && isNodeOut; ++i )
4771 if ( !myWorkClassifiers[i]->IsChecked() )
4772 isNodeOut = myWorkClassifiers[i]->IsOut( aPnt );
4776 for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i )
4777 isNodeOut = myClassifiers[i].IsOut( aPnt );
4779 setNodeIsOut( aPnt._node, isNodeOut );
4781 isSatisfy = !isNodeOut;
4784 // Check the center point for volumes MantisBug 0020168
4787 myClassifiers[0].ShapeType() == TopAbs_SOLID )
4789 centerXYZ /= elem->NbNodes();
4793 myWorkClassifiers.clear();
4794 myOctree->GetClassifiersAtPoint( centerXYZ, myWorkClassifiers );
4795 for ( size_t i = 0; i < myWorkClassifiers.size() && !isSatisfy; ++i )
4796 isSatisfy = ! myWorkClassifiers[i]->IsOut( centerXYZ );
4800 for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i )
4801 isSatisfy = ! myClassifiers[i].IsOut( centerXYZ );
4808 //================================================================================
4810 * \brief Check and optionally return a satisfying shape
4812 //================================================================================
4814 bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
4815 TopoDS_Shape* okShape)
4820 if ( !myOctree && myClassifiers.size() > 5 )
4822 myWorkClassifiers.resize( myClassifiers.size() );
4823 for ( size_t i = 0; i < myClassifiers.size(); ++i )
4824 myWorkClassifiers[ i ] = & myClassifiers[ i ];
4825 myOctree = new OctreeClassifier( myWorkClassifiers );
4828 bool isNodeOut = true;
4830 if ( okShape || !getNodeIsOut( node, isNodeOut ))
4832 SMESH_NodeXYZ aPnt = node;
4835 myWorkClassifiers.clear();
4836 myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
4838 for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4839 myWorkClassifiers[i]->SetChecked( false );
4841 for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
4842 if ( !myWorkClassifiers[i]->IsChecked() &&
4843 !myWorkClassifiers[i]->IsOut( aPnt ))
4847 *okShape = myWorkClassifiers[i]->Shape();
4848 myWorkClassifiers[i]->GetParams( myU, myV );
4854 for ( size_t i = 0; i < myClassifiers.size(); ++i )
4855 if ( !myClassifiers[i].IsOut( aPnt ))
4859 *okShape = myClassifiers[i].Shape();
4860 myClassifiers[i].GetParams( myU, myV );
4864 setNodeIsOut( node, isNodeOut );
4870 void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
4872 const Bnd_B3d* theBox )
4878 bool isShapeBox = false;
4879 switch ( myShape.ShapeType() )
4883 if (( isShapeBox = isBox( theShape )))
4885 myIsOutFun = & ElementsOnShape::Classifier::isOutOfBox;
4889 mySolidClfr = new BRepClass3d_SolidClassifier( prepareSolid( theShape ));
4890 myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid;
4896 Standard_Real u1,u2,v1,v2;
4897 Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape ));
4898 if ( surf.IsNull() )
4899 myIsOutFun = & ElementsOnShape::Classifier::isOutOfNone;
4902 surf->Bounds( u1,u2,v1,v2 );
4903 myProjFace = new GeomAPI_ProjectPointOnSurf;
4904 myProjFace->Init( surf, u1,u2, v1,v2, myTol );
4905 myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace;
4911 Standard_Real u1, u2;
4912 Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2);
4913 if ( curve.IsNull() )
4914 myIsOutFun = & ElementsOnShape::Classifier::isOutOfNone;
4917 myProjEdge = new GeomAPI_ProjectPointOnCurve;
4918 myProjEdge->Init( curve, u1, u2 );
4919 myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge;
4925 myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) );
4926 myIsOutFun = & ElementsOnShape::Classifier::isOutOfVertex;
4930 throw SALOME_Exception("Programmer error in usage of ElementsOnShape::Classifier");
4942 if ( myShape.ShapeType() == TopAbs_FACE )
4944 BRepAdaptor_Surface SA( TopoDS::Face( myShape ), /*useBoundaries=*/false );
4945 if ( SA.GetType() == GeomAbs_BSplineSurface )
4946 BRepBndLib::AddOptimal( myShape, box,
4947 /*useTriangulation=*/true, /*useShapeTolerance=*/true );
4950 BRepBndLib::Add( myShape, box );
4952 myBox.Add( box.CornerMin() );
4953 myBox.Add( box.CornerMax() );
4954 gp_XYZ halfSize = 0.5 * ( box.CornerMax().XYZ() - box.CornerMin().XYZ() );
4955 for ( int iDim = 1; iDim <= 3; ++iDim )
4957 double x = halfSize.Coord( iDim );
4958 halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x ));
4960 myBox.SetHSize( halfSize );
4965 ElementsOnShape::Classifier::~Classifier()
4967 delete mySolidClfr; mySolidClfr = 0;
4968 delete myProjFace; myProjFace = 0;
4969 delete myProjEdge; myProjEdge = 0;
4972 TopoDS_Shape ElementsOnShape::Classifier::prepareSolid( const TopoDS_Shape& theSolid )
4974 // try to limit tolerance of theSolid down to myTol (issue #19026)
4976 // check if tolerance of theSolid is more than myTol
4977 bool tolIsOk = true; // max tolerance is at VERTEXes
4978 for ( TopExp_Explorer exp( theSolid, TopAbs_VERTEX ); exp.More() && tolIsOk; exp.Next() )
4979 tolIsOk = ( myTol >= BRep_Tool::Tolerance( TopoDS::Vertex( exp.Current() )));
4983 // make a copy to prevent the original shape from changes
4984 TopoDS_Shape resultShape = BRepBuilderAPI_Copy( theSolid );
4986 if ( !GEOMUtils::FixShapeTolerance( resultShape, TopAbs_SHAPE, myTol ))
4991 bool ElementsOnShape::Classifier::isOutOfSolid( const gp_Pnt& p )
4993 if ( isOutOfBox( p )) return true;
4994 mySolidClfr->Perform( p, myTol );
4995 return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON );
4998 bool ElementsOnShape::Classifier::isOutOfBox( const gp_Pnt& p )
5000 return myBox.IsOut( p.XYZ() );
5003 bool ElementsOnShape::Classifier::isOutOfFace( const gp_Pnt& p )
5005 if ( isOutOfBox( p )) return true;
5006 myProjFace->Perform( p );
5007 if ( myProjFace->IsDone() && myProjFace->LowerDistance() <= myTol )
5009 // check relatively to the face
5010 myProjFace->LowerDistanceParameters( myU, myV );
5011 gp_Pnt2d aProjPnt( myU, myV );
5012 BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
5013 if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON )
5019 bool ElementsOnShape::Classifier::isOutOfEdge( const gp_Pnt& p )
5021 if ( isOutOfBox( p )) return true;
5022 myProjEdge->Perform( p );
5023 bool isOn = ( myProjEdge->NbPoints() > 0 && myProjEdge->LowerDistance() <= myTol );
5025 myU = myProjEdge->LowerDistanceParameter();
5029 bool ElementsOnShape::Classifier::isOutOfVertex( const gp_Pnt& p )
5031 return ( myVertexXYZ.Distance( p ) > myTol );
5034 bool ElementsOnShape::Classifier::isBox(const TopoDS_Shape& theShape )
5036 TopTools_IndexedMapOfShape vMap;
5037 TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
5038 if ( vMap.Extent() != 8 )
5042 for ( int i = 1; i <= 8; ++i )
5043 myBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))).XYZ() );
5045 gp_XYZ pMin = myBox.CornerMin(), pMax = myBox.CornerMax();
5046 for ( int i = 1; i <= 8; ++i )
5048 gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vMap( i )));
5049 for ( int iC = 1; iC <= 3; ++ iC )
5051 double d1 = Abs( pMin.Coord( iC ) - p.Coord( iC ));
5052 double d2 = Abs( pMax.Coord( iC ) - p.Coord( iC ));
5053 if ( Min( d1, d2 ) > myTol )
5057 myBox.Enlarge( myTol );
5062 OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers )
5063 :SMESH_Octree( new SMESH_TreeLimit )
5065 myClassifiers = classifiers;
5070 OctreeClassifier::OctreeClassifier( const OctreeClassifier* otherTree,
5071 const std::vector< ElementsOnShape::Classifier >& clsOther,
5072 std::vector< ElementsOnShape::Classifier >& cls )
5073 :SMESH_Octree( new SMESH_TreeLimit )
5075 myBox = new Bnd_B3d( *otherTree->getBox() );
5077 if (( myIsLeaf = otherTree->isLeaf() ))
5079 myClassifiers.resize( otherTree->myClassifiers.size() );
5080 for ( size_t i = 0; i < otherTree->myClassifiers.size(); ++i )
5082 int ind = otherTree->myClassifiers[i] - & clsOther[0];
5083 myClassifiers[ i ] = & cls[ ind ];
5086 else if ( otherTree->myChildren )
5088 myChildren = new SMESH_Tree< Bnd_B3d, 8 > * [ 8 ];
5089 for ( int i = 0; i < nbChildren(); i++ )
5091 new OctreeClassifier( static_cast<const OctreeClassifier*>( otherTree->myChildren[i]),
5096 void ElementsOnShape::
5097 OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
5098 std::vector< ElementsOnShape::Classifier* >& result )
5100 if ( getBox()->IsOut( point ))
5105 for ( size_t i = 0; i < myClassifiers.size(); ++i )
5106 if ( !myClassifiers[i]->GetBndBox()->IsOut( point ))
5107 result.push_back( myClassifiers[i] );
5111 for (int i = 0; i < nbChildren(); i++)
5112 ((OctreeClassifier*) myChildren[i])->GetClassifiersAtPoint( point, result );
5116 size_t ElementsOnShape::OctreeClassifier::GetSize()
5118 size_t res = sizeof( *this );
5119 if ( !myClassifiers.empty() )
5120 res += sizeof( myClassifiers[0] ) * myClassifiers.size();
5123 for (int i = 0; i < nbChildren(); i++)
5124 res += ((OctreeClassifier*) myChildren[i])->GetSize();
5129 void ElementsOnShape::OctreeClassifier::buildChildrenData()
5131 // distribute myClassifiers among myChildren
5133 const int childFlag[8] = { 0x0000001,
5141 int nbInChild[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
5143 for ( size_t i = 0; i < myClassifiers.size(); ++i )
5145 for ( int j = 0; j < nbChildren(); j++ )
5147 if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() ))
5149 myClassifiers[i]->SetFlag( childFlag[ j ]);
5155 for ( int j = 0; j < nbChildren(); j++ )
5157 OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ j ]);
5158 child->myClassifiers.resize( nbInChild[ j ]);
5159 for ( size_t i = 0; nbInChild[ j ] && i < myClassifiers.size(); ++i )
5161 if ( myClassifiers[ i ]->IsSetFlag( childFlag[ j ]))
5164 child->myClassifiers[ nbInChild[ j ]] = myClassifiers[ i ];
5165 myClassifiers[ i ]->UnsetFlag( childFlag[ j ]);
5169 SMESHUtils::FreeVector( myClassifiers );
5171 // define if a child isLeaf()
5172 for ( int i = 0; i < nbChildren(); i++ )
5174 OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
5175 child->myIsLeaf = ( child->myClassifiers.size() <= 5 ||
5176 child->maxSize() < child->myClassifiers[0]->Tolerance() );
5180 Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox()
5182 Bnd_B3d* box = new Bnd_B3d;
5183 for ( size_t i = 0; i < myClassifiers.size(); ++i )
5184 box->Add( *myClassifiers[i]->GetBndBox() );
5189 Class : BelongToGeom
5190 Description : Predicate for verifying whether entity belongs to
5191 specified geometrical support
5194 BelongToGeom::BelongToGeom()
5196 myType(SMDSAbs_NbElementTypes),
5197 myIsSubshape(false),
5198 myTolerance(Precision::Confusion())
5201 Predicate* BelongToGeom::clone() const
5203 BelongToGeom* cln = 0;
5204 if ( myElementsOnShapePtr )
5205 if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
5207 cln = new BelongToGeom( *this );
5208 cln->myElementsOnShapePtr.reset( eos );
5213 void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh )
5215 if ( myMeshDS != theMesh )
5217 myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
5220 if ( myElementsOnShapePtr )
5221 myElementsOnShapePtr->SetMesh( myMeshDS );
5224 void BelongToGeom::SetGeom( const TopoDS_Shape& theShape )
5226 if ( myShape != theShape )
5233 static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap,
5234 const TopoDS_Shape& theShape)
5236 if (theMap.Contains(theShape)) return true;
5238 if (theShape.ShapeType() == TopAbs_COMPOUND ||
5239 theShape.ShapeType() == TopAbs_COMPSOLID)
5241 TopoDS_Iterator anIt (theShape, Standard_True, Standard_True);
5242 for (; anIt.More(); anIt.Next())
5244 if (!IsSubShape(theMap, anIt.Value())) {
5254 void BelongToGeom::init()
5256 if ( !myMeshDS || myShape.IsNull() ) return;
5258 // is sub-shape of main shape?
5259 TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
5260 if (aMainShape.IsNull()) {
5261 myIsSubshape = false;
5264 TopTools_IndexedMapOfShape aMap;
5265 TopExp::MapShapes( aMainShape, aMap );
5266 myIsSubshape = IsSubShape( aMap, myShape );
5270 TopExp::MapShapes( myShape, aMap );
5271 mySubShapesIDs.Clear();
5272 for ( int i = 1; i <= aMap.Extent(); ++i )
5274 int subID = myMeshDS->ShapeToIndex( aMap( i ));
5276 mySubShapesIDs.Add( subID );
5281 //if (!myIsSubshape) // to be always ready to check an element not bound to geometry
5283 if ( !myElementsOnShapePtr )
5284 myElementsOnShapePtr.reset( new ElementsOnShape() );
5285 myElementsOnShapePtr->SetTolerance( myTolerance );
5286 myElementsOnShapePtr->SetAllNodes( true ); // "belong", while false means "lays on"
5287 myElementsOnShapePtr->SetMesh( myMeshDS );
5288 myElementsOnShapePtr->SetShape( myShape, myType );
5292 bool BelongToGeom::IsSatisfy (long theId)
5294 if (myMeshDS == 0 || myShape.IsNull())
5299 return myElementsOnShapePtr->IsSatisfy(theId);
5304 if (myType == SMDSAbs_Node)
5306 if ( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ))
5308 if ( aNode->getshapeId() < 1 )
5309 return myElementsOnShapePtr->IsSatisfy(theId);
5311 return mySubShapesIDs.Contains( aNode->getshapeId() );
5316 if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId ))
5318 if ( myType == SMDSAbs_All || anElem->GetType() == myType )
5320 if ( anElem->getshapeId() < 1 )
5321 return myElementsOnShapePtr->IsSatisfy(theId);
5323 return mySubShapesIDs.Contains( anElem->getshapeId() );
5331 void BelongToGeom::SetType (SMDSAbs_ElementType theType)
5333 if ( myType != theType )
5340 SMDSAbs_ElementType BelongToGeom::GetType() const
5345 TopoDS_Shape BelongToGeom::GetShape()
5350 const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const
5355 void BelongToGeom::SetTolerance (double theTolerance)
5357 myTolerance = theTolerance;
5361 double BelongToGeom::GetTolerance()
5368 Description : Predicate for verifying whether entiy lying or partially lying on
5369 specified geometrical support
5372 LyingOnGeom::LyingOnGeom()
5374 myType(SMDSAbs_NbElementTypes),
5375 myIsSubshape(false),
5376 myTolerance(Precision::Confusion())
5379 Predicate* LyingOnGeom::clone() const
5381 LyingOnGeom* cln = 0;
5382 if ( myElementsOnShapePtr )
5383 if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
5385 cln = new LyingOnGeom( *this );
5386 cln->myElementsOnShapePtr.reset( eos );
5391 void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh )
5393 if ( myMeshDS != theMesh )
5395 myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
5398 if ( myElementsOnShapePtr )
5399 myElementsOnShapePtr->SetMesh( myMeshDS );
5402 void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape )
5404 if ( myShape != theShape )
5411 void LyingOnGeom::init()
5413 if (!myMeshDS || myShape.IsNull()) return;
5415 // is sub-shape of main shape?
5416 TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
5417 if (aMainShape.IsNull()) {
5418 myIsSubshape = false;
5421 myIsSubshape = myMeshDS->IsGroupOfSubShapes( myShape );
5426 TopTools_IndexedMapOfShape shapes;
5427 TopExp::MapShapes( myShape, shapes );
5428 mySubShapesIDs.Clear();
5429 for ( int i = 1; i <= shapes.Extent(); ++i )
5431 int subID = myMeshDS->ShapeToIndex( shapes( i ));
5433 mySubShapesIDs.Add( subID );
5436 // else // to be always ready to check an element not bound to geometry
5438 if ( !myElementsOnShapePtr )
5439 myElementsOnShapePtr.reset( new ElementsOnShape() );
5440 myElementsOnShapePtr->SetTolerance( myTolerance );
5441 myElementsOnShapePtr->SetAllNodes( false ); // lays on, while true means "belong"
5442 myElementsOnShapePtr->SetMesh( myMeshDS );
5443 myElementsOnShapePtr->SetShape( myShape, myType );
5447 bool LyingOnGeom::IsSatisfy( long theId )
5449 if ( myMeshDS == 0 || myShape.IsNull() )
5454 return myElementsOnShapePtr->IsSatisfy(theId);
5459 const SMDS_MeshElement* elem =
5460 ( myType == SMDSAbs_Node ) ? myMeshDS->FindNode( theId ) : myMeshDS->FindElement( theId );
5462 if ( mySubShapesIDs.Contains( elem->getshapeId() ))
5465 if (( elem->GetType() != SMDSAbs_Node ) &&
5466 ( myType == SMDSAbs_All || elem->GetType() == myType ))
5468 SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator();
5469 while ( nodeItr->more() )
5471 const SMDS_MeshElement* aNode = nodeItr->next();
5472 if ( mySubShapesIDs.Contains( aNode->getshapeId() ))
5480 void LyingOnGeom::SetType( SMDSAbs_ElementType theType )
5482 if ( myType != theType )
5489 SMDSAbs_ElementType LyingOnGeom::GetType() const
5494 TopoDS_Shape LyingOnGeom::GetShape()
5499 const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const
5504 void LyingOnGeom::SetTolerance (double theTolerance)
5506 myTolerance = theTolerance;
5510 double LyingOnGeom::GetTolerance()
5515 TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0)
5518 TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n), myElem(0)
5521 TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t), myElem(0)
5524 TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray), myElem(theSequenceOfXYZ.myElem)
5527 template <class InputIterator>
5528 TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd), myElem(0)
5531 TSequenceOfXYZ::~TSequenceOfXYZ()
5534 TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ)
5536 myArray = theSequenceOfXYZ.myArray;
5537 myElem = theSequenceOfXYZ.myElem;
5541 gp_XYZ& TSequenceOfXYZ::operator()(size_type n)
5543 return myArray[n-1];
5546 const gp_XYZ& TSequenceOfXYZ::operator()(size_type n) const
5548 return myArray[n-1];
5551 void TSequenceOfXYZ::clear()
5556 void TSequenceOfXYZ::reserve(size_type n)
5561 void TSequenceOfXYZ::push_back(const gp_XYZ& v)
5563 myArray.push_back(v);
5566 TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const
5568 return myArray.size();
5571 SMDSAbs_EntityType TSequenceOfXYZ::getElementEntity() const
5573 return myElem ? myElem->GetEntityType() : SMDSEntity_Last;
5576 TMeshModifTracer::TMeshModifTracer():
5577 myMeshModifTime(0), myMesh(0)
5580 void TMeshModifTracer::SetMesh( const SMDS_Mesh* theMesh )
5582 if ( theMesh != myMesh )
5583 myMeshModifTime = 0;
5586 bool TMeshModifTracer::IsMeshModified()
5588 bool modified = false;
5591 modified = ( myMeshModifTime != myMesh->GetMTime() );
5592 myMeshModifTime = myMesh->GetMTime();