X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_Algo.cxx;h=4de1879f1c231c776c864765bf238f28eebaab66;hp=1b73359a0ed6cc823f1f3093b6702e939bb7be7d;hb=1fb3ff621ac19da15742a5e8b9253b594977d14a;hpb=513a8ebdac590b2e23d81adcb2fc1de76df90eef diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index 1b73359a0..4de1879f1 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2019 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 @@ -20,7 +20,7 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMESH : implementaion of SMESH idl descriptions +// SMESH SMESH : implementation of SMESH idl descriptions // File : SMESH_Algo.cxx // Author : Paul RASCLE, EDF // Module : SMESH @@ -42,8 +42,6 @@ #include "SMESH_TypeDefs.hxx" #include "SMESH_subMesh.hxx" -#include - #include #include #include @@ -87,7 +85,7 @@ using namespace std; bool SMESH_Algo::Features::IsCompatible( const SMESH_Algo::Features& algo2 ) const { if ( _dim > algo2._dim ) return algo2.IsCompatible( *this ); - // algo2 is of highter dimension + // algo2 is of higher dimension if ( _outElemTypes.empty() || algo2._inElemTypes.empty() ) return false; bool compatible = true; @@ -175,8 +173,8 @@ const SMESH_Algo::Features& SMESH_Algo::GetFeatures( const std::string& algoType */ //============================================================================= -SMESH_Algo::SMESH_Algo (int hypId, int studyId, SMESH_Gen * gen) - : SMESH_Hypothesis(hypId, studyId, gen) +SMESH_Algo::SMESH_Algo (int hypId, SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, gen) { _compatibleAllHypFilter = _compatibleNoAuxHypFilter = NULL; _onlyUnaryInput = _requireDiscreteBoundary = _requireShape = true; @@ -204,26 +202,26 @@ SMESH_Algo::~SMESH_Algo() */ //============================================================================= -SMESH_0D_Algo::SMESH_0D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) +SMESH_0D_Algo::SMESH_0D_Algo(int hypId, SMESH_Gen* gen) + : SMESH_Algo(hypId, gen) { _shapeType = (1 << TopAbs_VERTEX); _type = ALGO_0D; } -SMESH_1D_Algo::SMESH_1D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) +SMESH_1D_Algo::SMESH_1D_Algo(int hypId, SMESH_Gen* gen) + : SMESH_Algo(hypId, gen) { _shapeType = (1 << TopAbs_EDGE); _type = ALGO_1D; } -SMESH_2D_Algo::SMESH_2D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) +SMESH_2D_Algo::SMESH_2D_Algo(int hypId, SMESH_Gen* gen) + : SMESH_Algo(hypId, gen) { _shapeType = (1 << TopAbs_FACE); _type = ALGO_2D; } -SMESH_3D_Algo::SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_Algo(hypId, studyId, gen) +SMESH_3D_Algo::SMESH_3D_Algo(int hypId, SMESH_Gen* gen) + : SMESH_Algo(hypId, gen) { _shapeType = (1 << TopAbs_SOLID); _type = ALGO_3D; @@ -231,7 +229,7 @@ SMESH_3D_Algo::SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen) //============================================================================= /*! - * Usually an algoritm has nothing to save + * Usually an algorithm has nothing to save */ //============================================================================= @@ -265,6 +263,10 @@ SMESH_Algo::GetUsedHypothesis(SMESH_Mesh & aMesh, const bool ignoreAuxiliary) const { SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); + + std::list savedHyps; // don't delete the list if + savedHyps.swap( me->_usedHypList ); // it does not change (#16578) + me->_usedHypList.clear(); if ( const SMESH_HypoFilter* filter = GetCompatibleHypoFilter( ignoreAuxiliary )) { @@ -272,6 +274,9 @@ SMESH_Algo::GetUsedHypothesis(SMESH_Mesh & aMesh, if ( ignoreAuxiliary && _usedHypList.size() > 1 ) me->_usedHypList.clear(); //only one compatible hypothesis allowed } + if ( _usedHypList == savedHyps ) + savedHyps.swap( me->_usedHypList ); + return _usedHypList; } @@ -289,10 +294,17 @@ SMESH_Algo::GetAppliedHypothesis(SMESH_Mesh & aMesh, const bool ignoreAuxiliary) const { SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); + + std::list savedHyps; // don't delete the list if + savedHyps.swap( me->_appliedHypList ); // it does not change (#16578) + me->_appliedHypList.clear(); if ( const SMESH_HypoFilter* filter = GetCompatibleHypoFilter( ignoreAuxiliary )) aMesh.GetHypotheses( aShape, *filter, me->_appliedHypList, false ); + if ( _appliedHypList == savedHyps ) + savedHyps.swap( me->_appliedHypList ); + return _appliedHypList; } @@ -360,12 +372,9 @@ bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); while ( nIt->more() ) { - const SMDS_MeshNode* node = nIt->next(); - const SMDS_PositionPtr& pos = node->GetPosition(); - if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) + SMDS_EdgePositionPtr epos = nIt->next()->GetPosition(); + if ( !epos ) return false; - const SMDS_EdgePosition* epos = - static_cast(node->GetPosition()); if ( !paramSet.insert( epos->GetUParameter() ).second ) return false; // equal parameters } @@ -412,7 +421,7 @@ bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theM return false; SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge ); - if ( !eSubMesh || ( eSubMesh->NbElements()==0 && eSubMesh->NbNodes() == 0)) + if ( !eSubMesh || ( eSubMesh->NbElements() == 0 && eSubMesh->NbNodes() == 0)) return false; // edge is not meshed int nbNodes = 0; @@ -426,32 +435,30 @@ bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theM const SMDS_MeshNode* node = nIt->next(); if ( ignoreMediumNodes && SMESH_MesherHelper::IsMedium( node, typeToCheck )) continue; - const SMDS_PositionPtr& pos = node->GetPosition(); - if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) + SMDS_EdgePositionPtr epos = node->GetPosition(); + if ( ! epos ) return false; - const SMDS_EdgePosition* epos = - static_cast(node->GetPosition()); theNodes.insert( theNodes.end(), make_pair( epos->GetUParameter(), node )); - //MESSAGE("U " << epos->GetUParameter() << " ID " << node->GetID()); ++nbNodes; } } // add vertex nodes TopoDS_Vertex v1, v2; TopExp::Vertices(theEdge, v1, v2); - const SMDS_MeshNode* n1 = VertexNode( v1, (SMESHDS_Mesh*) theMesh ); - const SMDS_MeshNode* n2 = VertexNode( v2, (SMESHDS_Mesh*) theMesh ); - //MESSAGE("Vertices ID " << n1->GetID() << " " << n2->GetID()); + const SMDS_MeshNode* n1 = VertexNode( v1, eSubMesh, 0 ); + const SMDS_MeshNode* n2 = VertexNode( v2, eSubMesh, 0 ); + const SMDS_MeshNode* nEnd[2] = { nbNodes ? theNodes.begin()->second : 0, + nbNodes ? theNodes.rbegin()->second : 0 }; Standard_Real f, l; BRep_Tool::Range(theEdge, f, l); if ( v1.Orientation() != TopAbs_FORWARD ) std::swap( f, l ); - if ( n1 && ++nbNodes ) + if ( n1 && n1 != nEnd[0] && n1 != nEnd[1] && ++nbNodes ) theNodes.insert( make_pair( f, n1 )); - if ( n2 && ++nbNodes ) + if ( n2 && n2 != nEnd[0] && n2 != nEnd[1] && ++nbNodes ) theNodes.insert( make_pair( l, n2 )); - return theNodes.size() == nbNodes; + return (int)theNodes.size() == nbNodes; } //================================================================================ @@ -471,7 +478,7 @@ SMESH_Algo::GetCompatibleHypoFilter(const bool ignoreAuxiliary) const { SMESH_HypoFilter* filter = new SMESH_HypoFilter(); filter->Init( filter->HasName( _compatibleHypothesis[0] )); - for ( int i = 1; i < _compatibleHypothesis.size(); ++i ) + for ( size_t i = 1; i < _compatibleHypothesis.size(); ++i ) filter->Or( filter->HasName( _compatibleHypothesis[ i ] )); SMESH_HypoFilter* filterNoAux = new SMESH_HypoFilter( filter ); @@ -496,10 +503,11 @@ SMESH_Algo::GetCompatibleHypoFilter(const bool ignoreAuxiliary) const */ //================================================================================ -GeomAbs_Shape SMESH_Algo::Continuity(TopoDS_Edge E1, - TopoDS_Edge E2) +GeomAbs_Shape SMESH_Algo::Continuity(const TopoDS_Edge& theE1, + const TopoDS_Edge& theE2) { - //E1.Orientation(TopAbs_FORWARD), E2.Orientation(TopAbs_FORWARD); // avoid pb with internal edges + // avoid pb with internal edges + TopoDS_Edge E1 = theE1, E2 = theE2; if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL E1.Orientation( TopAbs_FORWARD ); if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL @@ -552,28 +560,35 @@ bool SMESH_Algo::IsStraight( const TopoDS_Edge & E, case GeomAbs_Hyperbola: case GeomAbs_Parabola: return false; - // case GeomAbs_BezierCurve: - // case GeomAbs_BSplineCurve: - // case GeomAbs_OtherCurve: + // case GeomAbs_BezierCurve: + // case GeomAbs_BSplineCurve: + // case GeomAbs_OtherCurve: default:; } - const double f = curve.FirstParameter(); - const double l = curve.LastParameter(); - const gp_Pnt pf = curve.Value( f ); - const gp_Pnt pl = curve.Value( l ); - const gp_Vec v1( pf, pl ); - const double v1Len = v1.Magnitude(); - if ( v1Len < std::numeric_limits< double >::min() ) + + // evaluate how far from a straight line connecting the curve ends + // stand internal points of the curve + double f = curve.FirstParameter(); + double l = curve.LastParameter(); + gp_Pnt pf = curve.Value( f ); + gp_Pnt pl = curve.Value( l ); + gp_Vec lineVec( pf, pl ); + double lineLen2 = lineVec.SquareMagnitude(); + if ( lineLen2 < std::numeric_limits< double >::min() ) return false; // E seems closed - const double tol = Min( 10 * curve.Tolerance(), v1Len * 1e-2 ); + + double edgeTol = 10 * curve.Tolerance(); + double lenTol2 = lineLen2 * 1e-4; + double tol2 = Min( edgeTol * edgeTol, lenTol2 ); + const double nbSamples = 7; for ( int i = 0; i < nbSamples; ++i ) { - const double r = ( i + 1 ) / nbSamples; - const gp_Pnt pi = curve.Value( f * r + l * ( 1 - r )); - const gp_Vec vi( pf, pi ); - const double h = 0.5 * v1.Crossed( vi ).Magnitude() / v1Len; - if ( h > tol ) + double r = ( i + 1 ) / nbSamples; + gp_Pnt pi = curve.Value( f * r + l * ( 1 - r )); + gp_Vec vi( pf, pi ); + double h2 = lineVec.Crossed( vi ).SquareMagnitude() / lineLen2; + if ( h2 > tol2 ) return false; } return true; @@ -585,8 +600,10 @@ bool SMESH_Algo::IsStraight( const TopoDS_Edge & E, */ //================================================================================ -bool SMESH_Algo::isDegenerated( const TopoDS_Edge & E ) +bool SMESH_Algo::isDegenerated( const TopoDS_Edge & E, const bool checkLength ) { + if ( checkLength ) + return EdgeLength( E ) == 0; double f,l; TopLoc_Location loc; Handle(Geom_Curve) C = BRep_Tool::Curve( E, loc, f,l ); @@ -614,6 +631,118 @@ const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, return 0; } +//======================================================================= +/*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param mesh - mesh + * \retval const SMDS_MeshNode* - found node or NULL + */ +//======================================================================= + +const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, + const SMESH_Mesh* mesh) +{ + const SMDS_MeshNode* node = VertexNode( V, mesh->GetMeshDS() ); + + if ( !node && mesh->HasModificationsToDiscard() ) + { + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( V, *mesh, TopAbs_EDGE ); + while ( const TopoDS_Shape* edge = edgeIt->next() ) + if ( SMESHDS_SubMesh* edgeSM = mesh->GetMeshDS()->MeshElements( *edge )) + if ( edgeSM->NbElements() > 0 ) + return VertexNode( V, edgeSM, mesh, /*checkV=*/false ); + } + return node; +} + +//======================================================================= +/*! + * \brief Return the node built on a vertex. + * A node moved to other geometry by MergeNodes() is also returned. + * \param V - the vertex + * \param edgeSM - sub-mesh of a meshed EDGE sharing the vertex + * \param checkV - if \c true, presence of a node on the vertex is checked + * \retval const SMDS_MeshNode* - found node or NULL + */ +//======================================================================= + +const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V, + const SMESHDS_SubMesh* edgeSM, + const SMESH_Mesh* mesh, + const bool checkV) +{ + const SMDS_MeshNode* node = checkV ? VertexNode( V, edgeSM->GetParent() ) : 0; + + if ( !node && edgeSM ) + { + // find nodes not shared by mesh segments + typedef set< const SMDS_MeshNode* > TNodeSet; + typedef map< const SMDS_MeshNode*, const SMDS_MeshNode* > TNodeMap; + TNodeMap notSharedNodes; + TNodeSet otherShapeNodes; + vector< const SMDS_MeshNode* > segNodes(3); + SMDS_ElemIteratorPtr segIt = edgeSM->GetElements(); + while ( segIt->more() ) + { + const SMDS_MeshElement* seg = segIt->next(); + if ( seg->GetType() != SMDSAbs_Edge ) + return node; + segNodes.assign( seg->begin_nodes(), seg->end_nodes() ); + for ( int i = 0; i < 2; ++i ) + { + const SMDS_MeshNode* n1 = segNodes[i]; + const SMDS_MeshNode* n2 = segNodes[1-i]; + pair it2new = notSharedNodes.insert( make_pair( n1, n2 )); + if ( !it2new.second ) // n encounters twice + notSharedNodes.erase( it2new.first ); + if ( n1->getshapeId() != edgeSM->GetID() ) + otherShapeNodes.insert( n1 ); + } + } + if ( otherShapeNodes.size() == 1 && notSharedNodes.empty() ) // a closed EDGE + return *otherShapeNodes.begin(); + + if ( notSharedNodes.size() == 2 ) // two end nodes found + { + SMESHDS_Mesh* meshDS = edgeSM->GetParent(); + const TopoDS_Shape& E = meshDS->IndexToShape( edgeSM->GetID() ); + if ( E.IsNull() || E.ShapeType() != TopAbs_EDGE ) + return node; + const SMDS_MeshNode* n1 = notSharedNodes.begin ()->first; + const SMDS_MeshNode* n2 = notSharedNodes.rbegin()->first; + TopoDS_Shape S1 = SMESH_MesherHelper::GetSubShapeByNode( n1, meshDS ); + if ( S1.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S1, E )) + return n2; + TopoDS_Shape S2 = SMESH_MesherHelper::GetSubShapeByNode( n2, meshDS ); + if ( S2.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S2, E )) + return n1; + if ( edgeSM->NbElements() <= 2 || !mesh ) // one-two segments + { + gp_Pnt pV = BRep_Tool::Pnt( V ); + double dist1 = pV.SquareDistance( SMESH_TNodeXYZ( n1 )); + double dist2 = pV.SquareDistance( SMESH_TNodeXYZ( n2 )); + return dist1 < dist2 ? n1 : n2; + } + if ( mesh ) + { + SMESH_MesherHelper helper( const_cast( *mesh )); + const SMDS_MeshNode* n1i = notSharedNodes.begin ()->second; + const SMDS_MeshNode* n2i = notSharedNodes.rbegin()->second; + const TopoDS_Edge& edge = TopoDS::Edge( E ); + bool posOK = true; + double pos1 = helper.GetNodeU( edge, n1i, n2i, &posOK ); + double pos2 = helper.GetNodeU( edge, n2i, n1i, &posOK ); + double posV = BRep_Tool::Parameter( V, edge ); + if ( Abs( pos1 - posV ) < Abs( pos2 - posV )) return n1; + else return n2; + } + } + } + return node; +} + //======================================================================= //function : GetMeshError //purpose : Finds topological errors of a sub-mesh @@ -636,7 +765,7 @@ SMESH_Algo::EMeshError SMESH_Algo::GetMeshError(SMESH_subMesh* subMesh) if ( !fIt->more() ) return MEr_EMPTY; - // We check that olny links on EDGEs encouter once, the rest links, twice + // We check that only links on EDGEs encounter once, the rest links, twice set< SMESH_TLink > links; while ( fIt->more() ) { @@ -737,6 +866,16 @@ bool SMESH_Algo::Compute(SMESH_Mesh & /*aMesh*/, SMESH_MesherHelper* /*aHelper*/ return error( COMPERR_BAD_INPUT_MESH, "Mesh built on shape expected"); } +//======================================================================= +//function : IsApplicableToShape +//purpose : Return true if the algorithm can mesh a given shape +//======================================================================= + +bool SMESH_Algo::IsApplicableToShape(const TopoDS_Shape & shape, bool toCheckAll) const +{ + return true; +} + //======================================================================= //function : CancelCompute //purpose : Sets _computeCanceled to true. It's usage depends on @@ -784,7 +923,12 @@ bool SMESH_Algo::error(SMESH_ComputeErrorPtr error) if ( error ) { _error = error->myName; _comment = error->myComment; - _badInputElements = error->myBadElements; + if ( error->HasBadElems() ) + { + SMESH_BadInputElements* badElems = static_cast( error.get() ); + _badInputElements = badElems->GetElements(); + _mesh = badElems->GetMesh(); + } return error->IsOK(); } return true; @@ -798,11 +942,15 @@ bool SMESH_Algo::error(SMESH_ComputeErrorPtr error) SMESH_ComputeErrorPtr SMESH_Algo::GetComputeError() const { - SMESH_ComputeErrorPtr err = SMESH_ComputeError::New( _error, _comment, this ); - // hope this method is called by only SMESH_subMesh after this->Compute() - err->myBadElements.splice( err->myBadElements.end(), - (list&) _badInputElements ); - return err; + if ( !_badInputElements.empty() && _mesh ) + { + SMESH_BadInputElements* err = new SMESH_BadInputElements( _mesh, _error, _comment, this ); + // hope this method is called by only SMESH_subMesh after this->Compute() + err->myBadElements.splice( err->myBadElements.end(), + (list&) _badInputElements ); + return SMESH_ComputeErrorPtr( err ); + } + return SMESH_ComputeError::New( _error, _comment, this ); } //================================================================================ @@ -820,6 +968,7 @@ void SMESH_Algo::InitComputeError() if ( (*elem)->GetID() < 1 ) delete *elem; _badInputElements.clear(); + _mesh = 0; _computeCanceled = false; _progressTic = 0; @@ -1113,7 +1262,7 @@ bool SMESH_2D_Algo::FixInternalNodes(const SMESH_ProxyMesh& mesh, gp_Pnt p = S->Value( uv.Coord(1), uv.Coord(2)); const SMDS_MeshNode* n = nodeRows[iRow][iCol]; meshDS->MoveNode( n, p.X(), p.Y(), p.Z() ); - if ( SMDS_FacePosition* pos = dynamic_cast< SMDS_FacePosition*>( n->GetPosition() )) + if ( SMDS_FacePositionPtr pos = n->GetPosition() ) pos->SetParameters( uv.Coord(1), uv.Coord(2) ); } }