X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FControls%2FSMESH_Controls.cxx;h=7fcc948da5ef4c6789c2fdd0fe844ea5264c50ab;hp=66601f3dfd478a4841ff615dab6905aadd3d2b16;hb=24dd5df5f053455d186962be79786dc9237a1a0e;hpb=f5016d85b7b4b88623723027a1585c6414c4dc66 diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 66601f3df..7fcc948da 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,29 +23,39 @@ #include "SMESH_ControlsDef.hxx" #include "SMDS_BallElement.hxx" +#include "SMDS_FacePosition.hxx" #include "SMDS_Iterator.hxx" #include "SMDS_Mesh.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" -#include "SMDS_QuadraticEdge.hxx" -#include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_VolumeTool.hxx" #include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_GroupOnFilter.hxx" #include "SMESHDS_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_OctreeNode.hxx" +#include + #include +#include +#include +#include #include #include +#include #include #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -65,12 +75,14 @@ #include #include - /* AUXILIARY METHODS */ -namespace{ +namespace { + + const double theEps = 1e-100; + const double theInf = 1e+100; inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode ) { @@ -85,6 +97,15 @@ namespace{ v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 ); } + inline double getCos2( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 ) + { + gp_Vec v1( P1 - P2 ), v2( P3 - P2 ); + double dot = v1 * v2, len1 = v1.SquareMagnitude(), len2 = v2.SquareMagnitude(); + + return ( dot < 0 || len1 < gp::Resolution() || len2 < gp::Resolution() ? -1 : + dot * dot / len1 / len2 ); + } + inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 ) { gp_Vec aVec1( P2 - P1 ); @@ -124,13 +145,13 @@ namespace{ // +-----+------+ +-----+------+ // | | | | // | | | | - // result sould be 2 in both cases + // result should be 2 in both cases // int aResult0 = 0, aResult1 = 0; // last node, it is a medium one in a quadratic edge const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 ); - const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 ); - const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 ); + const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 ); + const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 ); if ( aNode1 == aLastNode ) aNode1 = 0; SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator(); @@ -152,29 +173,6 @@ namespace{ } int aResult = std::max ( aResult0, aResult1 ); -// TColStd_MapOfInteger aMap; - -// SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator(); -// if ( anIter != 0 ) { -// while( anIter->more() ) { -// const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next(); -// if ( aNode == 0 ) -// return 0; -// SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator(); -// while( anElemIter->more() ) { -// const SMDS_MeshElement* anElem = anElemIter->next(); -// if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) { -// int anId = anElem->GetID(); - -// if ( anIter->more() ) // i.e. first node -// aMap.Add( anId ); -// else if ( aMap.Contains( anId ) ) -// aResult++; -// } -// } -// } -// } - return aResult; } @@ -190,7 +188,7 @@ namespace{ n += q2 ^ q3; } double len = n.Modulus(); - bool zeroLen = ( len <= numeric_limits::min()); + bool zeroLen = ( len <= std::numeric_limits::min()); if ( !zeroLen ) n /= len; @@ -208,10 +206,13 @@ using namespace SMESH::Controls; * FUNCTORS */ +//================================================================================ /* Class : NumericalFunctor Description : Base class for numerical functors */ +//================================================================================ + NumericalFunctor::NumericalFunctor(): myMesh(NULL) { @@ -223,7 +224,7 @@ void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh ) myMesh = theMesh; } -bool NumericalFunctor::GetPoints(const int theId, +bool NumericalFunctor::GetPoints(const int theId, TSequenceOfXYZ& theRes ) const { theRes.clear(); @@ -231,7 +232,11 @@ bool NumericalFunctor::GetPoints(const int theId, if ( myMesh == 0 ) return false; - return GetPoints( myMesh->FindElement( theId ), theRes ); + const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); + if ( !anElem || anElem->GetType() != this->GetType() ) + return false; + + return GetPoints( anElem, theRes ); } bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, @@ -239,37 +244,19 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, { theRes.clear(); - if ( anElem == 0) + if ( anElem == 0 ) return false; theRes.reserve( anElem->NbNodes() ); + theRes.setElement( anElem ); // Get nodes of the element - SMDS_ElemIteratorPtr anIter; - - if ( anElem->IsQuadratic() ) { - switch ( anElem->GetType() ) { - case SMDSAbs_Edge: - anIter = dynamic_cast - (anElem)->interlacedNodesElemIterator(); - break; - case SMDSAbs_Face: - anIter = dynamic_cast - (anElem)->interlacedNodesElemIterator(); - break; - default: - anIter = anElem->nodesIterator(); - //return false; - } - } - else { - anIter = anElem->nodesIterator(); - } - + SMDS_NodeIteratorPtr anIter= anElem->interlacedNodesIterator(); if ( anIter ) { + SMESH_NodeXYZ p; while( anIter->more() ) { - if ( const SMDS_MeshNode* aNode = static_cast( anIter->next() )) - theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); + if ( p.Set( anIter->next() )) + theRes.push_back( p ); } } @@ -294,7 +281,7 @@ double NumericalFunctor::GetValue( long theId ) myCurrElement = myMesh->FindElement( theId ); TSequenceOfXYZ P; - if ( GetPoints( theId, P )) + if ( GetPoints( theId, P )) // elem type is checked here aVal = Round( GetValue( P )); return aVal; @@ -316,11 +303,12 @@ double NumericalFunctor::Round( const double & aVal ) */ //================================================================================ -void NumericalFunctor::GetHistogram(int nbIntervals, - std::vector& nbEvents, - std::vector& funValues, - const vector& elements, - const double* minmax) +void NumericalFunctor::GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues, + const std::vector& elements, + const double* minmax, + const bool isLogarithmic) { if ( nbIntervals < 1 || !myMesh || @@ -333,13 +321,13 @@ void NumericalFunctor::GetHistogram(int nbIntervals, std::multiset< double > values; if ( elements.empty() ) { - SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() ); while ( elemIt->more() ) values.insert( GetValue( elemIt->next()->GetID() )); } else { - vector::const_iterator id = elements.begin(); + std::vector::const_iterator id = elements.begin(); for ( ; id != elements.end(); ++id ) values.insert( GetValue( *id )); } @@ -373,8 +361,15 @@ void NumericalFunctor::GetHistogram(int nbIntervals, for ( int i = 0; i < nbIntervals; ++i ) { // find end value of i-th interval - double r = (i+1) / double( nbIntervals ); - funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + double r = (i+1) / double(nbIntervals); + if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) { + double logmin = log10(funValues.front()); + double lval = logmin + r * (log10(funValues.back()) - logmin); + funValues[i+1] = pow(10.0, lval); + } + else { + funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + } // count values in the i-th interval if there are any if ( min != values.end() && *min <= funValues[i+1] ) @@ -390,9 +385,11 @@ void NumericalFunctor::GetHistogram(int nbIntervals, } //======================================================================= -//function : GetValue -//purpose : -//======================================================================= +/* + Class : Volume + Description : Functor calculating volume of a 3D element +*/ +//================================================================================ double Volume::GetValue( long theElementId ) { @@ -404,86 +401,93 @@ double Volume::GetValue( long theElementId ) return 0; } -//======================================================================= -//function : GetBadRate -//purpose : meaningless as it is not quality control functor -//======================================================================= - double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const { return Value; } -//======================================================================= -//function : GetType -//purpose : -//======================================================================= - SMDSAbs_ElementType Volume::GetType() const { return SMDSAbs_Volume; } - +//======================================================================= /* Class : MaxElementLength2D Description : Functor calculating maximum length of 2D element */ +//================================================================================ + +double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P ) +{ + if(P.size() == 0) + return 0.; + double aVal = 0; + int len = P.size(); + if( len == 3 ) { // triangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + } + else if( len == 4 ) { // quadrangles + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 3 )); + double D2 = getDistance(P( 2 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + } + else if( len == 6 ) { // quadratic triangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); + aVal = Max(L1,Max(L2,L3)); + } + else if( len == 8 || len == 9 ) { // quadratic quadrangles + double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); + double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); + double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 )); + double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 )); + double D1 = getDistance(P( 1 ),P( 5 )); + double D2 = getDistance(P( 3 ),P( 7 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); + } + // Diagonals are undefined for concave polygons + // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon + // { + // // sides + // aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 )); + // for ( size_t i = 1; i < P.size()-1; i += 2 ) + // { + // double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )); + // aVal = Max( aVal, L ); + // } + // // diagonals + // for ( int i = P.size()-5; i > 0; i -= 2 ) + // for ( int j = i + 4; j < P.size() + i - 2; i += 2 ) + // { + // double D = getDistance( P( i ), P( j )); + // aVal = Max( aVal, D ); + // } + // } + // { // polygons + + // } + + if( myPrecision >= 0 ) + { + double prec = pow( 10., (double)myPrecision ); + aVal = floor( aVal * prec + 0.5 ) / prec; + } + return aVal; +} double MaxElementLength2D::GetValue( long theElementId ) { TSequenceOfXYZ P; - if( GetPoints( theElementId, P ) ) { - double aVal = 0; - const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId ); - SMDSAbs_ElementType aType = aElem->GetType(); - int len = P.size(); - switch( aType ) { - case SMDSAbs_Face: - if( len == 3 ) { // triangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - break; - } - else if( len == 4 ) { // quadrangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 1 )); - double D1 = getDistance(P( 1 ),P( 3 )); - double D2 = getDistance(P( 2 ),P( 4 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); - break; - } - else if( len == 6 ) { // quadratic triangles - double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); - double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); - double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - break; - } - else if( len == 8 || len == 9 ) { // quadratic quadrangles - double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); - double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); - double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 )); - double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 )); - double D1 = getDistance(P( 1 ),P( 5 )); - double D2 = getDistance(P( 3 ),P( 7 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); - break; - } - } - - if( myPrecision >= 0 ) - { - double prec = pow( 10., (double)myPrecision ); - aVal = floor( aVal * prec + 0.5 ) / prec; - } - return aVal; - } - return 0.; + return GetPoints( theElementId, P ) ? GetValue(P) : 0.0; } double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -496,10 +500,12 @@ SMDSAbs_ElementType MaxElementLength2D::GetType() const return SMDSAbs_Face; } +//======================================================================= /* Class : MaxElementLength3D Description : Functor calculating maximum length of 3D element */ +//================================================================================ double MaxElementLength3D::GetValue( long theElementId ) { @@ -507,148 +513,165 @@ double MaxElementLength3D::GetValue( long theElementId ) if( GetPoints( theElementId, P ) ) { double aVal = 0; const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId ); - SMDSAbs_ElementType aType = aElem->GetType(); + SMDSAbs_EntityType aType = aElem->GetEntityType(); int len = P.size(); - switch( aType ) { - case SMDSAbs_Volume: - if( len == 4 ) { // tetras - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); - double L4 = getDistance(P( 1 ),P( 4 )); - double L5 = getDistance(P( 2 ),P( 4 )); - double L6 = getDistance(P( 3 ),P( 4 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - break; - } - else if( len == 5 ) { // pyramids - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 1 )); - double L5 = getDistance(P( 1 ),P( 5 )); - double L6 = getDistance(P( 2 ),P( 5 )); - double L7 = getDistance(P( 3 ),P( 5 )); - double L8 = getDistance(P( 4 ),P( 5 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(L7,L8)); - break; - } - else if( len == 6 ) { // pentas - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); - double L4 = getDistance(P( 4 ),P( 5 )); - double L5 = getDistance(P( 5 ),P( 6 )); - double L6 = getDistance(P( 6 ),P( 4 )); - double L7 = getDistance(P( 1 ),P( 4 )); - double L8 = getDistance(P( 2 ),P( 5 )); - double L9 = getDistance(P( 3 ),P( 6 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(Max(L7,L8),L9)); - break; - } - else if( len == 8 ) { // hexas - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 1 )); - double L5 = getDistance(P( 5 ),P( 6 )); - double L6 = getDistance(P( 6 ),P( 7 )); - double L7 = getDistance(P( 7 ),P( 8 )); - double L8 = getDistance(P( 8 ),P( 5 )); - double L9 = getDistance(P( 1 ),P( 5 )); - double L10= getDistance(P( 2 ),P( 6 )); - double L11= getDistance(P( 3 ),P( 7 )); - double L12= getDistance(P( 4 ),P( 8 )); - double D1 = getDistance(P( 1 ),P( 7 )); - double D2 = getDistance(P( 2 ),P( 8 )); - double D3 = getDistance(P( 3 ),P( 5 )); - double D4 = getDistance(P( 4 ),P( 6 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); - aVal = Max(aVal,Max(L11,L12)); - aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); - break; - } - else if( len == 12 ) { // hexagonal prism - for ( int i1 = 1; i1 < 12; ++i1 ) - for ( int i2 = i1+1; i1 <= 12; ++i1 ) - aVal = Max( aVal, getDistance(P( i1 ),P( i2 ))); - break; - } - else if( len == 10 ) { // quadratic tetras - double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 )); - double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); - double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 )); - double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - break; - } - else if( len == 13 ) { // quadratic pyramids - double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); - double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); - double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 )); - double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 )); - double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(L7,L8)); - break; - } - else if( len == 15 ) { // quadratic pentas - double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); - double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); - double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 )); - double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 )); - double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 )); - double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 )); - double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(Max(L7,L8),L9)); - break; - } - else if( len == 20 || len == 27 ) { // quadratic hexas - double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 )); - double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 )); - double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 )); - double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 )); - double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 )); - double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 )); - double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 )); - double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 )); - double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 )); - double D1 = getDistance(P( 1 ),P( 7 )); - double D2 = getDistance(P( 2 ),P( 8 )); - double D3 = getDistance(P( 3 ),P( 5 )); - double D4 = getDistance(P( 4 ),P( 6 )); - aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); - aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); - aVal = Max(aVal,Max(L11,L12)); - aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); - break; - } - else if( len > 1 && aElem->IsPoly() ) { // polys - // get the maximum distance between all pairs of nodes - for( int i = 1; i <= len; i++ ) { - for( int j = 1; j <= len; j++ ) { - if( j > i ) { // optimization of the loop - double D = getDistance( P(i), P(j) ); - aVal = Max( aVal, D ); - } + switch ( aType ) { + case SMDSEntity_Tetra: { // tetras + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + case SMDSEntity_Pyramid: { // pyramids + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + case SMDSEntity_Penta: { // pentas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + case SMDSEntity_Hexa: { // hexas + double L1 = getDistance(P( 1 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + case SMDSEntity_Hexagonal_Prism: { // hexagonal prism + for ( int i1 = 1; i1 < 12; ++i1 ) + for ( int i2 = i1+1; i1 <= 12; ++i1 ) + aVal = Max( aVal, getDistance(P( i1 ),P( i2 ))); + break; + } + case SMDSEntity_Quad_Tetra: { // quadratic tetras + double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 )); + double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 )); + double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + break; + } + case SMDSEntity_Quad_Pyramid: { // quadratic pyramids + double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 )); + double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 )); + double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(L7,L8)); + break; + } + case SMDSEntity_Quad_Penta: + case SMDSEntity_BiQuad_Penta: { // quadratic pentas + double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 )); + double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 )); + double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 )); + double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 )); + double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 )); + double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),L9)); + break; + } + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: { // quadratic hexas + double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 )); + double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 )); + double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 )); + double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 )); + double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 )); + double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 )); + double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 )); + double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 )); + double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 )); + double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 )); + double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 )); + double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 )); + double D1 = getDistance(P( 1 ),P( 7 )); + double D2 = getDistance(P( 2 ),P( 8 )); + double D3 = getDistance(P( 3 ),P( 5 )); + double D4 = getDistance(P( 4 ),P( 6 )); + aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6)); + aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10))); + aVal = Max(aVal,Max(L11,L12)); + aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4))); + break; + } + case SMDSEntity_Quad_Polyhedra: + case SMDSEntity_Polyhedra: { // polys + // get the maximum distance between all pairs of nodes + for( int i = 1; i <= len; i++ ) { + for( int j = 1; j <= len; j++ ) { + if( j > i ) { // optimization of the loop + double D = getDistance( P(i), P(j) ); + aVal = Max( aVal, D ); } } } + break; } + case SMDSEntity_Node: + case SMDSEntity_0D: + case SMDSEntity_Edge: + case SMDSEntity_Quad_Edge: + case SMDSEntity_Triangle: + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + case SMDSEntity_Quadrangle: + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + case SMDSEntity_Ball: + case SMDSEntity_Last: return 0; + } // switch ( aType ) if( myPrecision >= 0 ) { @@ -670,28 +693,34 @@ SMDSAbs_ElementType MaxElementLength3D::GetType() const return SMDSAbs_Volume; } - +//======================================================================= /* Class : MinimumAngle Description : Functor for calculation of minimum angle */ +//================================================================================ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) { - double aMin; - - if (P.size() <3) + if ( P.size() < 3 ) return 0.; - aMin = getAngle(P( P.size() ), P( 1 ), P( 2 )); - aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 ))); + double aMaxCos2; + + aMaxCos2 = getCos2( P( P.size() ), P( 1 ), P( 2 )); + aMaxCos2 = Max( aMaxCos2, getCos2( P( P.size()-1 ), P( P.size() ), P( 1 ))); - for (int i=2; i= 1 ) return 0; + return acos( cos ) * 180.0 / M_PI; } double MinimumAngle::GetBadRate( double Value, int nbNodes ) const @@ -707,10 +736,13 @@ SMDSAbs_ElementType MinimumAngle::GetType() const } +//================================================================================ /* Class : AspectRatio Description : Functor for calculating aspect ratio */ +//================================================================================ + double AspectRatio::GetValue( long theId ) { double aVal = 0; @@ -718,8 +750,8 @@ double AspectRatio::GetValue( long theId ) if ( myCurrElement && myCurrElement->GetVtkType() == VTK_QUAD ) { // issue 21723 - vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid(); - if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() )) + vtkUnstructuredGrid* grid = const_cast( myMesh )->GetGrid(); + if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() )) aVal = Round( vtkMeshQuality::QuadAspectRatio( avtkCell )); } else @@ -747,58 +779,51 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) if ( nbNodes == 3 ) { // Compute lengths of the sides - std::vector< double > aLen (nbNodes); - for ( int i = 0; i < nbNodes - 1; i++ ) - aLen[ i ] = getDistance( P( i + 1 ), P( i + 2 ) ); - aLen[ nbNodes - 1 ] = getDistance( P( 1 ), P( nbNodes ) ); + double aLen1 = getDistance( P( 1 ), P( 2 )); + double aLen2 = getDistance( P( 2 ), P( 3 )); + double aLen3 = getDistance( P( 3 ), P( 1 )); // Q = alfa * h * p / S, where // // alfa = sqrt( 3 ) / 6 // h - length of the longest edge // p - half perimeter // S - triangle surface - const double alfa = sqrt( 3. ) / 6.; - double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) ); - double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.; - double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) ); - if ( anArea <= Precision::Confusion() ) - return 0.; + const double alfa = sqrt( 3. ) / 6.; + double maxLen = Max( aLen1, Max( aLen2, aLen3 )); + double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.; + double anArea = getArea( P( 1 ), P( 2 ), P( 3 )); + if ( anArea <= theEps ) + return theInf; return alfa * maxLen * half_perimeter / anArea; } else if ( nbNodes == 6 ) { // quadratic triangles // Compute lengths of the sides - std::vector< double > aLen (3); - aLen[0] = getDistance( P(1), P(3) ); - aLen[1] = getDistance( P(3), P(5) ); - aLen[2] = getDistance( P(5), P(1) ); - // Q = alfa * h * p / S, where - // - // alfa = sqrt( 3 ) / 6 - // h - length of the longest edge - // p - half perimeter - // S - triangle surface - const double alfa = sqrt( 3. ) / 6.; - double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) ); - double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.; - double anArea = getArea( P(1), P(3), P(5) ); - if ( anArea <= Precision::Confusion() ) - return 0.; + double aLen1 = getDistance( P( 1 ), P( 3 )); + double aLen2 = getDistance( P( 3 ), P( 5 )); + double aLen3 = getDistance( P( 5 ), P( 1 )); + // algo same as for the linear triangle + const double alfa = sqrt( 3. ) / 6.; + double maxLen = Max( aLen1, Max( aLen2, aLen3 )); + double half_perimeter = ( aLen1 + aLen2 + aLen3 ) / 2.; + double anArea = getArea( P( 1 ), P( 3 ), P( 5 )); + if ( anArea <= theEps ) + return theInf; return alfa * maxLen * half_perimeter / anArea; } else if( nbNodes == 4 ) { // quadrangle // Compute lengths of the sides - std::vector< double > aLen (4); + double aLen[4]; aLen[0] = getDistance( P(1), P(2) ); aLen[1] = getDistance( P(2), P(3) ); aLen[2] = getDistance( P(3), P(4) ); aLen[3] = getDistance( P(4), P(1) ); // Compute lengths of the diagonals - std::vector< double > aDia (2); + double aDia[2]; aDia[0] = getDistance( P(1), P(3) ); aDia[1] = getDistance( P(2), P(4) ); // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - std::vector< double > anArea (4); + double anArea[4]; anArea[0] = getArea( P(1), P(2), P(3) ); anArea[1] = getArea( P(1), P(2), P(4) ); anArea[2] = getArea( P(1), P(3), P(4) ); @@ -814,35 +839,35 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) // Si - areas of the triangles const double alpha = sqrt( 1 / 32. ); double L = Max( aLen[ 0 ], - Max( aLen[ 1 ], - Max( aLen[ 2 ], - Max( aLen[ 3 ], - Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); double C1 = sqrt( ( aLen[0] * aLen[0] + aLen[1] * aLen[1] + aLen[2] * aLen[2] + aLen[3] * aLen[3] ) / 4. ); double C2 = Min( anArea[ 0 ], - Min( anArea[ 1 ], - Min( anArea[ 2 ], anArea[ 3 ] ) ) ); - if ( C2 <= Precision::Confusion() ) - return 0.; + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + if ( C2 <= theEps ) + return theInf; return alpha * L * C1 / C2; } else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle // Compute lengths of the sides - std::vector< double > aLen (4); + double aLen[4]; aLen[0] = getDistance( P(1), P(3) ); aLen[1] = getDistance( P(3), P(5) ); aLen[2] = getDistance( P(5), P(7) ); aLen[3] = getDistance( P(7), P(1) ); // Compute lengths of the diagonals - std::vector< double > aDia (2); + double aDia[2]; aDia[0] = getDistance( P(1), P(5) ); aDia[1] = getDistance( P(3), P(7) ); // Compute areas of all triangles which can be built // taking three nodes of the quadrangle - std::vector< double > anArea (4); + double anArea[4]; anArea[0] = getArea( P(1), P(3), P(5) ); anArea[1] = getArea( P(1), P(3), P(7) ); anArea[2] = getArea( P(1), P(5), P(7) ); @@ -869,8 +894,8 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) double C2 = Min( anArea[ 0 ], Min( anArea[ 1 ], Min( anArea[ 2 ], anArea[ 3 ] ) ) ); - if ( C2 <= Precision::Confusion() ) - return 0.; + if ( C2 <= theEps ) + return theInf; return alpha * L * C1 / C2; } return 0; @@ -891,10 +916,13 @@ SMDSAbs_ElementType AspectRatio::GetType() const } +//================================================================================ /* Class : AspectRatio3D Description : Functor for calculating aspect ratio */ +//================================================================================ + namespace{ inline double getHalfPerimeter(double theTria[3]){ @@ -966,8 +994,8 @@ double AspectRatio3D::GetValue( long theId ) // Action from CoTech | ACTION 31.3: // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH. - vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid(); - if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() )) + vtkUnstructuredGrid* grid = const_cast( myMesh )->GetGrid(); + if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() )) aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell )); } else @@ -986,7 +1014,7 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) int nbNodes = P.size(); - if(myCurrElement->IsQuadratic()) { + if( myCurrElement->IsQuadratic() ) { if(nbNodes==10) nbNodes=4; // quadratic tetrahedron else if(nbNodes==13) nbNodes=5; // quadratic pyramid else if(nbNodes==15) nbNodes=6; // quadratic pentahedron @@ -1230,7 +1258,7 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) } // switch(nbNodes) if ( nbNodes > 4 ) { - // avaluate aspect ratio of quadranle faces + // evaluate aspect ratio of quadrangle faces AspectRatio aspect2D; SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes ); int nbFaces = SMDS_VolumeTool::NbFaces( type ); @@ -1239,7 +1267,7 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 ) continue; const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true ); - for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadranle face + for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadrangle face points( p + 1 ) = P( pInd[ p ] + 1 ); aQuality = std::max( aQuality, aspect2D.GetValue( points )); } @@ -1261,10 +1289,13 @@ SMDSAbs_ElementType AspectRatio3D::GetType() const } +//================================================================================ /* Class : Warping Description : Functor for calculating warping */ +//================================================================================ + double Warping::GetValue( const TSequenceOfXYZ& P ) { if ( P.size() != 4 ) @@ -1277,7 +1308,11 @@ double Warping::GetValue( const TSequenceOfXYZ& P ) double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G ); double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G ); - return Max( Max( A1, A2 ), Max( A3, A4 ) ); + double val = Max( Max( A1, A2 ), Max( A3, A4 ) ); + + const double eps = 0.1; // val is in degrees + + return val < eps ? 0. : val; } double Warping::ComputeA( const gp_XYZ& thePnt1, @@ -1288,8 +1323,8 @@ double Warping::ComputeA( const gp_XYZ& thePnt1, double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) ); double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) ); double L = Min( aLen1, aLen2 ) * 0.5; - if ( L < Precision::Confusion()) - return 0.; + if ( L < theEps ) + return theInf; gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG; gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG; @@ -1318,37 +1353,44 @@ SMDSAbs_ElementType Warping::GetType() const } +//================================================================================ /* Class : Taper Description : Functor for calculating taper */ +//================================================================================ + double Taper::GetValue( const TSequenceOfXYZ& P ) { if ( P.size() != 4 ) return 0.; // Compute taper - double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ) / 2.; - double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ) / 2.; - double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ) / 2.; - double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ) / 2.; + double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ); + double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ); + double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ); + double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ); double JA = 0.25 * ( J1 + J2 + J3 + J4 ); - if ( JA <= Precision::Confusion() ) - return 0.; + if ( JA <= theEps ) + return theInf; double T1 = fabs( ( J1 - JA ) / JA ); double T2 = fabs( ( J2 - JA ) / JA ); double T3 = fabs( ( J3 - JA ) / JA ); double T4 = fabs( ( J4 - JA ) / JA ); - return Max( Max( T1, T2 ), Max( T3, T4 ) ); + double val = Max( Max( T1, T2 ), Max( T3, T4 ) ); + + const double eps = 0.01; + + return val < eps ? 0. : val; } double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const { // the taper is in the range [0.0,1.0] - // 0.0 = good (no taper) + // 0.0 = good (no taper) // 1.0 = bad (les cotes opposes sont allignes) return Value; } @@ -1358,11 +1400,13 @@ SMDSAbs_ElementType Taper::GetType() const return SMDSAbs_Face; } - +//================================================================================ /* Class : Skew Description : Functor for calculating skew in degrees */ +//================================================================================ + static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 ) { gp_XYZ p12 = ( p2 + p1 ) / 2.; @@ -1380,7 +1424,7 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) return 0.; // Compute skew - static double PI2 = M_PI / 2.; + const double PI2 = M_PI / 2.; if ( P.size() == 3 ) { double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) ); @@ -1400,11 +1444,11 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution() ? 0. : fabs( PI2 - v1.Angle( v2 ) ); - //BUG SWP12743 - if ( A < Precision::Angular() ) - return 0.; + double val = A * 180. / M_PI; + + const double eps = 0.1; // val is in degrees - return A * 180. / M_PI; + return val < eps ? 0. : val; } } @@ -1422,20 +1466,26 @@ SMDSAbs_ElementType Skew::GetType() const } +//================================================================================ /* Class : Area Description : Functor for calculating area */ +//================================================================================ + double Area::GetValue( const TSequenceOfXYZ& P ) { double val = 0.0; - if ( P.size() > 2 ) { + if ( P.size() > 2 ) + { gp_Vec aVec1( P(2) - P(1) ); gp_Vec aVec2( P(3) - P(1) ); gp_Vec SumVec = aVec1 ^ aVec2; - for (int i=4; i<=P.size(); i++) { + + for (size_t i=4; i<=P.size(); i++) + { gp_Vec aVec1( P(i-1) - P(1) ); - gp_Vec aVec2( P(i) - P(1) ); + gp_Vec aVec2( P(i ) - P(1) ); gp_Vec tmp = aVec1 ^ aVec2; SumVec.Add(tmp); } @@ -1455,11 +1505,13 @@ SMDSAbs_ElementType Area::GetType() const return SMDSAbs_Face; } - +//================================================================================ /* Class : Length Description : Functor for calculating length of edge */ +//================================================================================ + double Length::GetValue( const TSequenceOfXYZ& P ) { switch ( P.size() ) { @@ -1480,210 +1532,252 @@ SMDSAbs_ElementType Length::GetType() const return SMDSAbs_Edge; } +//================================================================================ /* Class : Length2D - Description : Functor for calculating length of edge + Description : Functor for calculating minimal length of edge */ +//================================================================================ -double Length2D::GetValue( long theElementId) +double Length2D::GetValue( const TSequenceOfXYZ& P ) { - TSequenceOfXYZ P; - - //cout<<"Length2D::GetValue"<FindElement( theElementId ); - SMDSAbs_ElementType aType = aElem->GetType(); - - int len = P.size(); - - switch (aType){ - case SMDSAbs_All: - case SMDSAbs_Node: - case SMDSAbs_Edge: - if (len == 2){ - aVal = getDistance( P( 1 ), P( 2 ) ); - break; - } - else if (len == 3){ // quadratic edge - aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 )); - break; - } - case SMDSAbs_Face: - if (len == 3){ // triangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - break; - } - else if (len == 4){ // quadrangles - double L1 = getDistance(P( 1 ),P( 2 )); - double L2 = getDistance(P( 2 ),P( 3 )); - double L3 = getDistance(P( 3 ),P( 4 )); - double L4 = getDistance(P( 4 ),P( 1 )); - aVal = Max(Max(L1,L2),Max(L3,L4)); - break; - } - if (len == 6){ // quadratic triangles - double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); - double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); - double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); - aVal = Max(L1,Max(L2,L3)); - //cout<<"L1="<GetType(); if ( myType != SMDSAbs_All && anElemType != myType ) return false; - const int aNbNode = anElem->NbNodes(); - bool isOk = false; - switch( anElemType ) - { - case SMDSAbs_Node: - isOk = (myGeomType == SMDSGeom_POINT); - break; - - case SMDSAbs_Edge: - isOk = (myGeomType == SMDSGeom_EDGE); - break; - - case SMDSAbs_Face: - if ( myGeomType == SMDSGeom_TRIANGLE ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 6 : aNbNode == 3)); - else if ( myGeomType == SMDSGeom_QUADRANGLE ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? ( aNbNode == 8 || aNbNode == 9 ) : aNbNode == 4)); - else if ( myGeomType == SMDSGeom_POLYGON ) - isOk = anElem->IsPoly(); - break; - - case SMDSAbs_Volume: - if ( myGeomType == SMDSGeom_TETRA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 10 : aNbNode == 4)); - else if ( myGeomType == SMDSGeom_PYRAMID ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 13 : aNbNode == 5)); - else if ( myGeomType == SMDSGeom_PENTA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 15 : aNbNode == 6)); - else if ( myGeomType == SMDSGeom_HEXA ) - isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? ( aNbNode == 20 || aNbNode == 27 ): aNbNode == 8)); - else if ( myGeomType == SMDSGeom_HEXAGONAL_PRISM ) - isOk = (anElem->GetEntityType() == SMDSEntity_Hexagonal_Prism ); - else if ( myGeomType == SMDSGeom_POLYHEDRA ) - isOk = anElem->IsPoly(); - break; - default: break; - } + bool isOk = ( anElem->GetGeomType() == myGeomType ); return isOk; } @@ -2705,12 +2878,214 @@ SMDSAbs_GeometryType ElemGeomType::GetGeomType() const return myGeomType; } +//================================================================================ +/* + Class : ElemEntityType + Description : Predicate to check element entity type +*/ +//================================================================================ + +ElemEntityType::ElemEntityType(): + myMesh( 0 ), + myType( SMDSAbs_All ), + myEntityType( SMDSEntity_0D ) +{ +} + +void ElemEntityType::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMesh = theMesh; +} + +bool ElemEntityType::IsSatisfy( long theId ) +{ + if ( !myMesh ) return false; + if ( myType == SMDSAbs_Node ) + return myMesh->FindNode( theId ); + const SMDS_MeshElement* anElem = myMesh->FindElement( theId ); + return ( anElem && + myEntityType == anElem->GetEntityType() ); +} + +void ElemEntityType::SetType( SMDSAbs_ElementType theType ) +{ + myType = theType; +} + +SMDSAbs_ElementType ElemEntityType::GetType() const +{ + return myType; +} + +void ElemEntityType::SetElemEntityType( SMDSAbs_EntityType theEntityType ) +{ + myEntityType = theEntityType; +} + +SMDSAbs_EntityType ElemEntityType::GetElemEntityType() const +{ + return myEntityType; +} + +//================================================================================ +/*! + * \brief Class ConnectedElements + */ +//================================================================================ + +ConnectedElements::ConnectedElements(): + myNodeID(0), myType( SMDSAbs_All ), myOkIDsReady( false ) {} + +SMDSAbs_ElementType ConnectedElements::GetType() const +{ return myType; } + +int ConnectedElements::GetNode() const +{ return myXYZ.empty() ? myNodeID : 0; } // myNodeID can be found by myXYZ + +std::vector ConnectedElements::GetPoint() const +{ return myXYZ; } + +void ConnectedElements::clearOkIDs() +{ myOkIDsReady = false; myOkIDs.clear(); } + +void ConnectedElements::SetType( SMDSAbs_ElementType theType ) +{ + if ( myType != theType || myMeshModifTracer.IsMeshModified() ) + clearOkIDs(); + myType = theType; +} + +void ConnectedElements::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified() ) + { + clearOkIDs(); + if ( !myXYZ.empty() ) + SetPoint( myXYZ[0], myXYZ[1], myXYZ[2] ); // find a node near myXYZ it in a new mesh + } +} + +void ConnectedElements::SetNode( int nodeID ) +{ + myNodeID = nodeID; + myXYZ.clear(); + + bool isSameDomain = false; + if ( myOkIDsReady && myMeshModifTracer.GetMesh() && !myMeshModifTracer.IsMeshModified() ) + if ( const SMDS_MeshNode* n = myMeshModifTracer.GetMesh()->FindNode( myNodeID )) + { + SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( myType ); + while ( !isSameDomain && eIt->more() ) + isSameDomain = IsSatisfy( eIt->next()->GetID() ); + } + if ( !isSameDomain ) + clearOkIDs(); +} + +void ConnectedElements::SetPoint( double x, double y, double z ) +{ + myXYZ.resize(3); + myXYZ[0] = x; + myXYZ[1] = y; + myXYZ[2] = z; + myNodeID = 0; + + bool isSameDomain = false; + + // find myNodeID by myXYZ if possible + if ( myMeshModifTracer.GetMesh() ) + { + SMESHUtils::Deleter searcher + ( SMESH_MeshAlgos::GetElementSearcher( (SMDS_Mesh&) *myMeshModifTracer.GetMesh() )); + + std::vector< const SMDS_MeshElement* > foundElems; + searcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_All, foundElems ); + + if ( !foundElems.empty() ) + { + myNodeID = foundElems[0]->GetNode(0)->GetID(); + if ( myOkIDsReady && !myMeshModifTracer.IsMeshModified() ) + isSameDomain = IsSatisfy( foundElems[0]->GetID() ); + } + } + if ( !isSameDomain ) + clearOkIDs(); +} + +bool ConnectedElements::IsSatisfy( long theElementId ) +{ + // Here we do NOT check if the mesh has changed, we do it in Set...() only!!! + + if ( !myOkIDsReady ) + { + if ( !myMeshModifTracer.GetMesh() ) + return false; + const SMDS_MeshNode* node0 = myMeshModifTracer.GetMesh()->FindNode( myNodeID ); + if ( !node0 ) + return false; + + std::list< const SMDS_MeshNode* > nodeQueue( 1, node0 ); + std::set< int > checkedNodeIDs; + // algo: + // foreach node in nodeQueue: + // foreach element sharing a node: + // add ID of an element of myType to myOkIDs; + // push all element nodes absent from checkedNodeIDs to nodeQueue; + while ( !nodeQueue.empty() ) + { + const SMDS_MeshNode* node = nodeQueue.front(); + nodeQueue.pop_front(); + + // loop on elements sharing the node + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); + while ( eIt->more() ) + { + // keep elements of myType + const SMDS_MeshElement* element = eIt->next(); + if ( element->GetType() == myType ) + myOkIDs.insert( myOkIDs.end(), element->GetID() ); + + // enqueue nodes of the element + SMDS_ElemIteratorPtr nIt = element->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = static_cast< const SMDS_MeshNode* >( nIt->next() ); + if ( checkedNodeIDs.insert( n->GetID() ).second ) + nodeQueue.push_back( n ); + } + } + } + if ( myType == SMDSAbs_Node ) + std::swap( myOkIDs, checkedNodeIDs ); + + size_t totalNbElems = myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ); + if ( myOkIDs.size() == totalNbElems ) + myOkIDs.clear(); + + myOkIDsReady = true; + } + + return myOkIDs.empty() ? true : myOkIDs.count( theElementId ); +} + //================================================================================ /*! * \brief Class CoplanarFaces */ //================================================================================ +namespace +{ + inline bool isLessAngle( const gp_Vec& v1, const gp_Vec& v2, const double cos ) + { + double dot = v1 * v2; // cos * |v1| * |v2| + double l1 = v1.SquareMagnitude(); + double l2 = v2.SquareMagnitude(); + return (( dot * cos >= 0 ) && + ( dot * dot ) / l1 / l2 >= ( cos * cos )); + } +} CoplanarFaces::CoplanarFaces() : myFaceID(0), myToler(0) { @@ -2722,7 +3097,7 @@ void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) { // Build a set of coplanar face ids - myCoplanarIDs.clear(); + myCoplanarIDs.Clear(); if ( !myMeshModifTracer.GetMesh() || !myFaceID || !myToler ) return; @@ -2736,11 +3111,11 @@ void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) if (!normOK) return; - const double radianTol = myToler * M_PI / 180.; - std::set< SMESH_TLink > checkedLinks; + const double cosTol = Cos( myToler * M_PI / 180. ); + NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks; - std::list< pair< const SMDS_MeshElement*, gp_Vec > > faceQueue; - faceQueue.push_back( make_pair( face, myNorm )); + std::list< std::pair< const SMDS_MeshElement*, gp_Vec > > faceQueue; + faceQueue.push_back( std::make_pair( face, myNorm )); while ( !faceQueue.empty() ) { face = faceQueue.front().first; @@ -2751,7 +3126,7 @@ void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) { const SMDS_MeshNode* n1 = face->GetNode( i ); const SMDS_MeshNode* n2 = face->GetNode(( i+1 )%nbN); - if ( !checkedLinks.insert( SMESH_TLink( n1, n2 )).second ) + if ( !checkedLinks.Add( SMESH_TLink( n1, n2 ))) continue; SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator(SMDSAbs_Face); while ( fIt->more() ) @@ -2760,10 +3135,10 @@ void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) if ( f->GetNodeIndex( n2 ) > -1 ) { gp_Vec norm = getNormale( static_cast(f), &normOK ); - if (!normOK || myNorm.Angle( norm ) <= radianTol) + if (!normOK || isLessAngle( myNorm, norm, cosTol)) { - myCoplanarIDs.insert( f->GetID() ); - faceQueue.push_back( make_pair( f, norm )); + myCoplanarIDs.Add( f->GetID() ); + faceQueue.push_back( std::make_pair( f, norm )); } } } @@ -2773,7 +3148,7 @@ void CoplanarFaces::SetMesh( const SMDS_Mesh* theMesh ) } bool CoplanarFaces::IsSatisfy( long theElementId ) { - return myCoplanarIDs.count( theElementId ); + return myCoplanarIDs.Contains( theElementId ); } /* @@ -2901,11 +3276,13 @@ bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr ) myIds.Clear(); TCollection_AsciiString aStr = theStr; - aStr.RemoveAll( ' ' ); - aStr.RemoveAll( '\t' ); - - for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) ) - aStr.Remove( aPos, 2 ); + for ( int i = 1; i <= aStr.Length(); ++i ) + { + char c = aStr.Value( i ); + if ( !isdigit( c ) && c != ',' && c != '-' ) + aStr.SetValue( i, ','); + } + aStr.RemoveAll( ' ' ); TCollection_AsciiString tmpStr = aStr.Token( ",", 1 ); int i = 1; @@ -3176,6 +3553,31 @@ bool LogicalOR::IsSatisfy( long theId ) FILTER */ +// #ifdef WITH_TBB +// #include +// #include + +// namespace Parallel +// { +// typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq; + +// struct Predicate +// { +// const SMDS_Mesh* myMesh; +// PredicatePtr myPredicate; +// TIdSeq & myOKIds; +// Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ): +// myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {} +// void operator() ( const tbb::blocked_range& r ) const +// { +// for ( size_t i = r.begin(); i != r.end(); ++i ) +// if ( myPredicate->IsSatisfy( i )) +// myOKIds.local().push_back(); +// } +// } +// } +// #endif + Filter::Filter() {} @@ -3356,7 +3758,7 @@ bool ManifoldPart::process() myMapIds.Add( aFaceId ); } - if ( fi == ( myAllFacePtr.size() - 1 ) ) + if ( fi == int( myAllFacePtr.size() - 1 )) fi = 0; } // end run on vector of faces return !myMapIds.IsEmpty(); @@ -3537,35 +3939,80 @@ void ManifoldPart::expandBoundary void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, ManifoldPart::TVectorOfFacePtr& theFaces ) const { - std::set aSetOfFaces; + // take all faces that shared first node - SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator(); - for ( ; anItr->more(); ) - { - SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); - if ( !aFace ) - continue; - aSetOfFaces.insert( aFace ); - } + SMDS_ElemIteratorPtr anItr = theLink.myNode1->GetInverseElementIterator( SMDSAbs_Face ); + SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > faces( anItr ), facesEnd; + std::set aSetOfFaces( faces, facesEnd ); + // take all faces that shared second node - anItr = theLink.myNode2->facesIterator(); + anItr = theLink.myNode2->GetInverseElementIterator( SMDSAbs_Face ); // find the common part of two sets for ( ; anItr->more(); ) { - SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); - if ( aSetOfFaces.count( aFace ) ) - theFaces.push_back( aFace ); + const SMDS_MeshElement* aFace = anItr->next(); + if ( aSetOfFaces.count( aFace )) + theFaces.push_back( (SMDS_MeshFace*) aFace ); } } - /* - ElementsOnSurface + Class : BelongToMeshGroup + Description : Verify whether a mesh element is included into a mesh group */ +BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 ) +{ +} + +void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g ) +{ + myGroup = g; +} + +void BelongToMeshGroup::SetStoreName( const std::string& sn ) +{ + myStoreName = sn; +} + +void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( myGroup && myGroup->GetMesh() != theMesh ) + { + myGroup = 0; + } + if ( !myGroup && !myStoreName.empty() ) + { + if ( const SMESHDS_Mesh* aMesh = dynamic_cast(theMesh)) + { + const std::set& grps = aMesh->GetGroups(); + std::set::const_iterator g = grps.begin(); + for ( ; g != grps.end() && !myGroup; ++g ) + if ( *g && myStoreName == (*g)->GetStoreName() ) + myGroup = *g; + } + } + if ( myGroup ) + { + myGroup->IsEmpty(); // make GroupOnFilter update its predicate + } +} + +bool BelongToMeshGroup::IsSatisfy( long theElementId ) +{ + return myGroup ? myGroup->Contains( theElementId ) : false; +} + +SMDSAbs_ElementType BelongToMeshGroup::GetType() const +{ + return myGroup ? myGroup->GetType() : SMDSAbs_All; +} + +//================================================================================ +// ElementsOnSurface +//================================================================================ ElementsOnSurface::ElementsOnSurface() { - myMesh = 0; myIds.Clear(); myType = SMDSAbs_All; mySurf.Nullify(); @@ -3575,15 +4022,13 @@ ElementsOnSurface::ElementsOnSurface() ElementsOnSurface::~ElementsOnSurface() { - myMesh = 0; } void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh ) { - if ( myMesh == theMesh ) - return; - myMesh = theMesh; - process(); + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified()) + process(); } bool ElementsOnSurface::IsSatisfy( long theElementId ) @@ -3638,32 +4083,14 @@ void ElementsOnSurface::process() if ( mySurf.IsNull() ) return; - if ( myMesh == 0 ) + if ( !myMeshModifTracer.GetMesh() ) return; - if ( myType == SMDSAbs_Face || myType == SMDSAbs_All ) - { - myIds.ReSize( myMesh->NbFaces() ); - SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } - - if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All ) - { - myIds.ReSize( myIds.Extent() + myMesh->NbEdges() ); - SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } + myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType )); - if ( myType == SMDSAbs_Node ) - { - myIds.ReSize( myMesh->NbNodes() ); - SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator(); - for(; anIter->more(); ) - process( anIter->next() ); - } + SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType ); + for(; anIter->more(); ) + process( anIter->next() ); } void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr ) @@ -3716,33 +4143,96 @@ bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) } -/* - ElementsOnShape -*/ +//================================================================================ +// ElementsOnShape +//================================================================================ -ElementsOnShape::ElementsOnShape() - : //myMesh(0), - myType(SMDSAbs_All), - myToler(Precision::Confusion()), - myAllNodesFlag(false) +namespace { + const int theIsCheckedFlag = 0x0000100; +} + +struct ElementsOnShape::Classifier +{ + Classifier() { mySolidClfr = 0; myFlags = 0; } + ~Classifier(); + void Init(const TopoDS_Shape& s, double tol, const Bnd_B3d* box = 0 ); + bool IsOut(const gp_Pnt& p) { return SetChecked( true ), (this->*myIsOutFun)( p ); } + TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); } + const TopoDS_Shape& Shape() const { return myShape; } + const Bnd_B3d* GetBndBox() const { return & myBox; } + bool IsChecked() { return myFlags & theIsCheckedFlag; } + bool IsSetFlag( int flag ) const { return myFlags & flag; } + void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); } + void SetFlag ( int flag ) { myFlags |= flag; } + void UnsetFlag( int flag ) { myFlags &= ~flag; } + +private: + bool isOutOfSolid (const gp_Pnt& p); + bool isOutOfBox (const gp_Pnt& p); + bool isOutOfFace (const gp_Pnt& p); + bool isOutOfEdge (const gp_Pnt& p); + bool isOutOfVertex(const gp_Pnt& p); + bool isBox (const TopoDS_Shape& s); + + bool (Classifier::* myIsOutFun)(const gp_Pnt& p); + BRepClass3d_SolidClassifier* mySolidClfr; // ptr because of a run-time forbidden copy-constructor + Bnd_B3d myBox; + GeomAPI_ProjectPointOnSurf myProjFace; + GeomAPI_ProjectPointOnCurve myProjEdge; + gp_Pnt myVertexXYZ; + TopoDS_Shape myShape; + double myTol; + int myFlags; +}; + +struct ElementsOnShape::OctreeClassifier : public SMESH_Octree +{ + OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers ); + OctreeClassifier( const OctreeClassifier* otherTree, + const std::vector< ElementsOnShape::Classifier >& clsOther, + std::vector< ElementsOnShape::Classifier >& cls ); + void GetClassifiersAtPoint( const gp_XYZ& p, + std::vector< ElementsOnShape::Classifier* >& classifiers ); +protected: + OctreeClassifier() {} + SMESH_Octree* newChild() const { return new OctreeClassifier; } + void buildChildrenData(); + Bnd_B3d* buildRootBox(); + + std::vector< ElementsOnShape::Classifier* > myClassifiers; +}; + + +ElementsOnShape::ElementsOnShape(): + myOctree(0), + myType(SMDSAbs_All), + myToler(Precision::Confusion()), + myAllNodesFlag(false) { - myCurShapeType = TopAbs_SHAPE; } ElementsOnShape::~ElementsOnShape() { + clearClassifiers(); } -void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) -{ - myMeshModifTracer.SetMesh( theMesh ); - if ( myMeshModifTracer.IsMeshModified()) - SetShape(myShape, myType); -} - -bool ElementsOnShape::IsSatisfy (long theElementId) +Predicate* ElementsOnShape::clone() const { - return myIds.Contains(theElementId); + ElementsOnShape* cln = new ElementsOnShape(); + cln->SetAllNodes ( myAllNodesFlag ); + cln->SetTolerance( myToler ); + cln->SetMesh ( myMeshModifTracer.GetMesh() ); + cln->myShape = myShape; // avoid creation of myClassifiers + cln->SetShape ( myShape, myType ); + cln->myClassifiers.resize( myClassifiers.size() ); + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + cln->myClassifiers[ i ].Init( BRepBuilderAPI_Copy( myClassifiers[ i ].Shape()), + myToler, myClassifiers[ i ].GetBndBox() ); + if ( myOctree ) // copy myOctree + { + cln->myOctree = new OctreeClassifier( myOctree, myClassifiers, cln->myClassifiers ); + } + return cln; } SMDSAbs_ElementType ElementsOnShape::GetType() const @@ -3765,202 +4255,820 @@ double ElementsOnShape::GetTolerance() const void ElementsOnShape::SetAllNodes (bool theAllNodes) { - if (myAllNodesFlag != theAllNodes) { - myAllNodesFlag = theAllNodes; - SetShape(myShape, myType); + myAllNodesFlag = theAllNodes; +} + +void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified()) + { + size_t nbNodes = theMesh ? theMesh->NbNodes() : 0; + if ( myNodeIsChecked.size() == nbNodes ) + { + std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false ); + } + else + { + SMESHUtils::FreeVector( myNodeIsChecked ); + SMESHUtils::FreeVector( myNodeIsOut ); + myNodeIsChecked.resize( nbNodes, false ); + myNodeIsOut.resize( nbNodes ); + } + } +} + +bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut ) +{ + if ( n->GetID() >= (int) myNodeIsChecked.size() || + !myNodeIsChecked[ n->GetID() ]) + return false; + + isOut = myNodeIsOut[ n->GetID() ]; + return true; +} + +void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool isOut ) +{ + if ( n->GetID() < (int) myNodeIsChecked.size() ) + { + myNodeIsChecked[ n->GetID() ] = true; + myNodeIsOut [ n->GetID() ] = isOut; } } void ElementsOnShape::SetShape (const TopoDS_Shape& theShape, const SMDSAbs_ElementType theType) { - myType = theType; + bool shapeChanges = ( myShape != theShape ); + myType = theType; myShape = theShape; - myIds.Clear(); + if ( myShape.IsNull() ) return; - const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); - - if ( !myMesh ) return; + if ( shapeChanges ) + { + // find most complex shapes + TopTools_IndexedMapOfShape shapesMap; + TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }; + TopExp_Explorer sub; + for ( int i = 0; i < 4; ++i ) + { + if ( shapesMap.IsEmpty() ) + for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + if ( i > 0 ) + for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + } + + clearClassifiers(); + myClassifiers.resize( shapesMap.Extent() ); + for ( int i = 0; i < shapesMap.Extent(); ++i ) + myClassifiers[ i ].Init( shapesMap( i+1 ), myToler ); + } - switch (myType) + if ( theType == SMDSAbs_Node ) { - case SMDSAbs_All: - myIds.ReSize(myMesh->NbEdges() + myMesh->NbFaces() + myMesh->NbVolumes()); - break; - case SMDSAbs_Node: - myIds.ReSize(myMesh->NbNodes()); - break; - case SMDSAbs_Edge: - myIds.ReSize(myMesh->NbEdges()); - break; - case SMDSAbs_Face: - myIds.ReSize(myMesh->NbFaces()); - break; - case SMDSAbs_Volume: - myIds.ReSize(myMesh->NbVolumes()); - break; - default: - break; + SMESHUtils::FreeVector( myNodeIsChecked ); + SMESHUtils::FreeVector( myNodeIsOut ); + } + else + { + std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false ); } +} + +void ElementsOnShape::clearClassifiers() +{ + // for ( size_t i = 0; i < myClassifiers.size(); ++i ) + // delete myClassifiers[ i ]; + myClassifiers.clear(); - myShapesMap.Clear(); - addShape(myShape); + delete myOctree; + myOctree = 0; } -void ElementsOnShape::addShape (const TopoDS_Shape& theShape) +bool ElementsOnShape::IsSatisfy( long elemId ) { - if (theShape.IsNull() || myMeshModifTracer.GetMesh() == 0) - return; + if ( myClassifiers.empty() ) + return false; + + const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh(); + if ( myType == SMDSAbs_Node ) + return IsSatisfy( mesh->FindNode( elemId )); + return IsSatisfy( mesh->FindElement( elemId )); +} + +bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem) +{ + if ( !elem ) + return false; + + bool isSatisfy = myAllNodesFlag, isNodeOut; + + gp_XYZ centerXYZ (0, 0, 0); - if (!myShapesMap.Add(theShape)) return; + if ( !myOctree && myClassifiers.size() > 5 ) + { + myWorkClassifiers.resize( myClassifiers.size() ); + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + myWorkClassifiers[ i ] = & myClassifiers[ i ]; + myOctree = new OctreeClassifier( myWorkClassifiers ); + } - myCurShapeType = theShape.ShapeType(); - switch (myCurShapeType) + SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator(); + while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SHELL: - case TopAbs_WIRE: + SMESH_TNodeXYZ aPnt( aNodeItr->next() ); + centerXYZ += aPnt; + + isNodeOut = true; + if ( !getNodeIsOut( aPnt._node, isNodeOut )) { - TopoDS_Iterator anIt (theShape, Standard_True, Standard_True); - for (; anIt.More(); anIt.Next()) addShape(anIt.Value()); + if ( myOctree ) + { + myWorkClassifiers.clear(); + myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers ); + + for ( size_t i = 0; i < myWorkClassifiers.size(); ++i ) + myWorkClassifiers[i]->SetChecked( false ); + + for ( size_t i = 0; i < myWorkClassifiers.size() && isNodeOut; ++i ) + if ( !myWorkClassifiers[i]->IsChecked() ) + isNodeOut = myWorkClassifiers[i]->IsOut( aPnt ); + } + else + { + for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i ) + isNodeOut = myClassifiers[i].IsOut( aPnt ); + } + setNodeIsOut( aPnt._node, isNodeOut ); } - break; + isSatisfy = !isNodeOut; + } + + // Check the center point for volumes MantisBug 0020168 + if ( isSatisfy && + myAllNodesFlag && + myClassifiers[0].ShapeType() == TopAbs_SOLID ) + { + centerXYZ /= elem->NbNodes(); + isSatisfy = false; + if ( myOctree ) + for ( size_t i = 0; i < myWorkClassifiers.size() && !isSatisfy; ++i ) + isSatisfy = ! myWorkClassifiers[i]->IsOut( centerXYZ ); + else + for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i ) + isSatisfy = ! myClassifiers[i].IsOut( centerXYZ ); + } + + return isSatisfy; +} + +//================================================================================ +/*! + * \brief Check and optionally return a satisfying shape + */ +//================================================================================ + +bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node, + TopoDS_Shape* okShape) +{ + if ( !node ) + return false; + + if ( !myOctree && myClassifiers.size() > 5 ) + { + myWorkClassifiers.resize( myClassifiers.size() ); + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + myWorkClassifiers[ i ] = & myClassifiers[ i ]; + myOctree = new OctreeClassifier( myWorkClassifiers ); + } + + bool isNodeOut = true; + + if ( okShape || !getNodeIsOut( node, isNodeOut )) + { + SMESH_NodeXYZ aPnt = node; + if ( myOctree ) + { + myWorkClassifiers.clear(); + myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers ); + + for ( size_t i = 0; i < myWorkClassifiers.size(); ++i ) + myWorkClassifiers[i]->SetChecked( false ); + + for ( size_t i = 0; i < myWorkClassifiers.size(); ++i ) + if ( !myWorkClassifiers[i]->IsChecked() && + !myWorkClassifiers[i]->IsOut( aPnt )) + { + isNodeOut = false; + if ( okShape ) + *okShape = myWorkClassifiers[i]->Shape(); + break; + } + } + else + { + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + if ( !myClassifiers[i].IsOut( aPnt )) + { + isNodeOut = false; + if ( okShape ) + *okShape = myWorkClassifiers[i]->Shape(); + break; + } + } + setNodeIsOut( node, isNodeOut ); + } + + return !isNodeOut; +} + +void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape, + double theTol, + const Bnd_B3d* theBox ) +{ + myShape = theShape; + myTol = theTol; + myFlags = 0; + + bool isShapeBox = false; + switch ( myShape.ShapeType() ) + { case TopAbs_SOLID: + { + if (( isShapeBox = isBox( theShape ))) { - myCurSC.Load(theShape); - process(); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfBox; } - break; - case TopAbs_FACE: + else { - TopoDS_Face aFace = TopoDS::Face(theShape); - BRepAdaptor_Surface SA (aFace, true); - Standard_Real - u1 = SA.FirstUParameter(), - u2 = SA.LastUParameter(), - v1 = SA.FirstVParameter(), - v2 = SA.LastVParameter(); - Handle(Geom_Surface) surf = BRep_Tool::Surface(aFace); - myCurProjFace.Init(surf, u1,u2, v1,v2); - myCurFace = aFace; - process(); + mySolidClfr = new BRepClass3d_SolidClassifier(theShape); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid; } break; + } + case TopAbs_FACE: + { + Standard_Real u1,u2,v1,v2; + Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape )); + surf->Bounds( u1,u2,v1,v2 ); + myProjFace.Init(surf, u1,u2, v1,v2, myTol ); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace; + break; + } case TopAbs_EDGE: - { - TopoDS_Edge anEdge = TopoDS::Edge(theShape); - Standard_Real u1, u2; - Handle(Geom_Curve) curve = BRep_Tool::Curve(anEdge, u1, u2); - myCurProjEdge.Init(curve, u1, u2); - process(); - } + { + Standard_Real u1, u2; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2); + myProjEdge.Init(curve, u1, u2); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge; break; + } case TopAbs_VERTEX: - { - TopoDS_Vertex aV = TopoDS::Vertex(theShape); - myCurPnt = BRep_Tool::Pnt(aV); - process(); - } + { + myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) ); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfVertex; break; + } default: - break; + throw SALOME_Exception("Programmer error in usage of ElementsOnShape::Classifier"); + } + + if ( !isShapeBox ) + { + if ( theBox ) + { + myBox = *theBox; + } + else + { + Bnd_Box box; + BRepBndLib::Add( myShape, box ); + myBox.Clear(); + myBox.Add( box.CornerMin() ); + myBox.Add( box.CornerMax() ); + gp_XYZ halfSize = 0.5 * ( box.CornerMax().XYZ() - box.CornerMin().XYZ() ); + for ( int iDim = 1; iDim <= 3; ++iDim ) + { + double x = halfSize.Coord( iDim ); + halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x )); + } + myBox.SetHSize( halfSize ); + } } } -void ElementsOnShape::process() +ElementsOnShape::Classifier::~Classifier() { - const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); - if (myShape.IsNull() || myMesh == 0) - return; + delete mySolidClfr; mySolidClfr = 0; +} - SMDS_ElemIteratorPtr anIter = myMesh->elementsIterator(myType); - while (anIter->more()) - process(anIter->next()); +bool ElementsOnShape::Classifier::isOutOfSolid (const gp_Pnt& p) +{ + mySolidClfr->Perform( p, myTol ); + return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON ); } -void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) +bool ElementsOnShape::Classifier::isOutOfBox (const gp_Pnt& p) { - if (myShape.IsNull()) - return; + return myBox.IsOut( p.XYZ() ); +} - SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator(); - bool isSatisfy = myAllNodesFlag; +bool ElementsOnShape::Classifier::isOutOfFace (const gp_Pnt& p) +{ + myProjFace.Perform( p ); + if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol ) + { + // check relatively to the face + Standard_Real u, v; + myProjFace.LowerDistanceParameters(u, v); + gp_Pnt2d aProjPnt (u, v); + BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol ); + if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON ) + return false; + } + return true; +} - gp_XYZ centerXYZ (0, 0, 0); +bool ElementsOnShape::Classifier::isOutOfEdge (const gp_Pnt& p) +{ + myProjEdge.Perform( p ); + return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol ); +} - while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) +bool ElementsOnShape::Classifier::isOutOfVertex(const gp_Pnt& p) +{ + return ( myVertexXYZ.Distance( p ) > myTol ); +} + +bool ElementsOnShape::Classifier::isBox (const TopoDS_Shape& theShape) +{ + TopTools_IndexedMapOfShape vMap; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap ); + if ( vMap.Extent() != 8 ) + return false; + + myBox.Clear(); + for ( int i = 1; i <= 8; ++i ) + myBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))).XYZ() ); + + gp_XYZ pMin = myBox.CornerMin(), pMax = myBox.CornerMax(); + for ( int i = 1; i <= 8; ++i ) { - SMESH_TNodeXYZ aPnt ( aNodeItr->next() ); - centerXYZ += aPnt; + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vMap( i ))); + for ( int iC = 1; iC <= 3; ++ iC ) + { + double d1 = Abs( pMin.Coord( iC ) - p.Coord( iC )); + double d2 = Abs( pMax.Coord( iC ) - p.Coord( iC )); + if ( Min( d1, d2 ) > myTol ) + return false; + } + } + myBox.Enlarge( myTol ); + return true; +} + +ElementsOnShape:: +OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers ) + :SMESH_Octree( new SMESH_TreeLimit ) +{ + myClassifiers = classifiers; + compute(); +} + +ElementsOnShape:: +OctreeClassifier::OctreeClassifier( const OctreeClassifier* otherTree, + const std::vector< ElementsOnShape::Classifier >& clsOther, + std::vector< ElementsOnShape::Classifier >& cls ) + :SMESH_Octree( new SMESH_TreeLimit ) +{ + myBox = new Bnd_B3d( *otherTree->getBox() ); + + if (( myIsLeaf = otherTree->isLeaf() )) + { + myClassifiers.resize( otherTree->myClassifiers.size() ); + for ( size_t i = 0; i < otherTree->myClassifiers.size(); ++i ) + { + int ind = otherTree->myClassifiers[i] - & clsOther[0]; + myClassifiers[ i ] = & cls[ ind ]; + } + } + else if ( otherTree->myChildren ) + { + myChildren = new SMESH_Tree< Bnd_B3d, 8 > * [ 8 ]; + for ( int i = 0; i < nbChildren(); i++ ) + myChildren[i] = + new OctreeClassifier( static_cast( otherTree->myChildren[i]), + clsOther, cls ); + } +} + +void ElementsOnShape:: +OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point, + std::vector< ElementsOnShape::Classifier* >& result ) +{ + if ( getBox()->IsOut( point )) + return; + + if ( isLeaf() ) + { + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + if ( !myClassifiers[i]->GetBndBox()->IsOut( point )) + result.push_back( myClassifiers[i] ); + } + else + { + for (int i = 0; i < nbChildren(); i++) + ((OctreeClassifier*) myChildren[i])->GetClassifiersAtPoint( point, result ); + } +} - switch (myCurShapeType) +void ElementsOnShape::OctreeClassifier::buildChildrenData() +{ + // distribute myClassifiers among myChildren + + const int childFlag[8] = { 0x0000001, + 0x0000002, + 0x0000004, + 0x0000008, + 0x0000010, + 0x0000020, + 0x0000040, + 0x0000080 }; + int nbInChild[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + { + for ( int j = 0; j < nbChildren(); j++ ) { - case TopAbs_SOLID: + if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() )) { - myCurSC.Perform(aPnt, myToler); - isSatisfy = (myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON); + myClassifiers[i]->SetFlag( childFlag[ j ]); + ++nbInChild[ j ]; } - break; - case TopAbs_FACE: + } + } + + for ( int j = 0; j < nbChildren(); j++ ) + { + OctreeClassifier* child = static_cast( myChildren[ j ]); + child->myClassifiers.resize( nbInChild[ j ]); + for ( size_t i = 0; nbInChild[ j ] && i < myClassifiers.size(); ++i ) + { + if ( myClassifiers[ i ]->IsSetFlag( childFlag[ j ])) { - myCurProjFace.Perform(aPnt); - isSatisfy = (myCurProjFace.IsDone() && myCurProjFace.LowerDistance() <= myToler); - if (isSatisfy) - { - // check relatively the face - Quantity_Parameter u, v; - myCurProjFace.LowerDistanceParameters(u, v); - gp_Pnt2d aProjPnt (u, v); - BRepClass_FaceClassifier aClsf (myCurFace, aProjPnt, myToler); - isSatisfy = (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON); - } + --nbInChild[ j ]; + child->myClassifiers[ nbInChild[ j ]] = myClassifiers[ i ]; + myClassifiers[ i ]->UnsetFlag( childFlag[ j ]); } - break; - case TopAbs_EDGE: - { - myCurProjEdge.Perform(aPnt); - isSatisfy = (myCurProjEdge.NbPoints() > 0 && myCurProjEdge.LowerDistance() <= myToler); + } + } + SMESHUtils::FreeVector( myClassifiers ); + + // define if a child isLeaf() + for ( int i = 0; i < nbChildren(); i++ ) + { + OctreeClassifier* child = static_cast( myChildren[ i ]); + child->myIsLeaf = ( child->myClassifiers.size() <= 5 ); + } +} + +Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox() +{ + Bnd_B3d* box = new Bnd_B3d; + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + box->Add( *myClassifiers[i]->GetBndBox() ); + return box; +} + +/* + Class : BelongToGeom + Description : Predicate for verifying whether entity belongs to + specified geometrical support +*/ + +BelongToGeom::BelongToGeom() + : myMeshDS(NULL), + myType(SMDSAbs_NbElementTypes), + myIsSubshape(false), + myTolerance(Precision::Confusion()) +{} + +Predicate* BelongToGeom::clone() const +{ + BelongToGeom* cln = new BelongToGeom( *this ); + cln->myElementsOnShapePtr.reset( static_cast( myElementsOnShapePtr->clone() )); + return cln; +} + +void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( myMeshDS != theMesh ) + { + myMeshDS = dynamic_cast(theMesh); + init(); + } +} + +void BelongToGeom::SetGeom( const TopoDS_Shape& theShape ) +{ + if ( myShape != theShape ) + { + myShape = theShape; + init(); + } +} + +static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap, + const TopoDS_Shape& theShape) +{ + if (theMap.Contains(theShape)) return true; + + if (theShape.ShapeType() == TopAbs_COMPOUND || + theShape.ShapeType() == TopAbs_COMPSOLID) + { + TopoDS_Iterator anIt (theShape, Standard_True, Standard_True); + for (; anIt.More(); anIt.Next()) + { + if (!IsSubShape(theMap, anIt.Value())) { + return false; } - break; - case TopAbs_VERTEX: + } + return true; + } + + return false; +} + +void BelongToGeom::init() +{ + if ( !myMeshDS || myShape.IsNull() ) return; + + // is sub-shape of main shape? + TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh(); + if (aMainShape.IsNull()) { + myIsSubshape = false; + } + else { + TopTools_IndexedMapOfShape aMap; + TopExp::MapShapes( aMainShape, aMap ); + myIsSubshape = IsSubShape( aMap, myShape ); + if ( myIsSubshape ) + { + aMap.Clear(); + TopExp::MapShapes( myShape, aMap ); + mySubShapesIDs.Clear(); + for ( int i = 1; i <= aMap.Extent(); ++i ) { - isSatisfy = (myCurPnt.Distance(aPnt) <= myToler); + int subID = myMeshDS->ShapeToIndex( aMap( i )); + if ( subID > 0 ) + mySubShapesIDs.Add( subID ); } - break; - default: + } + } + + //if (!myIsSubshape) // to be always ready to check an element not bound to geometry + { + if ( !myElementsOnShapePtr ) + myElementsOnShapePtr.reset( new ElementsOnShape() ); + myElementsOnShapePtr->SetTolerance( myTolerance ); + myElementsOnShapePtr->SetAllNodes( true ); // "belong", while false means "lays on" + myElementsOnShapePtr->SetMesh( myMeshDS ); + myElementsOnShapePtr->SetShape( myShape, myType ); + } +} + +bool BelongToGeom::IsSatisfy (long theId) +{ + if (myMeshDS == 0 || myShape.IsNull()) + return false; + + if (!myIsSubshape) + { + return myElementsOnShapePtr->IsSatisfy(theId); + } + + // Case of sub-mesh + + if (myType == SMDSAbs_Node) + { + if ( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId )) + { + if ( aNode->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + else + return mySubShapesIDs.Contains( aNode->getshapeId() ); + } + } + else + { + if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId )) + { + if ( anElem->GetType() == myType ) { - isSatisfy = false; + if ( anElem->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + else + return mySubShapesIDs.Contains( anElem->getshapeId() ); } } } - if (isSatisfy && myCurShapeType == TopAbs_SOLID) { // Check the center point for volumes MantisBug 0020168 - centerXYZ /= theElemPtr->NbNodes(); - gp_Pnt aCenterPnt (centerXYZ); - myCurSC.Perform(aCenterPnt, myToler); - if ( !(myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON)) - isSatisfy = false; + return false; +} + +void BelongToGeom::SetType (SMDSAbs_ElementType theType) +{ + if ( myType != theType ) + { + myType = theType; + init(); + } +} + +SMDSAbs_ElementType BelongToGeom::GetType() const +{ + return myType; +} + +TopoDS_Shape BelongToGeom::GetShape() +{ + return myShape; +} + +const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const +{ + return myMeshDS; +} + +void BelongToGeom::SetTolerance (double theTolerance) +{ + myTolerance = theTolerance; + init(); +} + +double BelongToGeom::GetTolerance() +{ + return myTolerance; +} + +/* + Class : LyingOnGeom + Description : Predicate for verifying whether entiy lying or partially lying on + specified geometrical support +*/ + +LyingOnGeom::LyingOnGeom() + : myMeshDS(NULL), + myType(SMDSAbs_NbElementTypes), + myIsSubshape(false), + myTolerance(Precision::Confusion()) +{} + +Predicate* LyingOnGeom::clone() const +{ + LyingOnGeom* cln = new LyingOnGeom( *this ); + cln->myElementsOnShapePtr.reset( static_cast( myElementsOnShapePtr->clone() )); + return cln; +} + +void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( myMeshDS != theMesh ) + { + myMeshDS = dynamic_cast(theMesh); + init(); + } +} + +void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape ) +{ + if ( myShape != theShape ) + { + myShape = theShape; + init(); } +} + +void LyingOnGeom::init() +{ + if (!myMeshDS || myShape.IsNull()) return; + + // is sub-shape of main shape? + TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh(); + if (aMainShape.IsNull()) { + myIsSubshape = false; + } + else { + myIsSubshape = myMeshDS->IsGroupOfSubShapes( myShape ); + } + + if (myIsSubshape) + { + TopTools_IndexedMapOfShape shapes; + TopExp::MapShapes( myShape, shapes ); + mySubShapesIDs.Clear(); + for ( int i = 1; i <= shapes.Extent(); ++i ) + { + int subID = myMeshDS->ShapeToIndex( shapes( i )); + if ( subID > 0 ) + mySubShapesIDs.Add( subID ); + } + } + // else // to be always ready to check an element not bound to geometry + { + if ( !myElementsOnShapePtr ) + myElementsOnShapePtr.reset( new ElementsOnShape() ); + myElementsOnShapePtr->SetTolerance( myTolerance ); + myElementsOnShapePtr->SetAllNodes( false ); // lays on, while true means "belong" + myElementsOnShapePtr->SetMesh( myMeshDS ); + myElementsOnShapePtr->SetShape( myShape, myType ); + } +} + +bool LyingOnGeom::IsSatisfy( long theId ) +{ + if ( myMeshDS == 0 || myShape.IsNull() ) + return false; + + if (!myIsSubshape) + { + return myElementsOnShapePtr->IsSatisfy(theId); + } + + // Case of sub-mesh + + const SMDS_MeshElement* elem = + ( myType == SMDSAbs_Node ) ? myMeshDS->FindNode( theId ) : myMeshDS->FindElement( theId ); + + if ( mySubShapesIDs.Contains( elem->getshapeId() )) + return true; + + if ( elem->GetType() != SMDSAbs_Node && elem->GetType() == myType ) + { + SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshElement* aNode = nodeItr->next(); + if ( mySubShapesIDs.Contains( aNode->getshapeId() )) + return true; + } + } + + return false; +} + +void LyingOnGeom::SetType( SMDSAbs_ElementType theType ) +{ + if ( myType != theType ) + { + myType = theType; + init(); + } +} + +SMDSAbs_ElementType LyingOnGeom::GetType() const +{ + return myType; +} + +TopoDS_Shape LyingOnGeom::GetShape() +{ + return myShape; +} + +const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const +{ + return myMeshDS; +} - if (isSatisfy) - myIds.Add(theElemPtr->GetID()); +void LyingOnGeom::SetTolerance (double theTolerance) +{ + myTolerance = theTolerance; + init(); +} + +double LyingOnGeom::GetTolerance() +{ + return myTolerance; } -TSequenceOfXYZ::TSequenceOfXYZ() +TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n) +TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n), myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t) +TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t), myElem(0) {} -TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray) +TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray), myElem(theSequenceOfXYZ.myElem) {} template -TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd) +TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd), myElem(0) {} TSequenceOfXYZ::~TSequenceOfXYZ() @@ -3969,6 +5077,7 @@ TSequenceOfXYZ::~TSequenceOfXYZ() TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ) { myArray = theSequenceOfXYZ.myArray; + myElem = theSequenceOfXYZ.myElem; return *this; } @@ -4002,6 +5111,11 @@ TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const return myArray.size(); } +SMDSAbs_EntityType TSequenceOfXYZ::getElementEntity() const +{ + return myElem ? myElem->GetEntityType() : SMDSEntity_Last; +} + TMeshModifTracer::TMeshModifTracer(): myMeshModifTime(0), myMesh(0) {