X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Projection_2D.cxx;h=f69c3a58d0d2aeec4fbc66ae5ae80954559790d5;hp=5e4586bed89df5e2216ee2f60c8e728b1f03a711;hb=fc0c585f17e07adb49d96dbb8d020545976d3e4d;hpb=079e65a9b152c9dec23fa91a346ac312b04eb145 diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx index 5e4586bed..f69c3a58d 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 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 @@ -56,9 +56,12 @@ #include #include #include +#include #include +#include #include #include +#include using namespace std; @@ -427,15 +430,44 @@ namespace { // get ordered src EDGEs TError err; srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err); - if ( err && !err->IsOK() ) + if ( err && !err->IsOK() || srcWires.empty() ) return err; + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + // make corresponding sequence of tgt EDGEs tgtWires.resize( srcWires.size() ); for ( size_t iW = 0; iW < srcWires.size(); ++iW ) { - list< TopoDS_Edge > tgtEdges; + // check ori + bool reverse = false; StdMeshers_FaceSidePtr srcWire = srcWires[iW]; + // for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) + // { + // if ( srcHelper.IsRealSeam( srcWire->EdgeID( iE ))) + // continue; + // TopoDS_Shape srcE = srcWire->Edge( iE ); + // TopoDS_Shape tgtE = shape2ShapeMap( srcE, /*isSrc=*/true); + // if ( shape2ShapeMap._assocType == TShapeShapeMap::PROPAGATION || + // shape2ShapeMap._assocType == TShapeShapeMap::PROPAGATION) + // { + // reverse = false; + // } + // else if ( tgtMesh == srcMesh ) + // { + // reverse = (( srcE.Orientation() == srcHelper.GetSubShapeOri( srcFace, srcE )) != + // ( tgtE.Orientation() == srcHelper.GetSubShapeOri( tgtFace, tgtE ))); + // } + // else + // { + // TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false ); + // reverse = ( srcE.Orientation() != srcEbis.Orientation() ); + // } + // break; + // } + + list< TopoDS_Edge > tgtEdges; TopTools_IndexedMapOfShape edgeMap; // to detect seam edges for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) { @@ -443,6 +475,7 @@ namespace { TopoDS_Edge tgtE = TopoDS::Edge( shape2ShapeMap( srcE, /*isSrc=*/true)); TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false ); if ( srcE.Orientation() != srcEbis.Orientation() ) + //if ( reverse ) tgtE.Reverse(); // reverse a seam edge encountered for the second time const int index = edgeMap.Add( tgtE ); @@ -486,15 +519,10 @@ namespace { } else { + const bool skipMediumNodes = true; map< double, const SMDS_MeshNode* > srcNodes, tgtNodes; - if (( ! SMESH_Algo::GetSortedNodesOnEdge( srcMeshDS, TopoDS::Edge( srcE ), - /*ignoreMediumNodes = */true, - srcNodes )) - || - ( ! SMESH_Algo::GetSortedNodesOnEdge( tgtMeshDS, TopoDS::Edge( tgtE ), - /*ignoreMediumNodes = */true, - tgtNodes )) - ) + if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMeshDS, srcE, skipMediumNodes, srcNodes) || + !SMESH_Algo::GetSortedNodesOnEdge( tgtMeshDS, tgtE, skipMediumNodes, tgtNodes )) return SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, "Invalid node parameters on edges"); @@ -504,10 +532,18 @@ namespace { if ( !tgtNodes.empty() ) { map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin(); - map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin(); - for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) - src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); - + if ( srcE.Orientation() == tgtE.Orientation() ) + { + map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin(); + for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) + src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); + } + else + { + map< double, const SMDS_MeshNode* >::reverse_iterator u_sn = srcNodes.rbegin(); + for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) + src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); + } is1DComputed = true; } } @@ -546,13 +582,24 @@ namespace { // transformation to get location of target nodes from source ones StdMeshers_ProjectionUtils::TrsfFinder3D trsf; + bool trsfIsOK = false; if ( tgtFace.IsPartner( srcFace )) { - gp_Trsf srcTrsf = srcFace.Location(); - gp_Trsf tgtTrsf = tgtFace.Location(); - trsf.Set( srcTrsf.Inverted() * tgtTrsf ); + gp_GTrsf srcTrsf = srcFace.Location().Transformation(); + gp_GTrsf tgtTrsf = tgtFace.Location().Transformation(); + gp_GTrsf t = srcTrsf.Inverted().Multiplied( tgtTrsf ); + trsf.Set( t ); + // check + gp_Pnt srcP = BRep_Tool::Pnt( srcWires[0]->FirstVertex() ); + gp_Pnt tgtP = BRep_Tool::Pnt( tgtWires[0]->FirstVertex() ); + trsfIsOK = ( tgtP.Distance( trsf.Transform( srcP )) < tol ); + if ( !trsfIsOK ) + { + trsf.Set( tgtTrsf.Inverted().Multiplied( srcTrsf )); + trsfIsOK = ( tgtP.Distance( trsf.Transform( srcP )) < tol ); + } } - else + if ( !trsfIsOK ) { // Try to find the 3D transformation @@ -560,6 +607,7 @@ namespace { vector< gp_XYZ > srcPnts, tgtPnts; srcPnts.reserve( totNbSeg ); tgtPnts.reserve( totNbSeg ); + gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 ); for ( size_t iW = 0; iW < srcWires.size(); ++iW ) { const double minSegLen = srcWires[iW]->Length() / totNbSeg; @@ -576,6 +624,8 @@ namespace { tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() ); srcU += srcDu; tgtU += tgtDu; + srcBC += srcPnts.back(); + tgtBC += tgtPnts.back(); } } } @@ -584,10 +634,11 @@ namespace { // check trsf - bool trsfIsOK = true; const int nbTestPnt = 20; const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); // check boundary + gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol ); for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) { gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] ); @@ -598,8 +649,8 @@ namespace { { BRepAdaptor_Surface srcSurf( srcFace ); gp_Pnt srcP = - srcSurf.Value( 0.5 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), - 0.5 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); + srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), + 0.123 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); gp_Pnt tgtTrsfP = trsf.Transform( srcP ); TopLoc_Location loc; GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( tgtFace, loc, 0.1*tol ); @@ -698,7 +749,12 @@ namespace { if ( !tgtFace.IsPartner( srcFace ) ) { + SMESH_MesherHelper edgeHelper( *tgtMesh ); + edgeHelper.ToFixNodeParameters( true ); + helper.ToFixNodeParameters( true ); + int nbOkPos = 0; + bool toCheck = true; const double tol2d = 1e-12; srcN_tgtN = src2tgtNodes.begin(); for ( ; srcN_tgtN != src2tgtNodes.end(); ++srcN_tgtN ) @@ -708,22 +764,20 @@ namespace { { case SMDS_TOP_FACE: { + if ( nbOkPos > 10 ) break; gp_XY uv = helper.GetNodeUV( tgtFace, n ), uvBis = uv; if (( helper.CheckNodeUV( tgtFace, n, uv, tol )) && - (( uv - uvBis ).SquareModulus() < tol2d ) && - ( ++nbOkPos > 10 )) - return true; + (( uv - uvBis ).SquareModulus() < tol2d )) + ++nbOkPos; else - nbOkPos = 0; + nbOkPos = -((int) src2tgtNodes.size() ); break; } case SMDS_TOP_EDGE: { const TopoDS_Edge & tgtE = TopoDS::Edge( tgtMeshDS->IndexToShape( n->getshapeId() )); - double u = helper.GetNodeU( tgtE, n ), uBis = u; - if (( !helper.CheckNodeU( tgtE, n, u, tol )) || - (( u - uBis ) < tol2d )) - nbOkPos = 0; + edgeHelper.SetSubShape( tgtE ); + edgeHelper.GetNodeU( tgtE, n, 0, &toCheck ); break; } default:; @@ -877,10 +931,9 @@ namespace { case SMDS_TOP_EDGE: { TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() ); TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true )); - tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge )); - double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode ); + double U = Precision::Infinite(); helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion()); - n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U ))); + tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U ); break; } case SMDS_TOP_VERTEX: { @@ -900,91 +953,191 @@ namespace { case 3: helper.AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break; case 4: helper.AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break; } - } - return true; + } // loop on all mesh faces on srcFace - } // bool projectBy2DSimilarity(...) + return true; + } //================================================================================ /*! - * \brief Fix bad faces by smoothing + * \brief Preform projection in case of quadrilateral faces */ //================================================================================ - void fixDistortedFaces( SMESH_MesherHelper& helper, - TSideVector& ) + bool projectQuads(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) { - // Detect bad faces + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); + SMESHDS_Mesh * tgtMeshDS = tgtMesh->GetMeshDS(); + SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS(); + + if ( srcWires[0]->NbEdges() != 4 ) + return false; + if ( !is1DComputed ) + return false; + for ( int iE = 0; iE < 4; ++iE ) + { + SMESHDS_SubMesh* sm = srcMeshDS->MeshElements( srcWires[0]->Edge( iE )); + if ( !sm ) return false; + if ( sm->NbNodes() + sm->NbElements() == 0 ) return false; + } + if ( BRepAdaptor_Surface( tgtFace ).GetType() != GeomAbs_Plane ) + return false; + // if ( BRepAdaptor_Surface( tgtFace ).GetType() == GeomAbs_Plane && + // BRepAdaptor_Surface( srcFace ).GetType() == GeomAbs_Plane ) + // return false; // too easy - bool haveBadFaces = false; + // load EDGEs to SMESH_Block - const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() ); - SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F ); - if ( !smDS || smDS->NbElements() == 0 ) return; + SMESH_Block block; + TopTools_IndexedMapOfOrientedShape blockSubShapes; + { + const TopoDS_Solid& box = srcMesh->PseudoShape(); + TopoDS_Shell shell = TopoDS::Shell( TopExp_Explorer( box, TopAbs_SHELL ).Current() ); + TopoDS_Vertex v; + block.LoadBlockShapes( shell, v, v, blockSubShapes ); // fill all since operator[] is missing + } + const SMESH_Block::TShapeID srcFaceBID = SMESH_Block::ID_Fxy0; + const SMESH_Block::TShapeID tgtFaceBID = SMESH_Block::ID_Fxy1; + vector< int > edgeBID; + block.GetFaceEdgesIDs( srcFaceBID, edgeBID ); // u0, u1, 0v, 1v + blockSubShapes.Substitute( edgeBID[0], srcWires[0]->Edge(0) ); + blockSubShapes.Substitute( edgeBID[1], srcWires[0]->Edge(2) ); + blockSubShapes.Substitute( edgeBID[2], srcWires[0]->Edge(3) ); + blockSubShapes.Substitute( edgeBID[3], srcWires[0]->Edge(1) ); + block.GetFaceEdgesIDs( tgtFaceBID, edgeBID ); // u0, u1, 0v, 1v + blockSubShapes.Substitute( edgeBID[0], tgtWires[0]->Edge(0) ); + blockSubShapes.Substitute( edgeBID[1], tgtWires[0]->Edge(2) ); + blockSubShapes.Substitute( edgeBID[2], tgtWires[0]->Edge(3) ); + blockSubShapes.Substitute( edgeBID[3], tgtWires[0]->Edge(1) ); + block.LoadFace( srcFace, srcFaceBID, blockSubShapes ); + block.LoadFace( tgtFace, tgtFaceBID, blockSubShapes ); + + // remember connectivity of new faces in terms of ( node-or-XY ) + + typedef std::pair< const SMDS_MeshNode*, gp_XYZ > TNodeOrXY; // node-or-XY + typedef std::vector< TNodeOrXY* > TFaceConn; // face connectivity + std::vector< TFaceConn > newFacesVec; // connectivity of all faces + std::map< const SMDS_MeshNode*, TNodeOrXY > srcNode2tgtNXY; // src node -> node-or-XY + + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; + std::map< const SMDS_MeshNode*, TNodeOrXY >::iterator srcN_tgtNXY; + std::pair< std::map< const SMDS_MeshNode*, TNodeOrXY >::iterator, bool > n2n_isNew; + TNodeOrXY nullNXY( (SMDS_MeshNode*)NULL, gp_XYZ(0,0,0) ); - SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); - double prevArea2D = 0; - vector< const SMDS_MeshNode* > nodes; - vector< gp_XY > uv; - while ( faceIt->more() && !haveBadFaces ) + SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace ); + newFacesVec.resize( srcSubDS->NbElements() ); + int iFaceSrc = 0; + + SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements(); + while ( elemIt->more() ) // loop on all mesh faces on srcFace { - const SMDS_MeshElement* face = faceIt->next(); + const SMDS_MeshElement* elem = elemIt->next(); + TFaceConn& tgtNodes = newFacesVec[ iFaceSrc++ ]; - // get nodes - nodes.resize( face->NbCornerNodes() ); - SMDS_MeshElement::iterator n = face->begin_nodes(); - for ( size_t i = 0; i < nodes.size(); ++n, ++i ) - nodes[ i ] = *n; + const int nbN = elem->NbCornerNodes(); + tgtNodes.resize( nbN ); + for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element + { + const SMDS_MeshNode* srcNode = elem->GetNode(i); + n2n_isNew = srcNode2tgtNXY.insert( make_pair( srcNode, nullNXY )); + TNodeOrXY & tgtNodeOrXY = n2n_isNew.first->second; + if ( n2n_isNew.second ) // new src node encounters + { + srcN_tgtN = src2tgtNodes.find( srcNode ); + if ( srcN_tgtN != src2tgtNodes.end() ) + { + tgtNodeOrXY.first = srcN_tgtN->second; // tgt node exists + } + else + { + // find XY of src node withing the quadrilateral srcFace + if ( !block.ComputeParameters( SMESH_TNodeXYZ( srcNode ), + tgtNodeOrXY.second, srcFaceBID )) + return false; + } + } + tgtNodes[ i ] = & tgtNodeOrXY; + } + } + + // as all XY are computed, create tgt nodes and faces + + SMESH_MesherHelper helper( *tgtMesh ); + helper.SetSubShape( tgtFace ); + if ( is1DComputed ) + helper.IsQuadraticSubMesh( tgtFace ); + else + helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() ); + helper.SetElementsOnShape( true ); + Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace ); - // avoid elems on degenarate shapes as UV on them can be wrong - if ( helper.HasDegeneratedEdges() ) + SMESH_MesherHelper srcHelper( *srcMesh ); + srcHelper.SetSubShape( srcFace ); + + vector< const SMDS_MeshNode* > tgtNodes; + gp_XY uv; + + for ( size_t iFaceTgt = 0; iFaceTgt < newFacesVec.size(); ++iFaceTgt ) + { + TFaceConn& tgtConn = newFacesVec[ iFaceTgt ]; + tgtNodes.resize( tgtConn.size() ); + for ( size_t iN = 0; iN < tgtConn.size(); ++iN ) { - bool isOnDegen = false; - for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i ) - isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() ); - if ( isOnDegen ) - continue; + const SMDS_MeshNode* & tgtN = tgtConn[ iN ]->first; + if ( !tgtN ) // create a node + { + if ( !block.FaceUV( tgtFaceBID, tgtConn[iN]->second, uv )) + return false; + gp_Pnt p = tgtSurface->Value( uv.X(), uv.Y() ); + tgtN = helper.AddNode( p.X(), p.Y(), p.Z(), uv.X(), uv.Y() ); + } + tgtNodes[ tgtNodes.size() - iN - 1] = tgtN; // reversed orientation } - // prepare to getting UVs - const SMDS_MeshNode* inFaceNode = 0; - if ( helper.HasSeam() ) - for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i ) - if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() )) - inFaceNode = nodes[ i ]; - - // get UVs - uv.resize( nodes.size() ); - for ( size_t i = 0; i < nodes.size(); ++i ) - uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode ); - - // compare orientation of triangles - for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT ) + switch ( tgtNodes.size() ) { - gp_XY v1 = uv[ iT+1 ] - uv[ 0 ]; - gp_XY v2 = uv[ iT+2 ] - uv[ 0 ]; - double area2D = v2 ^ v1; - if (( haveBadFaces = ( area2D * prevArea2D < 0 ))) - break; - prevArea2D = area2D; + case 3: helper.AddFace(tgtNodes[0], tgtNodes[1], tgtNodes[2]); break; + case 4: helper.AddFace(tgtNodes[0], tgtNodes[1], tgtNodes[2], tgtNodes[3]); break; + default: + if ( tgtNodes.size() > 4 ) + helper.AddPolygonalFace( tgtNodes ); } } + return true; - // Fix faces + } // bool projectQuads(...) - if ( haveBadFaces ) + //================================================================================ + /*! + * \brief Fix bad faces by smoothing + */ + //================================================================================ + + bool fixDistortedFaces( SMESH_MesherHelper& helper, + TSideVector& tgtWires ) + { + SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() ); + + if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false )) { SMESH_MeshEditor editor( helper.GetMesh() ); + SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS(); + const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() ); TIDSortedElemSet faces; + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); for ( faceIt = smDS->GetElements(); faceIt->more(); ) faces.insert( faces.end(), faceIt->next() ); // choose smoothing algo //SMESH_MeshEditor:: SmoothMethod algo = SMESH_MeshEditor::CENTROIDAL; bool isConcaveBoundary = false; - TError err; - TSideVector tgtWires = - StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(),/*skipMediumNodes=*/0, err); for ( size_t iW = 0; iW < tgtWires.size() && !isConcaveBoundary; ++iW ) { TopoDS_Edge prevEdge = tgtWires[iW]->Edge( tgtWires[iW]->NbEdges() - 1 ); @@ -1009,7 +1162,12 @@ namespace { set fixedNodes; editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + helper.ToFixNodeParameters( true ); + + return !helper.IsDistorted2D( faceSM, /*checkUV=*/true ); } + return true; } } // namespace @@ -1034,6 +1192,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& srcMesh = tgtMesh; SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + SMESH_MesherHelper helper( theMesh ); // --------------------------- // Make sub-shapes association @@ -1050,8 +1209,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& { if ( srcShape.ShapeType() == TopAbs_FACE ) { - int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); - int nbE2 = SMESH_MesherHelper::Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = helper.Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true ); if ( nbE1 != nbE2 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Different number of edges in source and target faces: ") @@ -1061,6 +1220,23 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD)); + // orient faces + // if ( srcMesh == tgtMesh ) + // { + // TopoDS_Shape solid = + // helper.GetCommonAncestor( srcFace, tgtFace, *tgtMesh, TopAbs_SOLID ); + // if ( !solid.IsNull() ) + // { + // srcFace.Orientation( helper.GetSubShapeOri( solid, srcFace )); + // tgtFace.Orientation( helper.GetSubShapeOri( solid, tgtFace )); + // } + // else if ( helper.NbAncestors( srcFace, *tgtMesh, TopAbs_SOLID ) == 1 && + // helper.NbAncestors( tgtFace, *tgtMesh, TopAbs_SOLID ) == 1 ) + // { + // srcFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), srcFace )); + // tgtFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), tgtFace )); + // } + // } // ---------------------------------------------- // Assure that mesh on a source Face is computed // ---------------------------------------------- @@ -1092,25 +1268,33 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( err && !err->IsOK() ) return error( err ); - bool done = false; + bool projDone = false; - if ( !done ) + if ( !projDone ) { // try to project from the same face with different location - done = projectPartner( tgtFace, srcFace, tgtWires, srcWires, - shape2ShapeMap, _src2tgtNodes, is1DComputed ); + projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed ); } - if ( !done ) + if ( !projDone ) { // projection in case if the faces are similar in 2D space - done = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, - shape2ShapeMap, _src2tgtNodes, is1DComputed); + projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed); + } + if ( !projDone ) + { + // projection in case of quadrilateral faces + // projDone = projectQuads( tgtFace, srcFace, tgtWires, srcWires, + // shape2ShapeMap, _src2tgtNodes, is1DComputed); } - SMESH_MesherHelper helper( theMesh ); helper.SetSubShape( tgtFace ); - if ( !done ) + // it will remove mesh built on edges and vertices in failure case + MeshCleaner cleaner( tgtSubMesh ); + + if ( !projDone ) { _src2tgtNodes.clear(); // -------------------- @@ -1120,20 +1304,22 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Check if node projection to a face is needed Bnd_B2d uvBox; SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements(); - int nbFaceNodes = 0; - for ( ; nbFaceNodes < 3 && faceIt->more(); ) { + set< const SMDS_MeshNode* > faceNodes; + for ( ; faceNodes.size() < 3 && faceIt->more(); ) { const SMDS_MeshElement* face = faceIt->next(); SMDS_ElemIteratorPtr nodeIt = face->nodesIterator(); while ( nodeIt->more() ) { const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { - nbFaceNodes++; + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && + faceNodes.insert( node ).second ) uvBox.Add( helper.GetNodeUV( srcFace, node )); - } } } - const bool toProjectNodes = - ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN )); + bool toProjectNodes = false; + if ( faceNodes.size() == 1 ) + toProjectNodes = ( uvBox.IsVoid() || uvBox.CornerMin().IsEqual( gp_XY(0,0), 1e-12 )); + else if ( faceNodes.size() > 1 ) + toProjectNodes = ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ); // Find the corresponding source and target vertex // and flag needed to call mapper.Apply() @@ -1141,13 +1327,10 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& TopoDS_Vertex srcV1, tgtV1; bool reverse = false; - if ( _sourceHypo->HasVertexAssociation() ) { - srcV1 = _sourceHypo->GetSourceVertex(1); - tgtV1 = _sourceHypo->GetTargetVertex(1); - } else { - srcV1 = TopoDS::Vertex( TopExp_Explorer( srcFace, TopAbs_VERTEX ).Current() ); - tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); - } + TopExp_Explorer vSrcExp( srcFace, TopAbs_VERTEX ); + srcV1 = TopoDS::Vertex( vSrcExp.Current() ); + tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); + list< TopoDS_Edge > tgtEdges, srcEdges; list< int > nbEdgesInWires; SMESH_Block::GetOrderedEdges( tgtFace, tgtEdges, nbEdgesInWires, tgtV1 ); @@ -1159,7 +1342,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 ); reverse = ( ! srcE1.IsSame( srcE1bis )); if ( reverse && - _sourceHypo->HasVertexAssociation() && + //_sourceHypo->HasVertexAssociation() && nbEdgesInWires.front() > 2 && helper.IsRealSeam( tgtEdges.front() )) { @@ -1168,11 +1351,66 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // we can't use only theReverse flag to correctly associate source // and target faces in the mapper. Thus we select srcV1 so that // GetOrderedEdges() to return EDGEs in a needed order - list< TopoDS_Edge >::iterator edge = srcEdges.begin(); - for ( ; edge != srcEdges.end(); ++edge ) { - if ( srcE1bis.IsSame( *edge )) { - srcV1 = helper.IthVertex( 0, *edge ); - break; + TopoDS_Face tgtFaceBis = tgtFace; + TopTools_MapOfShape checkedVMap( tgtEdges.size() ); + checkedVMap.Add ( srcV1 ); + for ( vSrcExp.Next(); vSrcExp.More(); ) + { + tgtFaceBis.Reverse(); + tgtEdges.clear(); + SMESH_Block::GetOrderedEdges( tgtFaceBis, tgtEdges, nbEdgesInWires, tgtV1 ); + bool ok = true; + list< TopoDS_Edge >::iterator edgeS = srcEdges.begin(), edgeT = tgtEdges.begin(); + for ( ; edgeS != srcEdges.end() && ok ; ++edgeS, ++edgeT ) + ok = edgeT->IsSame( shape2ShapeMap( *edgeS, /*isSrc=*/true )); + if ( ok ) + break; // FOUND! + + reverse = !reverse; + if ( reverse ) + { + vSrcExp.Next(); + while ( vSrcExp.More() && !checkedVMap.Add( vSrcExp.Current() )) + vSrcExp.Next(); + } + else + { + srcV1 = TopoDS::Vertex( vSrcExp.Current() ); + tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); + srcEdges.clear(); + SMESH_Block::GetOrderedEdges( srcFace, srcEdges, nbEdgesInWires, srcV1 ); + } + } + } + // for the case: project to a closed face from a non-closed face w/o vertex assoc; + // avoid projecting to a seam from two EDGEs with different nb nodes on them + // ( test mesh_Projection_2D_01/B1 ) + if ( !_sourceHypo->HasVertexAssociation() && + nbEdgesInWires.front() > 2 && + helper.IsRealSeam( tgtEdges.front() )) + { + TopoDS_Shape srcEdge1 = shape2ShapeMap( tgtEdges.front() ); + list< TopoDS_Edge >::iterator srcEdge2 = + std::find( srcEdges.begin(), srcEdges.end(), srcEdge1); + list< TopoDS_Edge >::iterator srcEdge3 = + std::find( srcEdges.begin(), srcEdges.end(), srcEdge1.Reversed()); + if ( srcEdge2 == srcEdges.end() || srcEdge3 == srcEdges.end() ) // srcEdge1 is not a seam + { + // find srcEdge2 which also will be projected to tgtEdges.front() + for ( srcEdge2 = srcEdges.begin(); srcEdge2 != srcEdges.end(); ++srcEdge2 ) + if ( !srcEdge1.IsSame( *srcEdge2 ) && + tgtEdges.front().IsSame( shape2ShapeMap( *srcEdge2, /*isSrc=*/true ))) + break; + // compare nb nodes on srcEdge1 and srcEdge2 + if ( srcEdge2 != srcEdges.end() ) + { + int nbN1 = 0, nbN2 = 0; + if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( srcEdge1 )) + nbN1 = sm->NbNodes(); + if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( *srcEdge2 )) + nbN2 = sm->NbNodes(); + if ( nbN1 != nbN2 ) + srcV1 = helper.IthVertex( 1, srcEdges.front() ); } } } @@ -1200,8 +1438,11 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Compute mesh on a target face mapper.Apply( tgtFace, tgtV1, reverse ); - if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) { + // std::ofstream file("/tmp/Pattern.smp" ); + // mapper.Save( file ); return error("Can't apply source mesh pattern to the face"); + } // Create the mesh @@ -1210,10 +1451,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) return error("Can't make mesh by source mesh pattern"); - // it will remove mesh built by pattern mapper on edges and vertices - // in failure case - MeshCleaner cleaner( tgtSubMesh ); - // ------------------------------------------------------------------------- // mapper doesn't take care of nodes already existing on edges and vertices, // so we must merge nodes created by it with existing ones @@ -1323,8 +1560,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& u2nodesOnSeam.size() > 0 && seam.ShapeType() == TopAbs_EDGE ) { - int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); - int nbE2 = SMESH_MesherHelper::Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = helper.Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true ); if ( nbE1 != nbE2 ) // 2 EDGEs are mapped to a seam EDGE { // find the 2 EDGEs of srcFace @@ -1373,14 +1610,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() ) return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces"); - - // ---------------------------------------------------------------- - // The mapper can create distorted faces by placing nodes out of the FACE - // boundary -- fix bad faces by smoothing - // ---------------------------------------------------------------- - - fixDistortedFaces( helper, tgtWires ); - // ---------------------------------------------------------------- // The mapper can't create quadratic elements, so convert if needed // ---------------------------------------------------------------- @@ -1399,11 +1628,18 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false); } - cleaner.Release(); // not to remove mesh - } // end of projection using Pattern mapping + if ( !projDone || is1DComputed ) + // ---------------------------------------------------------------- + // The mapper can create distorted faces by placing nodes out of the FACE + // boundary, also bad face can be created if EDGEs already discretized + // --> fix bad faces by smoothing + // ---------------------------------------------------------------- + if ( !fixDistortedFaces( helper, tgtWires )) + return error("Invalid mesh generated"); + // --------------------------- // Check elements orientation // --------------------------- @@ -1449,6 +1685,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } } + cleaner.Release(); // not to remove mesh + return true; }