// 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 // // 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. // // 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 // // File : StdMeshers_FaceSide.hxx // Created : Wed Jan 31 18:41:25 2007 // Author : Edward AGAPOV (eap) // Module : SMESH // #include "StdMeshers_FaceSide.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_MeshNode.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESHDS_SubMesh.hxx" #include "SMESH_Algo.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_ComputeError.hxx" #include "SMESH_Block.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utilities.h" //================================================================================ /*! * \brief Constructor of a side of one edge * \param theFace - the face * \param theEdge - the edge */ //================================================================================ StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, const TopoDS_Edge& theEdge, SMESH_Mesh* theMesh, const bool theIsForward, const bool theIgnoreMediumNodes) { list edges(1,theEdge); *this = StdMeshers_FaceSide( theFace, edges, theMesh, theIsForward, theIgnoreMediumNodes ); } //================================================================================ /*! * \brief Constructor of a side of several edges * \param theFace - the face * \param theEdge - the edge */ //================================================================================ StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, list& theEdges, SMESH_Mesh* theMesh, const bool theIsForward, const bool theIgnoreMediumNodes) { int nbEdges = theEdges.size(); myEdge.resize ( nbEdges ); myEdgeID.resize ( nbEdges ); myC2d.resize ( nbEdges ); myC3dAdaptor.resize( nbEdges ); myFirst.resize ( nbEdges ); myLast.resize ( nbEdges ); myNormPar.resize ( nbEdges ); myEdgeLength.resize( nbEdges ); myIsUniform.resize ( nbEdges, true ); myLength = 0; myNbPonits = myNbSegments = 0; myMesh = theMesh; myMissingVertexNodes = false; myIgnoreMediumNodes = theIgnoreMediumNodes; myDefaultPnt2d = gp_Pnt2d( 1e+100, 1e+100 ); if ( nbEdges == 0 ) return; SMESHDS_Mesh* meshDS = theMesh->GetMeshDS(); int nbDegen = 0; list::iterator edge = theEdges.begin(); TopoDS_Iterator vExp; for ( int index = 0; edge != theEdges.end(); ++index, ++edge ) { int i = theIsForward ? index : nbEdges-index-1; myEdgeLength[i] = SMESH_Algo::EdgeLength( *edge ); if ( myEdgeLength[i] < DBL_MIN ) nbDegen++; myLength += myEdgeLength[i]; myEdge[i] = *edge; myEdgeID[i] = meshDS->ShapeToIndex( *edge ); if ( !theIsForward ) myEdge[i].Reverse(); if ( theFace.IsNull() ) BRep_Tool::Range( *edge, myFirst[i], myLast[i] ); else myC2d[i] = BRep_Tool::CurveOnSurface( *edge, theFace, myFirst[i], myLast[i] ); if ( myEdge[i].Orientation() == TopAbs_REVERSED ) std::swap( myFirst[i], myLast[i] ); if ( SMESHDS_SubMesh* sm = meshDS->MeshElements( *edge )) { int nbN = sm->NbNodes(); if ( theIgnoreMediumNodes ) { SMDS_ElemIteratorPtr elemIt = sm->GetElements(); if ( elemIt->more() && elemIt->next()->IsQuadratic() ) nbN -= sm->NbElements(); } myNbPonits += nbN; myNbSegments += sm->NbElements(); } // TopExp::FirstVertex() and TopExp::LastVertex() return NULL from INTERNAL edge vExp.Initialize( *edge ); if ( vExp.Value().Orientation() == TopAbs_REVERSED ) vExp.Next(); if ( SMESH_Algo::VertexNode( TopoDS::Vertex( vExp.Value()), meshDS )) myNbPonits += 1; // for the first end else myMissingVertexNodes = true; // check if edge has non-uniform parametrization (issue 0020705) if ( !myC2d[i].IsNull() && myEdgeLength[i] > DBL_MIN) { Geom2dAdaptor_Curve A2dC( myC2d[i], std::min( myFirst[i], myLast[i] ), std::max( myFirst[i], myLast[i] )); double p2 = myFirst[i]+(myLast[i]-myFirst[i])/2., p4 = myFirst[i]+(myLast[i]-myFirst[i])/4.; double d2 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p2 ); double d4 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p4 ); //cout<<"len = "<MeshElements( myEdge[i] )) { vector< pair< double, const SMDS_MeshNode*> > u2nodeVec; u2nodeVec.reserve( sm->NbNodes() ); SMDS_NodeIteratorPtr nItr = sm->GetNodes(); double paramSize = myLast[i] - myFirst[i]; double r = myNormPar[i] - prevNormPar; helper.SetSubShape( myEdge[i] ); helper.ToFixNodeParameters( true ); if ( !myIsUniform[i] ) while ( nItr->more() ) { const SMDS_MeshNode* node = nItr->next(); if ( myIgnoreMediumNodes && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge )) continue; double u = helper.GetNodeU( myEdge[i], node, 0, ¶mOK ); double aLenU = GCPnts_AbscissaPoint::Length ( const_cast( myC3dAdaptor[i]), myFirst[i], u ); if ( myEdgeLength[i] < aLenU ) // nonregression test "3D_mesh_NETGEN/G6" { u2nodeVec.clear(); break; } double normPar = prevNormPar + r*aLenU/myEdgeLength[i]; u2nodeVec.push_back( make_pair( normPar, node )); } nItr = sm->GetNodes(); if ( u2nodeVec.empty() ) while ( nItr->more() ) { const SMDS_MeshNode* node = nItr->next(); if ( myIgnoreMediumNodes && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge )) continue; double u = helper.GetNodeU( myEdge[i], node, 0, ¶mOK ); // paramSize is signed so orientation is taken into account double normPar = prevNormPar + r * ( u - myFirst[i] ) / paramSize; u2nodeVec.push_back( make_pair( normPar, node )); } for ( size_t j = 0; j < u2nodeVec.size(); ++j ) u2node.insert( u2node.end(), u2nodeVec[j] ); } // Put 2nd vertex node for a last edge if ( i+1 == myEdge.size() ) { node = SMESH_Algo::VertexNode( VV[1], meshDS ); if ( !node ) { MESSAGE(" NO NODE on VERTEX" ); return myPoints; } u2node.insert( u2node.end(), make_pair( 1., node )); } } if ( u2node.size() != myNbPonits ) { MESSAGE("Wrong node parameters on edges, u2node.size():" <* points = const_cast*>( &myPoints ); points->resize( myNbPonits ); int EdgeIndex = 0; double prevNormPar = 0, paramSize = myNormPar[ EdgeIndex ]; map< double, const SMDS_MeshNode*>::iterator u_node = u2node.begin(); for (int i = 0 ; u_node != u2node.end(); ++u_node, ++i ) { UVPtStruct & uvPt = (*points)[i]; uvPt.node = u_node->second; uvPt.x = uvPt.y = uvPt.normParam = u_node->first; if ( isXConst ) uvPt.x = constValue; else uvPt.y = constValue; const SMDS_EdgePosition* epos = dynamic_cast(uvPt.node->GetPosition()); if (( myNormPar[ EdgeIndex ] < uvPt.normParam ) || ( epos && uvPt.node->getshapeId() != myEdgeID[ EdgeIndex ])) // for myMissingVertexNodes { prevNormPar = myNormPar[ EdgeIndex ]; ++EdgeIndex; #ifdef _DEBUG_ if ( EdgeIndex >= myEdge.size() ) { dump("DEBUG"); MESSAGE ( "WRONg EdgeIndex " << 1+EdgeIndex << " myNormPar.size()="<MeshElements( myEdge[i] )) { SMDS_NodeIteratorPtr nItr = sm->GetNodes(); double paramSize = myLast[i] - myFirst[i]; double r = myNormPar[i] - prevNormPar; helper.SetSubShape( myEdge[i] ); helper.ToFixNodeParameters( true ); while ( nItr->more() ) { const SMDS_MeshNode* node = nItr->next(); if ( myIgnoreMediumNodes && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge )) continue; double u = helper.GetNodeU( myEdge[i], node, 0, ¶mOK ); // paramSize is signed so orientation is taken into account double normPar = prevNormPar + r * ( u - myFirst[i] ) / paramSize; u2node.insert( u2node.end(), make_pair( normPar, node )); } } // Put 2nd vertex node for a last edge if ( i+1 == myEdge.size() ) { node = SMESH_Algo::VertexNode( VV[1], meshDS ); if ( !node ) { return resultNodes; } u2node.insert( u2node.end(), make_pair( 1., node )); } } // Fill the result vector if ( u2node.size() == myNbPonits ) { resultNodes.reserve( u2node.size() ); map< double, const SMDS_MeshNode*>::iterator u2n = u2node.begin(); for ( ; u2n != u2node.end(); ++u2n ) resultNodes.push_back( u2n->second ); } } else { resultNodes.resize( myPoints.size() ); for ( size_t i = 0; i < myPoints.size(); ++i ) resultNodes[i] = myPoints[i].node; } return resultNodes; } //================================================================================ /*! * \brief reverse order of vector elements * \param vec - vector to reverse */ //================================================================================ template void reverse(vector & vec) { for ( int f=0, r=vec.size()-1; f < r; ++f, --r ) std::swap( vec[f], vec[r] ); } //================================================================================ /*! * \brief Change orientation of side geometry */ //================================================================================ void StdMeshers_FaceSide::Reverse() { int nbEdges = myEdge.size(); for ( int i = nbEdges-1; i >= 0; --i ) { std::swap( myFirst[i], myLast[i] ); myEdge[i].Reverse(); if ( i > 0 ) // at the first loop 1. is overwritten myNormPar[i] = 1 - myNormPar[i-1]; } if ( nbEdges > 1 ) { reverse( myEdge ); reverse( myEdgeID ); reverse( myC2d ); reverse( myC3dAdaptor ); reverse( myFirst ); reverse( myLast ); reverse( myNormPar ); reverse( myEdgeLength ); reverse( myIsUniform ); } if ( nbEdges > 0 ) { myNormPar[nbEdges-1]=1.; myPoints.clear(); myFalsePoints.clear(); } } //================================================================================ /*! * \brief Show side features */ //================================================================================ void StdMeshers_FaceSide::dump(const char* msg) const { #ifdef _DEBUG_ if (msg) MESSAGE ( std::endl << msg ); MESSAGE_BEGIN ("NB EDGES: "<< myEdge.size() ); MESSAGE_ADD ( "nbPoints: "<()<() << " V2: " << TopExp::LastVertex( myEdge[i], 1).TShape().operator->() ); } MESSAGE_ADD ( "\tC2d: "); if (myC2d[i].IsNull()) { MESSAGE_ADD ( "NULL" ); } else { MESSAGE_ADD ( myC2d[i].operator->() ); } MESSAGE_ADD ( "\tF: "<Value2d( U ); } Standard_Real FirstParameter() const { return 0; } Standard_Real LastParameter() const { return 1; } }; Adaptor2d_Curve2d* StdMeshers_FaceSide::GetCurve2d() const { return new Adaptor2dCurve2d( this ); } //================================================================================ /*! * \brief Creates a fully functional Adaptor_Curve */ //================================================================================ BRepAdaptor_CompCurve* StdMeshers_FaceSide::GetCurve3d() const { if ( myEdge.empty() ) return 0; TopoDS_Wire aWire; BRep_Builder aBuilder; aBuilder.MakeWire(aWire); for ( int i=0; imyLast[i] ? -1. : 1.); GCPnts_AbscissaPoint AbPnt ( const_cast( myC3dAdaptor[i]), aLen3dU, myFirst[i] ); if( AbPnt.IsDone() ) { par = AbPnt.Parameter(); } } return myC2d[ i ]->Value(par); } return myDefaultPnt2d; } //================================================================================ /*! * \brief Return wires of a face as StdMeshers_FaceSide's */ //================================================================================ TSideVector StdMeshers_FaceSide::GetFaceWires(const TopoDS_Face& theFace, SMESH_Mesh & theMesh, const bool theIgnoreMediumNodes, TError & theError) { TopoDS_Vertex V1; list< TopoDS_Edge > edges, internalEdges; list< int > nbEdgesInWires; int nbWires = SMESH_Block::GetOrderedEdges (theFace, V1, edges, nbEdgesInWires); // split list of all edges into separate wires TSideVector wires( nbWires ); list< int >::iterator nbE = nbEdgesInWires.begin(); list< TopoDS_Edge >::iterator from = edges.begin(), to = from; for ( int iW = 0; iW < nbWires; ++iW, ++nbE ) { std::advance( to, *nbE ); if ( *nbE == 0 ) // Issue 0020676 { --nbWires; --iW; wires.resize( nbWires ); continue; } list< TopoDS_Edge > wireEdges( from, to ); // assure that there is a node on the first vertex // as StdMeshers_FaceSide::GetUVPtStruct() requires if ( wireEdges.front().Orientation() != TopAbs_INTERNAL ) // Issue 0020676 { while ( !SMESH_Algo::VertexNode( TopExp::FirstVertex( wireEdges.front(), true), theMesh.GetMeshDS())) { wireEdges.splice(wireEdges.end(), wireEdges, wireEdges.begin(), ++wireEdges.begin()); if ( from->IsSame( wireEdges.front() )) { theError = TError ( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"No nodes on vertices")); return TSideVector(0); } } } else if ( *nbE > 1 ) // Issue 0020676 (Face_pb_netgen.brep) - several internal edges in a wire { internalEdges.splice( internalEdges.end(), wireEdges, ++wireEdges.begin(), wireEdges.end()); } StdMeshers_FaceSide* wire = new StdMeshers_FaceSide( theFace, wireEdges, &theMesh, /*isForward=*/true, theIgnoreMediumNodes); wires[ iW ] = StdMeshers_FaceSidePtr( wire ); from = to; } while ( !internalEdges.empty() ) { StdMeshers_FaceSide* wire = new StdMeshers_FaceSide( theFace, internalEdges.back(), &theMesh, /*isForward=*/true, theIgnoreMediumNodes); wires.push_back( StdMeshers_FaceSidePtr( wire )); internalEdges.pop_back(); } return wires; } //================================================================================ /*! * \brief Return 1st vertex of the i-the edge */ //================================================================================ TopoDS_Vertex StdMeshers_FaceSide::FirstVertex(int i) const { TopoDS_Vertex v; if ( i < NbEdges() ) { v = myEdge[i].Orientation() <= TopAbs_REVERSED ? // FORWARD || REVERSED TopExp::FirstVertex( myEdge[i], 1 ) : TopoDS::Vertex( TopoDS_Iterator( myEdge[i] ).Value() ); } return v; } //================================================================================ /*! * \brief Return last vertex of the i-the edge */ //================================================================================ TopoDS_Vertex StdMeshers_FaceSide::LastVertex(int i) const { TopoDS_Vertex v; if ( i < NbEdges() ) { const TopoDS_Edge& edge = i<0 ? myEdge[ NbEdges() + i ] : myEdge[i]; if ( edge.Orientation() <= TopAbs_REVERSED ) // FORWARD || REVERSED v = TopExp::LastVertex( edge, 1 ); else for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() ) v = TopoDS::Vertex( vIt.Value() ); } return v; }