X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FControls%2FSMESH_Controls.cxx;h=bad6ae8f9feed3f30c7c82908c37552ff537caea;hb=54d277e9e3ba8789be5a561d280b86b979266c87;hp=7699902c190078253069fcc809dbd096a12317f0;hpb=05fdecbb6aa137c234b18681c72f25ff9fd997c7;p=modules%2Fsmesh.git diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 7699902c1..bad6ae8f9 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -1,21 +1,21 @@ // Copyright (C) 2003 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 +// 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 distributed in the hope that it will be useful, +// 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 +// 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 -// -// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org +// +// 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 #include "SMESH_ControlsDef.hxx" @@ -46,17 +46,19 @@ #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" #include "SMDS_VolumeTool.hxx" +#include "SMDS_QuadraticFaceOfNodes.hxx" +#include "SMDS_QuadraticEdge.hxx" /* - AUXILIARY METHODS + AUXILIARY METHODS */ namespace{ inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 ) { gp_Vec v1( P1 - P2 ), v2( P3 - P2 ); - + return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 ); } @@ -85,35 +87,72 @@ namespace{ { if ( theMesh == 0 ) return 0; - + const SMDS_MeshElement* anEdge = theMesh->FindElement( theId ); - if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge || anEdge->NbNodes() != 2 ) + if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */) return 0; - - TColStd_MapOfInteger aMap; - - int aResult = 0; - 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++; - } - } + + // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge) + // count elements containing both nodes of the pair. + // Note that there may be such cases for a quadratic edge (a horizontal line): + // + // Case 1 Case 2 + // | | | | | + // | | | | | + // +-----+------+ +-----+------+ + // | | | | + // | | | | + // result sould 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 ); + if ( aNode1 == aLastNode ) aNode1 = 0; + + SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator(); + while( anElemIter->more() ) { + const SMDS_MeshElement* anElem = anElemIter->next(); + if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) { + SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); + while ( anIter->more() ) { + if ( const SMDS_MeshElement* anElemNode = anIter->next() ) { + if ( anElemNode == aNode0 ) { + aResult0++; + if ( !aNode1 ) break; // not a quadratic edge + } + else if ( anElemNode == aNode1 ) + aResult1++; + } + } } } - + int aResult = 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; } @@ -154,23 +193,41 @@ bool NumericalFunctor::GetPoints(const int theId, } bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, - TSequenceOfXYZ& theRes ) + TSequenceOfXYZ& theRes ) { theRes.clear(); if ( anElem == 0) return false; + theRes.reserve( anElem->NbNodes() ); + // Get nodes of the element - SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); - if ( anIter != 0 ) - { - while( anIter->more() ) - { - const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next(); - if ( aNode != 0 ){ + SMDS_ElemIteratorPtr anIter; + + if ( anElem->IsQuadratic() ) { + switch ( anElem->GetType() ) { + case SMDSAbs_Edge: + anIter = static_cast + (anElem)->interlacedNodesElemIterator(); + break; + case SMDSAbs_Face: + anIter = static_cast + (anElem)->interlacedNodesElemIterator(); + break; + default: + anIter = anElem->nodesIterator(); + //return false; + } + } + else { + anIter = anElem->nodesIterator(); + } + + if ( anIter ) { + while( anIter->more() ) { + if ( const SMDS_MeshNode* aNode = static_cast( anIter->next() )) theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); - } } } @@ -189,6 +246,7 @@ void NumericalFunctor::SetPrecision( const long thePrecision ) double NumericalFunctor::GetValue( long theId ) { + myCurrElement = myMesh->FindElement( theId ); TSequenceOfXYZ P; if ( GetPoints( theId, P )) { @@ -204,6 +262,42 @@ double NumericalFunctor::GetValue( long theId ) return 0.; } +//======================================================================= +//function : GetValue +//purpose : +//======================================================================= + +double Volume::GetValue( long theElementId ) +{ + if ( theElementId && myMesh ) { + SMDS_VolumeTool aVolumeTool; + if ( aVolumeTool.Set( myMesh->FindElement( theElementId ))) + return aVolumeTool.GetSize(); + } + 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 : MinimumAngle Description : Functor for calculation of minimum angle @@ -218,18 +312,19 @@ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) aMin = getAngle(P( P.size() ), P( 1 ), P( 2 )); aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 ))); - + for (int i=2; i 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 ) ); // Compute aspect ratio - if ( nbNodes == 3 ) + if ( nbNodes == 3 ) { + // 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.; - double aMaxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) ); - static double aCoef = sqrt( 3. ) / 4; - return aCoef * aMaxLen * aMaxLen / anArea; + return alfa * maxLen * half_perimeter / anArea; } else { - double aMinLen = aLen[ 0 ]; - double aMaxLen = aLen[ 0 ]; - - for(int i = 1; i < nbNodes ; i++ ){ - aMinLen = Min( aMinLen, aLen[ i ] ); - aMaxLen = Max( aMaxLen, aLen[ i ] ); - } - if ( aMinLen <= Precision::Confusion() ) - return 0.; - - return aMaxLen / aMinLen; + // return aspect ratio of the worst triange which can be built + // taking three nodes of the quadrangle + TSequenceOfXYZ triaPnts(3); + // triangle on nodes 1 3 2 + triaPnts(1) = P(1); + triaPnts(2) = P(3); + triaPnts(3) = P(2); + double ar = GetValue( triaPnts ); + // triangle on nodes 1 3 4 + triaPnts(3) = P(4); + ar = Max ( ar, GetValue( triaPnts )); + // triangle on nodes 1 2 4 + triaPnts(2) = P(2); + ar = Max ( ar, GetValue( triaPnts )); + // triangle on nodes 3 2 4 + triaPnts(1) = P(3); + ar = Max ( ar, GetValue( triaPnts )); + + return ar; } } @@ -341,7 +458,7 @@ namespace{ double Q = b2*f2*(a2+c2+d2+e2-b2-f2); double R = c2*d2*(a2+b2+e2+f2-c2-d2); double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2; - + return sqrt(P+Q+R-S)/12.0; } @@ -368,6 +485,7 @@ namespace{ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) { double aQuality = 0.0; + if(myCurrElement->IsPoly()) return aQuality; int nbNodes = P.size(); switch(nbNodes){ case 4:{ @@ -401,7 +519,7 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) double aVolume = getVolume(P); //double aVolume = getVolume(aLen); double aHeight = getMaxHeight(aLen); - static double aCoeff = sqrt(6.0)/36.0; + static double aCoeff = sqrt(2.0)/12.0; aQuality = aCoeff*aHeight*aSumArea/aVolume; break; } @@ -587,6 +705,21 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P ) break; } } + if ( nbNodes > 4 ) { + // avaluate aspect ratio of quadranle faces + AspectRatio aspect2D; + SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes ); + int nbFaces = SMDS_VolumeTool::NbFaces( type ); + TSequenceOfXYZ points(4); + for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume + 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 + points( p + 1 ) = P( pInd[ p ] + 1 ); + aQuality = max( aQuality, aspect2D.GetValue( points )); + } + } return aQuality; } @@ -732,7 +865,7 @@ double Skew::GetValue( const TSequenceOfXYZ& P ) return Max( A0, Max( A1, A2 ) ) * 180 / PI; } - else + else { gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2; gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2; @@ -767,21 +900,21 @@ SMDSAbs_ElementType Skew::GetType() const */ double Area::GetValue( const TSequenceOfXYZ& P ) { - double aArea = 0; - if ( P.size() == 3 ) - return getArea( P( 1 ), P( 2 ), P( 3 ) ); - else if (P.size() > 3) - aArea = getArea( P( 1 ), P( 2 ), P( 3 ) ); - else - return 0; - - for (int i=4; i<=P.size(); i++) - aArea += getArea(P(1),P(i-1),P(i)); - return aArea; + 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++) { + gp_Vec aVec1( P(i-1) - P(1) ); + gp_Vec aVec2( P(i) - P(1) ); + gp_Vec tmp = aVec1 ^ aVec2; + SumVec.Add(tmp); + } + return SumVec.Magnitude() * 0.5; } double Area::GetBadRate( double Value, int /*nbNodes*/ ) const { + // meaningless as it is not a quality control functor return Value; } @@ -797,11 +930,16 @@ SMDSAbs_ElementType Area::GetType() const */ double Length::GetValue( const TSequenceOfXYZ& P ) { - return ( P.size() == 2 ? getDistance( P( 1 ), P( 2 ) ) : 0 ); + switch ( P.size() ) { + case 2: return getDistance( P( 1 ), P( 2 ) ); + case 3: return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) ); + default: return 0.; + } } double Length::GetBadRate( double Value, int /*nbNodes*/ ) const { + // meaningless as it is not quality control functor return Value; } @@ -819,21 +957,28 @@ double Length2D::GetValue( long theElementId) { 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_Node: case SMDSAbs_Edge: if (len == 2){ aVal = getDistance( P( 1 ), P( 2 ) ); - break; + 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 @@ -851,6 +996,22 @@ double Length2D::GetValue( long theElementId) 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() && myType != SMDSAbs_All ) return false; } - + if ( myIds.Contains( theId ) ) return true; @@ -1729,10 +2007,10 @@ SMDSAbs_ElementType LogicalBinary::GetType() const */ bool LogicalAND::IsSatisfy( long theId ) { - return - myPredicate1 && - myPredicate2 && - myPredicate1->IsSatisfy( theId ) && + return + myPredicate1 && + myPredicate2 && + myPredicate1->IsSatisfy( theId ) && myPredicate2->IsSatisfy( theId ); } @@ -1743,10 +2021,10 @@ bool LogicalAND::IsSatisfy( long theId ) */ bool LogicalOR::IsSatisfy( long theId ) { - return - myPredicate1 && - myPredicate2 && - myPredicate1->IsSatisfy( theId ) || + return + myPredicate1 && + myPredicate2 && + myPredicate1->IsSatisfy( theId ) || myPredicate2->IsSatisfy( theId ); } @@ -1766,7 +2044,7 @@ void Filter::SetPredicate( PredicatePtr thePredicate ) myPredicate = thePredicate; } -template +template inline void FillSequence(const TIterator& theIterator, TPredicate& thePredicate, Filter::TIdSequence& theSequence) @@ -1783,13 +2061,13 @@ inline void FillSequence(const TIterator& theIterator, void Filter:: -GetElementsId( const SMDS_Mesh* theMesh, - PredicatePtr thePredicate, +GetElementsId( const SMDS_Mesh* theMesh, + PredicatePtr thePredicate, TIdSequence& theSequence ) { theSequence.clear(); - if ( !theMesh || !thePredicate ) + if ( !theMesh || !thePredicate ) return; thePredicate->SetMesh( theMesh ); @@ -1829,9 +2107,9 @@ Filter::GetElementsId( const SMDS_Mesh* theMesh, typedef std::set TMapOfFacePtr; -/* +/* Internal class Link -*/ +*/ ManifoldPart::Link::Link( SMDS_MeshNode* theNode1, SMDS_MeshNode* theNode2 ) @@ -1868,7 +2146,7 @@ bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1, const ManifoldPart::Link& theLink2 ) -{ +{ return theLink1.IsEqual( theLink2 ); } @@ -1914,7 +2192,7 @@ bool ManifoldPart::process() { myMapIds.Clear(); myMapBadGeomIds.Clear(); - + myAllFacePtr.clear(); myAllFacePtrIntDMap.clear(); if ( !myMesh ) @@ -1946,7 +2224,7 @@ bool ManifoldPart::process() if ( fi == aStartIndx ) isStartTreat = true; // as result next time when fi will be equal to aStartIndx - + SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ]; if ( aMapOfTreated.Contains( aFacePtr->GetID() ) ) continue; @@ -1979,7 +2257,7 @@ static void getLinks( const SMDS_MeshFace* theFace, SMDS_MeshNode* aNode = 0; for ( ; aNodeItr->more() && i <= aNbNode; ) { - + SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next(); if ( i == 1 ) aNode = aN1; @@ -1998,17 +2276,15 @@ static gp_XYZ getNormale( const SMDS_MeshFace* theFace ) TColgp_Array1OfXYZ anArrOfXYZ(1,4); SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator(); int i = 1; - for ( ; aNodeItr->more() && i <= 4; i++ ) - { + for ( ; aNodeItr->more() && i <= 4; i++ ) { SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); } - + gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1); gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1); n = q1 ^ q2; - if ( aNbNode > 3 ) - { + if ( aNbNode > 3 ) { gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1); n += q2 ^ q3; } @@ -2028,7 +2304,7 @@ bool ManifoldPart::findConnected theResFaces.Clear(); if ( !theAllFacePtrInt.size() ) return false; - + if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() ) { myMapBadGeomIds.Add( theStartFace->GetID() ); @@ -2040,7 +2316,7 @@ bool ManifoldPart::findConnected theResFaces.Add( theStartFace->GetID() ); ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace; - expandBoundary( aMapOfBoundary, aSeqOfBoundary, + expandBoundary( aMapOfBoundary, aSeqOfBoundary, aDMapLinkFace, theNonManifold, theStartFace ); bool isDone = false; @@ -2058,7 +2334,7 @@ bool ManifoldPart::findConnected ManifoldPart::TVectorOfFacePtr aFaces; // find next - if ( myIsOnlyManifold && + if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) ) continue; else @@ -2082,7 +2358,7 @@ bool ManifoldPart::findConnected continue; } } - + // compare normal with normals of neighbor element SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ]; ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin(); @@ -2101,7 +2377,7 @@ bool ManifoldPart::findConnected continue; // add new element to connected and extend the boundaries. theResFaces.Add( anNextFaceID ); - expandBoundary( aMapOfBoundary, aSeqOfBoundary, + expandBoundary( aMapOfBoundary, aSeqOfBoundary, aDMapLinkFace, theNonManifold, aNextFace ); isToReset = true; } @@ -2137,7 +2413,7 @@ void ManifoldPart::expandBoundary { ManifoldPart::TVectorOfLink aLinks; getLinks( theNextFace, aLinks ); - int aNbLink = aLinks.size(); + int aNbLink = (int)aLinks.size(); for ( int i = 0; i < aNbLink; i++ ) { ManifoldPart::Link aLink = aLinks[ i ]; @@ -2214,7 +2490,7 @@ ElementsOnSurface::~ElementsOnSurface() } void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh ) -{ +{ if ( myMesh == theMesh ) return; myMesh = theMesh;