X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FControls%2FSMESH_Controls.cxx;h=6b400350d09daae940b87994fc36ecec6be6ac76;hb=f0bf265fc0ea849ad1a359e10ad0c9cf6b0b9bb8;hp=5238b982f3c55ee99f83bf4048d2096b2f866e3c;hpb=d8f644ca3d4ce62f2ef41d4aacb52f5bb1221df3;p=modules%2Fsmesh.git diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 5238b982f..6b400350d 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -1,52 +1,57 @@ -// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2012 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 +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // -// 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. +// 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. // -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. // -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "SMESH_ControlsDef.hxx" -#include -#include +#include "SMDS_BallElement.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_Mesh.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 +#include +#include #include #include #include @@ -55,16 +60,11 @@ #include #include -#include "SMDS_Mesh.hxx" -#include "SMDS_Iterator.hxx" -#include "SMDS_MeshElement.hxx" -#include "SMDS_MeshNode.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMDS_QuadraticFaceOfNodes.hxx" -#include "SMDS_QuadraticEdge.hxx" +#include + +#include +#include -#include "SMESHDS_Mesh.hxx" -#include "SMESHDS_GroupBase.hxx" /* AUXILIARY METHODS @@ -250,11 +250,11 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, if ( anElem->IsQuadratic() ) { switch ( anElem->GetType() ) { case SMDSAbs_Edge: - anIter = static_cast + anIter = dynamic_cast (anElem)->interlacedNodesElemIterator(); break; case SMDSAbs_Face: - anIter = static_cast + anIter = dynamic_cast (anElem)->interlacedNodesElemIterator(); break; default: @@ -284,24 +284,25 @@ long NumericalFunctor::GetPrecision() const void NumericalFunctor::SetPrecision( const long thePrecision ) { myPrecision = thePrecision; + myPrecisionValue = pow( 10., (double)( myPrecision ) ); } double NumericalFunctor::GetValue( long theId ) { + double aVal = 0; + myCurrElement = myMesh->FindElement( theId ); + TSequenceOfXYZ P; if ( GetPoints( theId, P )) - { - double aVal = GetValue( P ); - if ( myPrecision >= 0 ) - { - double prec = pow( 10., (double)( myPrecision ) ); - aVal = floor( aVal * prec + 0.5 ) / prec; - } - return aVal; - } + aVal = Round( GetValue( P )); - return 0.; + return aVal; +} + +double NumericalFunctor::Round( const double & aVal ) +{ + return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal; } //================================================================================ @@ -310,12 +311,16 @@ double NumericalFunctor::GetValue( long theId ) * \param nbIntervals - number of intervals * \param nbEvents - number of mesh elements having values within i-th interval * \param funValues - boundaries of intervals + * \param elements - elements to check vulue of; empty list means "of all" + * \param minmax - boundaries of diapason of values to divide into intervals */ //================================================================================ void NumericalFunctor::GetHistogram(int nbIntervals, std::vector& nbEvents, - std::vector& funValues) + std::vector& funValues, + const vector& elements, + const double* minmax) { if ( nbIntervals < 1 || !myMesh || @@ -326,13 +331,30 @@ void NumericalFunctor::GetHistogram(int nbIntervals, // get all values sorted std::multiset< double > values; - SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); - while ( elemIt->more() ) - values.insert( GetValue( elemIt->next()->GetID() )); + if ( elements.empty() ) + { + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + while ( elemIt->more() ) + values.insert( GetValue( elemIt->next()->GetID() )); + } + else + { + vector::const_iterator id = elements.begin(); + for ( ; id != elements.end(); ++id ) + values.insert( GetValue( *id )); + } + if ( minmax ) + { + funValues[0] = minmax[0]; + funValues[nbIntervals] = minmax[1]; + } + else + { + funValues[0] = *values.begin(); + funValues[nbIntervals] = *values.rbegin(); + } // case nbIntervals == 1 - funValues[0] = *values.begin(); - funValues[nbIntervals] = *values.rbegin(); if ( nbIntervals == 1 ) { nbEvents[0] = values.size(); @@ -350,15 +372,21 @@ void NumericalFunctor::GetHistogram(int nbIntervals, std::multiset< double >::iterator min = values.begin(), max; 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; + + // count values in the i-th interval if there are any if ( min != values.end() && *min <= funValues[i+1] ) { - max = values.upper_bound( funValues[i+1] ); // greater than funValues[i+1], or end() + // find the first value out of the interval + max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end() nbEvents[i] = std::distance( min, max ); min = max; } } + // add values larger than minmax[1] + nbEvents.back() += std::distance( min, values.end() ); } //======================================================================= @@ -401,59 +429,56 @@ SMDSAbs_ElementType Volume::GetType() const 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)); + } + + 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 ) { // 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; + if( GetPoints( theElementId, P ) && myMesh->FindElement( theElementId )->GetType() == SMDSAbs_Face) { + GetValue(P); } return 0.; } @@ -543,6 +568,12 @@ double MaxElementLength3D::GetValue( long theElementId ) 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 )); @@ -580,7 +611,7 @@ double MaxElementLength3D::GetValue( long theElementId ) aVal = Max(aVal,Max(Max(L7,L8),L9)); break; } - else if( len == 20 ) { // quadratic hexas + 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 )); @@ -657,7 +688,7 @@ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) aMin = Min(aMin,A0); } - return aMin * 180.0 / PI; + return aMin * 180.0 / M_PI; } double MinimumAngle::GetBadRate( double Value, int nbNodes ) const @@ -677,6 +708,26 @@ SMDSAbs_ElementType MinimumAngle::GetType() const Class : AspectRatio Description : Functor for calculating aspect ratio */ +double AspectRatio::GetValue( long theId ) +{ + double aVal = 0; + myCurrElement = myMesh->FindElement( theId ); + if ( myCurrElement && myCurrElement->GetVtkType() == VTK_QUAD ) + { + // issue 21723 + vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid(); + if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() )) + aVal = Round( vtkMeshQuality::QuadAspectRatio( avtkCell )); + } + else + { + TSequenceOfXYZ P; + if ( GetPoints( myCurrElement, P )) + aVal = Round( GetValue( P )); + } + return aVal; +} + double AspectRatio::GetValue( const TSequenceOfXYZ& P ) { // According to "Mesh quality control" by Nadir Bouhamau referring to @@ -775,7 +826,7 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) return 0.; return alpha * L * C1 / C2; } - else if( nbNodes == 8 ){ // nbNodes==8 - quadratic quadrangle + else if( nbNodes == 8 || nbNodes == 9 ) { // nbNodes==8 - quadratic quadrangle // Compute lengths of the sides std::vector< double > aLen (4); aLen[0] = getDistance( P(1), P(3) ); @@ -825,9 +876,10 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const { // the aspect ratio is in the range [1.0,infinity] + // < 1.0 = very bad, zero area // 1.0 = good // infinity = bad - return Value / 1000.; + return ( Value < 0.9 ) ? 1000 : Value / 1000.; } SMDSAbs_ElementType AspectRatio::GetType() const @@ -902,6 +954,28 @@ namespace{ } +double AspectRatio3D::GetValue( long theId ) +{ + double aVal = 0; + myCurrElement = myMesh->FindElement( theId ); + if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA ) + { + // 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() )) + aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell )); + } + else + { + TSequenceOfXYZ P; + if ( GetPoints( myCurrElement, P )) + aVal = Round( GetValue( P )); + } + return aVal; +} + double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) { double aQuality = 0.0; @@ -914,10 +988,11 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) else if(nbNodes==13) nbNodes=5; // quadratic pyramid else if(nbNodes==15) nbNodes=6; // quadratic pentahedron else if(nbNodes==20) nbNodes=8; // quadratic hexahedron + else if(nbNodes==27) nbNodes=8; // quadratic hexahedron else return aQuality; } - switch(nbNodes){ + switch(nbNodes) { case 4:{ double aLen[6] = { getDistance(P( 1 ),P( 2 )), // a @@ -1135,7 +1210,22 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) } break; } - } + case 12: + { + gp_XYZ aXYZ[8] = {P( 1 ),P( 2 ),P( 4 ),P( 5 ),P( 7 ),P( 8 ),P( 10 ),P( 11 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + { + gp_XYZ aXYZ[8] = {P( 2 ),P( 3 ),P( 5 ),P( 6 ),P( 8 ),P( 9 ),P( 11 ),P( 12 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + { + gp_XYZ aXYZ[8] = {P( 3 ),P( 4 ),P( 6 ),P( 1 ),P( 9 ),P( 10 ),P( 12 ),P( 7 )}; + aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[8])),aQuality); + } + break; + } // switch(nbNodes) + if ( nbNodes > 4 ) { // avaluate aspect ratio of quadranle faces AspectRatio aspect2D; @@ -1203,12 +1293,12 @@ double Warping::ComputeA( const gp_XYZ& thePnt1, gp_XYZ N = GI.Crossed( GJ ); if ( N.Modulus() < gp::Resolution() ) - return PI / 2; + return M_PI / 2; N.Normalize(); double H = ( thePnt2 - theG ).Dot( N ); - return asin( fabs( H / L ) ) * 180. / PI; + return asin( fabs( H / L ) ) * 180. / M_PI; } double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const @@ -1287,14 +1377,14 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) return 0.; // Compute skew - static double PI2 = PI / 2.; + static double PI2 = M_PI / 2.; if ( P.size() == 3 ) { double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) ); double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) ); double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) ); - return Max( A0, Max( A1, A2 ) ) * 180. / PI; + return Max( A0, Max( A1, A2 ) ) * 180. / M_PI; } else { @@ -1311,7 +1401,7 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) if ( A < Precision::Angular() ) return 0.; - return A * 180. / PI; + return A * 180. / M_PI; } } @@ -1365,7 +1455,7 @@ SMDSAbs_ElementType Area::GetType() const /* Class : Length - Description : Functor for calculating length off edge + Description : Functor for calculating length of edge */ double Length::GetValue( const TSequenceOfXYZ& P ) { @@ -1622,10 +1712,10 @@ void Length2D::GetValues(TValues& theValues){ const SMDS_MeshFace* anElem = anIter->next(); if(anElem->IsQuadratic()) { - const SMDS_QuadraticFaceOfNodes* F = - static_cast(anElem); + const SMDS_VtkFace* F = + dynamic_cast(anElem); // use special nodes iterator - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); long aNodeId[4]; gp_Pnt P[4]; @@ -1819,7 +1909,7 @@ void MultiConnection2D::GetValues(MValues& theValues){ const SMDS_MeshFace* anElem = anIter->next(); SMDS_ElemIteratorPtr aNodesIter; if ( anElem->IsQuadratic() ) - aNodesIter = static_cast + aNodesIter = dynamic_cast (anElem)->interlacedNodesElemIterator(); else aNodesIter = anElem->nodesIterator(); @@ -1869,6 +1959,34 @@ void MultiConnection2D::GetValues(MValues& theValues){ } +/* + Class : BallDiameter + Description : Functor returning diameter of a ball element +*/ +double BallDiameter::GetValue( long theId ) +{ + double diameter = 0; + + if ( const SMDS_BallElement* ball = + dynamic_cast( myMesh->FindElement( theId ))) + { + diameter = ball->GetDiameter(); + } + return diameter; +} + +double BallDiameter::GetBadRate( double Value, int /*nbNodes*/ ) const +{ + // meaningless as it is not a quality control functor + return Value; +} + +SMDSAbs_ElementType BallDiameter::GetType() const +{ + return SMDSAbs_Ball; +} + + /* PREDICATES */ @@ -1902,6 +2020,218 @@ SMDSAbs_ElementType BadOrientedVolume::GetType() const return SMDSAbs_Volume; } +/* + Class : BareBorderVolume +*/ + +bool BareBorderVolume::IsSatisfy(long theElementId ) +{ + SMDS_VolumeTool myTool; + if ( myTool.Set( myMesh->FindElement(theElementId))) + { + for ( int iF = 0; iF < myTool.NbFaces(); ++iF ) + if ( myTool.IsFreeFace( iF )) + { + const SMDS_MeshNode** n = myTool.GetFaceNodes(iF); + vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF)); + if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false)) + return true; + } + } + return false; +} + +/* + Class : BareBorderFace +*/ + +bool BareBorderFace::IsSatisfy(long theElementId ) +{ + bool ok = false; + if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId)) + { + if ( face->GetType() == SMDSAbs_Face ) + { + int nbN = face->NbCornerNodes(); + for ( int i = 0; i < nbN && !ok; ++i ) + { + // check if a link is shared by another face + const SMDS_MeshNode* n1 = face->GetNode( i ); + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN ); + SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face ); + bool isShared = false; + while ( !isShared && fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + isShared = ( f != face && f->GetNodeIndex(n2) != -1 ); + } + if ( !isShared ) + { + const int iQuad = face->IsQuadratic(); + myLinkNodes.resize( 2 + iQuad); + myLinkNodes[0] = n1; + myLinkNodes[1] = n2; + if ( iQuad ) + myLinkNodes[2] = face->GetNode( i+nbN ); + ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false); + } + } + } + } + return ok; +} + +/* + Class : OverConstrainedVolume +*/ + +bool OverConstrainedVolume::IsSatisfy(long theElementId ) +{ + // An element is over-constrained if it has N-1 free borders where + // N is the number of edges/faces for a 2D/3D element. + SMDS_VolumeTool myTool; + if ( myTool.Set( myMesh->FindElement(theElementId))) + { + int nbSharedFaces = 0; + for ( int iF = 0; iF < myTool.NbFaces(); ++iF ) + if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 ) + break; + return ( nbSharedFaces == 1 ); + } + return false; +} + +/* + Class : OverConstrainedFace +*/ + +bool OverConstrainedFace::IsSatisfy(long theElementId ) +{ + // An element is over-constrained if it has N-1 free borders where + // N is the number of edges/faces for a 2D/3D element. + if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId)) + if ( face->GetType() == SMDSAbs_Face ) + { + int nbSharedBorders = 0; + int nbN = face->NbCornerNodes(); + for ( int i = 0; i < nbN; ++i ) + { + // check if a link is shared by another face + const SMDS_MeshNode* n1 = face->GetNode( i ); + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN ); + SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face ); + bool isShared = false; + while ( !isShared && fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + isShared = ( f != face && f->GetNodeIndex(n2) != -1 ); + } + if ( isShared && ++nbSharedBorders > 1 ) + break; + } + return ( nbSharedBorders == 1 ); + } + return false; +} + +/* + Class : CoincidentNodes + Description : Predicate of Coincident nodes +*/ + +CoincidentNodes::CoincidentNodes() +{ + myToler = 1e-5; +} + +bool CoincidentNodes::IsSatisfy( long theElementId ) +{ + return myCoincidentIDs.Contains( theElementId ); +} + +SMDSAbs_ElementType CoincidentNodes::GetType() const +{ + return SMDSAbs_Node; +} + +void CoincidentNodes::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified() ) + { + TIDSortedNodeSet nodesToCheck; + SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); + while ( nIt->more() ) + nodesToCheck.insert( nodesToCheck.end(), nIt->next() ); + + list< list< const SMDS_MeshNode*> > nodeGroups; + SMESH_OctreeNode::FindCoincidentNodes ( nodesToCheck, &nodeGroups, myToler ); + + myCoincidentIDs.Clear(); + list< list< const SMDS_MeshNode*> >::iterator groupIt = nodeGroups.begin(); + for ( ; groupIt != nodeGroups.end(); ++groupIt ) + { + list< const SMDS_MeshNode*>& coincNodes = *groupIt; + list< const SMDS_MeshNode*>::iterator n = coincNodes.begin(); + for ( ; n != coincNodes.end(); ++n ) + myCoincidentIDs.Add( (*n)->GetID() ); + } + } +} + +/* + Class : CoincidentElements + Description : Predicate of Coincident Elements + Note : This class is suitable only for visualization of Coincident Elements +*/ + +CoincidentElements::CoincidentElements() +{ + myMesh = 0; +} + +void CoincidentElements::SetMesh( const SMDS_Mesh* theMesh ) +{ + myMesh = theMesh; +} + +bool CoincidentElements::IsSatisfy( long theElementId ) +{ + if ( !myMesh ) return false; + + if ( const SMDS_MeshElement* e = myMesh->FindElement( theElementId )) + { + if ( e->GetType() != GetType() ) return false; + set< const SMDS_MeshNode* > elemNodes( e->begin_nodes(), e->end_nodes() ); + const int nbNodes = e->NbNodes(); + SMDS_ElemIteratorPtr invIt = (*elemNodes.begin())->GetInverseElementIterator( GetType() ); + while ( invIt->more() ) + { + const SMDS_MeshElement* e2 = invIt->next(); + if ( e2 == e || e2->NbNodes() != nbNodes ) continue; + + bool sameNodes = true; + for ( size_t i = 0; i < elemNodes.size() && sameNodes; ++i ) + sameNodes = ( elemNodes.count( e2->GetNode( i ))); + if ( sameNodes ) + return true; + } + } + return false; +} + +SMDSAbs_ElementType CoincidentElements1D::GetType() const +{ + return SMDSAbs_Edge; +} +SMDSAbs_ElementType CoincidentElements2D::GetType() const +{ + return SMDSAbs_Face; +} +SMDSAbs_ElementType CoincidentElements3D::GetType() const +{ + return SMDSAbs_Volume; +} /* @@ -1949,17 +2279,13 @@ bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId TColStd_MapOfInteger aMap; for ( int i = 0; i < 2; i++ ) { - SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator(); + SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator(SMDSAbs_Face); while( anElemIter->more() ) { - const SMDS_MeshElement* anElem = anElemIter->next(); - if ( anElem != 0 && anElem->GetType() == SMDSAbs_Face ) + if ( const SMDS_MeshElement* anElem = anElemIter->next()) { - int anId = anElem->GetID(); - - if ( i == 0 ) - aMap.Add( anId ); - else if ( aMap.Contains( anId ) && anId != theFaceId ) + const int anId = anElem->GetID(); + if ( anId != theFaceId && !aMap.Add( anId )) return false; } } @@ -1978,13 +2304,13 @@ bool FreeEdges::IsSatisfy( long theId ) SMDS_ElemIteratorPtr anIter; if ( aFace->IsQuadratic() ) { - anIter = static_cast + anIter = dynamic_cast (aFace)->interlacedNodesElemIterator(); } else { anIter = aFace->nodesIterator(); } - if ( anIter == 0 ) + if ( !anIter ) return false; int i = 0, nbNodes = aFace->NbNodes(); @@ -2047,7 +2373,7 @@ void FreeEdges::GetBoreders(TBorders& theBorders) long anElemId = anElem->GetID(); SMDS_ElemIteratorPtr aNodesIter; if ( anElem->IsQuadratic() ) - aNodesIter = static_cast(anElem)-> + aNodesIter = static_cast(anElem)-> interlacedNodesElemIterator(); else aNodesIter = anElem->nodesIterator(); @@ -2062,14 +2388,11 @@ void FreeEdges::GetBoreders(TBorders& theBorders) long anId = aNode->GetID(); Border aBorder(anElemId,aNodeId[1],anId); aNodeId[1] = anId; - //std::cout<FindElement( theId ); - if ( anElem == 0 || myType != anElem->GetType() && myType != SMDSAbs_All ) + if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All )) return false; } @@ -2826,8 +3128,8 @@ bool LogicalOR::IsSatisfy( long theId ) return myPredicate1 && myPredicate2 && - myPredicate1->IsSatisfy( theId ) || - myPredicate2->IsSatisfy( theId ); + (myPredicate1->IsSatisfy( theId ) || + myPredicate2->IsSatisfy( theId )); } @@ -2846,26 +3148,9 @@ void Filter::SetPredicate( PredicatePtr thePredicate ) myPredicate = thePredicate; } -template -inline void FillSequence(const TIterator& theIterator, - TPredicate& thePredicate, - Filter::TIdSequence& theSequence) -{ - if ( theIterator ) { - while( theIterator->more() ) { - TElement anElem = theIterator->next(); - long anId = anElem->GetID(); - if ( thePredicate->IsSatisfy( anId ) ) - theSequence.push_back( anId ); - } - } -} - -void -Filter:: -GetElementsId( const SMDS_Mesh* theMesh, - PredicatePtr thePredicate, - TIdSequence& theSequence ) +void Filter::GetElementsId( const SMDS_Mesh* theMesh, + PredicatePtr thePredicate, + TIdSequence& theSequence ) { theSequence.clear(); @@ -2874,31 +3159,19 @@ GetElementsId( const SMDS_Mesh* theMesh, thePredicate->SetMesh( theMesh ); - SMDSAbs_ElementType aType = thePredicate->GetType(); - switch(aType){ - case SMDSAbs_Node: - FillSequence(theMesh->nodesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Edge: - FillSequence(theMesh->edgesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Face: - FillSequence(theMesh->facesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_Volume: - FillSequence(theMesh->volumesIterator(),thePredicate,theSequence); - break; - case SMDSAbs_All: - FillSequence(theMesh->edgesIterator(),thePredicate,theSequence); - FillSequence(theMesh->facesIterator(),thePredicate,theSequence); - FillSequence(theMesh->volumesIterator(),thePredicate,theSequence); - break; + SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() ); + if ( elemIt ) { + while ( elemIt->more() ) { + const SMDS_MeshElement* anElem = elemIt->next(); + long anId = anElem->GetID(); + if ( thePredicate->IsSatisfy( anId ) ) + theSequence.push_back( anId ); + } } } -void -Filter::GetElementsId( const SMDS_Mesh* theMesh, - Filter::TIdSequence& theSequence ) +void Filter::GetElementsId( const SMDS_Mesh* theMesh, + Filter::TIdSequence& theSequence ) { GetElementsId(theMesh,myPredicate,theSequence); } @@ -3225,7 +3498,7 @@ void ManifoldPart::expandBoundary void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, ManifoldPart::TVectorOfFacePtr& theFaces ) const { - SMDS_Mesh::SetOfFaces aSetOfFaces; + std::set aSetOfFaces; // take all faces that shared first node SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator(); for ( ; anItr->more(); ) @@ -3233,7 +3506,7 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); if ( !aFace ) continue; - aSetOfFaces.Add( aFace ); + aSetOfFaces.insert( aFace ); } // take all faces that shared second node anItr = theLink.myNode2->facesIterator(); @@ -3241,7 +3514,7 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, for ( ; anItr->more(); ) { SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next(); - if ( aSetOfFaces.Contains( aFace ) ) + if ( aSetOfFaces.count( aFace ) ) theFaces.push_back( aFace ); } } @@ -3253,7 +3526,6 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink, ElementsOnSurface::ElementsOnSurface() { - myMesh = 0; myIds.Clear(); myType = SMDSAbs_All; mySurf.Nullify(); @@ -3263,15 +3535,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 ) @@ -3326,32 +3596,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 ) @@ -3409,7 +3661,7 @@ bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode ) */ ElementsOnShape::ElementsOnShape() - : myMesh(0), + : //myMesh(0), myType(SMDSAbs_All), myToler(Precision::Confusion()), myAllNodesFlag(false) @@ -3423,10 +3675,9 @@ ElementsOnShape::~ElementsOnShape() void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) { - if (myMesh != theMesh) { - myMesh = theMesh; + myMeshModifTracer.SetMesh( theMesh ); + if ( myMeshModifTracer.IsMeshModified()) SetShape(myShape, myType); - } } bool ElementsOnShape::IsSatisfy (long theElementId) @@ -3467,28 +3718,11 @@ void ElementsOnShape::SetShape (const TopoDS_Shape& theShape, myShape = theShape; myIds.Clear(); - if (myMesh == 0) return; + const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); + + if ( !myMesh ) return; - switch (myType) - { - 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; - } + myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType )); myShapesMap.Clear(); addShape(myShape); @@ -3496,7 +3730,7 @@ void ElementsOnShape::SetShape (const TopoDS_Shape& theShape, void ElementsOnShape::addShape (const TopoDS_Shape& theShape) { - if (theShape.IsNull() || myMesh == 0) + if (theShape.IsNull() || myMeshModifTracer.GetMesh() == 0) return; if (!myShapesMap.Add(theShape)) return; @@ -3557,39 +3791,13 @@ void ElementsOnShape::addShape (const TopoDS_Shape& theShape) void ElementsOnShape::process() { + const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); if (myShape.IsNull() || myMesh == 0) return; - if (myType == SMDSAbs_Node) - { - SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator(); - while (anIter->more()) - process(anIter->next()); - } - else - { - if (myType == SMDSAbs_Edge || myType == SMDSAbs_All) - { - SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator(); - while (anIter->more()) - process(anIter->next()); - } - - if (myType == SMDSAbs_Face || myType == SMDSAbs_All) - { - SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); - while (anIter->more()) { - process(anIter->next()); - } - } - - if (myType == SMDSAbs_Volume || myType == SMDSAbs_All) - { - SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); - while (anIter->more()) - process(anIter->next()); - } - } + SMDS_ElemIteratorPtr anIter = myMesh->elementsIterator(myType); + while (anIter->more()) + process(anIter->next()); } void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) @@ -3604,9 +3812,8 @@ void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) { - SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); - gp_Pnt aPnt (aNode->X(), aNode->Y(), aNode->Z()); - centerXYZ += aPnt.XYZ(); + SMESH_TNodeXYZ aPnt ( aNodeItr->next() ); + centerXYZ += aPnt; switch (myCurShapeType) { @@ -3639,7 +3846,7 @@ void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) break; case TopAbs_VERTEX: { - isSatisfy = (aPnt.Distance(myCurPnt) <= myToler); + isSatisfy = (myCurPnt.Distance(aPnt) <= myToler); } break; default: @@ -3715,3 +3922,24 @@ TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const { return myArray.size(); } + +TMeshModifTracer::TMeshModifTracer(): + myMeshModifTime(0), myMesh(0) +{ +} +void TMeshModifTracer::SetMesh( const SMDS_Mesh* theMesh ) +{ + if ( theMesh != myMesh ) + myMeshModifTime = 0; + myMesh = theMesh; +} +bool TMeshModifTracer::IsMeshModified() +{ + bool modified = false; + if ( myMesh ) + { + modified = ( myMeshModifTime != myMesh->GetMTime() ); + myMeshModifTime = myMesh->GetMTime(); + } + return modified; +}