X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_ProjectionUtils.cxx;h=bca7292ffaed8db11038a0842c70e8762e8d209b;hp=e5ab88a1ecc8c024ef76ab3f972d64b8982d09cc;hb=096485adbe5e66ace1182bf6c49dc6853f437d9c;hpb=22660447f9a0ebd2c8b3b854213391dd44ebdc08 diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index e5ab88a1e..bca7292ff 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 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 @@ -27,31 +27,34 @@ // #include "StdMeshers_ProjectionUtils.hxx" -#include "StdMeshers_ProjectionSource1D.hxx" -#include "StdMeshers_ProjectionSource2D.hxx" -#include "StdMeshers_ProjectionSource3D.hxx" - #include "SMDS_EdgePosition.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMESHDS_Mesh.hxx" #include "SMESH_Algo.hxx" #include "SMESH_Block.hxx" #include "SMESH_Gen.hxx" #include "SMESH_HypoFilter.hxx" #include "SMESH_Hypothesis.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_MeshAlgos.hxx" +#include "StdMeshers_ProjectionSource1D.hxx" +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionSource3D.hxx" #include "utilities.h" #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -78,23 +81,9 @@ using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } #define CONT_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); continue; } #define SHOW_SHAPE(v,msg) \ -// { \ -// if ( (v).IsNull() ) cout << msg << " NULL SHAPE" << endl; \ -// else if ((v).ShapeType() == TopAbs_VERTEX) {\ -// gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( (v) ));\ -// cout<::const_iterator e = l.begin();\ -// for ( int i = 0; e != l.end(); ++e, ++i ) {\ -// cout << i << "V (" << TopExp::FirstVertex( *e, true ).TShape().operator->() << ") "\ -// << i << "E (" << e->TShape().operator->() << "); "; }\ -// cout << endl;\ -// } + // { show_list((msg),(l)); } namespace HERE = StdMeshers_ProjectionUtils; @@ -107,7 +96,24 @@ namespace { return max(theMeshDS[0]->ShapeToIndex(S), theMeshDS[1]->ShapeToIndex(S) ); return long(S.TShape().operator->()); } - + void show_shape( TopoDS_Shape v, const char* msg ) // debug + { + if ( v.IsNull() ) cout << msg << " NULL SHAPE" << endl; + else if (v.ShapeType() == TopAbs_VERTEX) { + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( v )); + cout<& l ) // debug + { + cout << msg << " "; + list< TopoDS_Edge >::const_iterator e = l.begin(); + for ( int i = 0; e != l.end(); ++e, ++i ) { + cout << i << "V (" << TopExp::FirstVertex( *e, true ).TShape().operator->() << ") " + << i << "E (" << e->TShape().operator->() << "); "; } + cout << endl; + } //================================================================================ /*! * \brief Write shape for debug purposes @@ -120,6 +126,10 @@ namespace { const char* type[] ={"COMPOUND","COMPSOLID","SOLID","SHELL","FACE","WIRE","EDGE","VERTEX"}; BRepTools::Write( shape, SMESH_Comment("/tmp/") << type[shape.ShapeType()] << "_" << shape.TShape().operator->() << ".brep"); + if ( !theMeshDS[0] ) { + show_shape( TopoDS_Shape(), "avoid warning: show_shape() defined but not used"); + show_list( "avoid warning: show_list() defined but not used", list< TopoDS_Edge >() ); + } #endif return false; } @@ -233,6 +243,7 @@ namespace { v2 = SMESH_MesherHelper::IthVertex( 0, *eIt2 ); HERE::InsertAssociation( v1, v2, theMap ); } + theMap.SetAssocType( HERE::TShapeShapeMap::FEW_EF ); return true; } return false; @@ -388,6 +399,7 @@ namespace { } } } + theMap.SetAssocType( HERE::TShapeShapeMap::PROPAGATION ); return true; } @@ -404,9 +416,8 @@ namespace { const gp_Pnt2d& uv, const double& tol2d ) { - TopoDS_Vertex VV[2]; - TopExp::Vertices( edge, VV[0], VV[1], true); - gp_Pnt2d v1UV = BRep_Tool::Parameters( VV[vIndex], face); + TopoDS_Vertex V = SMESH_MesherHelper::IthVertex( vIndex, edge, /*CumOri=*/true ); + gp_Pnt2d v1UV = BRep_Tool::Parameters( V, face); double dist2d = v1UV.Distance( uv ); return dist2d < tol2d; } @@ -432,23 +443,36 @@ namespace { return true; } } + SMESH_MesherHelper helper( mesh ); + helper.SetSubShape( shape ); + TopExp_Explorer expF( shape, TopAbs_FACE ), expE; if ( expF.More() ) { for ( ; expF.More(); expF.Next() ) { TopoDS_Shape wire = StdMeshers_ProjectionUtils::OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); for ( expE.Init( wire, TopAbs_EDGE ); expE.More(); expE.Next() ) - if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( expE.Current() ))) - allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + if ( ! helper.IsClosedEdge( TopoDS::Edge( expE.Current() ))) + { + if ( helper.IsSeamShape( expE.Current() )) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + else + allBndEdges.push_front( TopoDS::Edge( expE.Current() )); + } } } else if ( shape.ShapeType() != TopAbs_EDGE) { // no faces for ( expE.Init( shape, TopAbs_EDGE ); expE.More(); expE.Next() ) - if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( expE.Current() ))) - allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + if ( ! helper.IsClosedEdge( TopoDS::Edge( expE.Current() ))) + { + if ( helper.IsSeamShape( expE.Current() )) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + else + allBndEdges.push_front( TopoDS::Edge( expE.Current() )); + } } else if ( shape.ShapeType() == TopAbs_EDGE ) { - if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( shape ))) + if ( ! helper.IsClosedEdge( TopoDS::Edge( shape ))) allBndEdges.push_back( TopoDS::Edge( shape )); } return !allBndEdges.empty(); @@ -477,9 +501,9 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the { // Structure of this long function is following // 1) Group -> Group projection: theShape1 is a group member, - // theShape2 is another group. We find a group theShape1 is in and recall self. + // theShape2 is another group. We find the group theShape1 is in and recall self. // 2) Accosiate same shapes with different location (partners). - // 3) If vertex association is given, perform accosiation according to shape type: + // 3) If vertex association is given, perform association according to shape type: // switch ( ShapeType ) { // case TopAbs_EDGE: // case ...: @@ -499,7 +523,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ================================================================================= // 1) Is it the case of associating a group member -> another group? (PAL16202, 16203) // ================================================================================= - if ( theShape1.ShapeType() != theShape2.ShapeType() ) { + if ( theShape1.ShapeType() != theShape2.ShapeType() ) + { TopoDS_Shape group1, group2; if ( theShape1.ShapeType() == TopAbs_COMPOUND ) { group1 = theShape1; @@ -538,6 +563,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the for ( ; s1It.More(); s1It.Next(), s2It.Next() ) shapesQueue.push_back( make_pair( s1It.Value(), s2It.Value() )); } + theMap.SetAssocType( TShapeShapeMap::PARTNER ); return true; } @@ -546,6 +572,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the //====================================================================== // 3) HAS initial vertex association //====================================================================== + bool isVCloseness = ( theMap._assocType == TShapeShapeMap::CLOSE_VERTEX ); + theMap.SetAssocType( TShapeShapeMap::INIT_VERTEX ); switch ( theShape1.ShapeType() ) { // ---------------------------------------------------------------------- case TopAbs_EDGE: { // TopAbs_EDGE @@ -594,7 +622,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } } list< TopoDS_Edge > edges1, edges2; - int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2, isVCloseness ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); fixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 ); @@ -698,8 +726,6 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the F2 = FF2[ 1 ]; } - TopTools_MapOfShape boundEdges; - // association of face sub-shapes and neighbour faces list< pair < TopoDS_Face, TopoDS_Edge > > FE1, FE2; list< pair < TopoDS_Face, TopoDS_Edge > >::iterator fe1, fe2; @@ -715,11 +741,11 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); list< TopoDS_Edge > edges1, edges2; - int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2, isVCloseness ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); InsertAssociation( face1, face2, theMap ); // assoc faces - MESSAGE("Assoc FACE " << theMesh1->GetMeshDS()->ShapeToIndex( face1 )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( face2 )); + // MESSAGE("Assoc FACE " << theMesh1->GetMeshDS()->ShapeToIndex( face1 )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( face2 )); if ( nbE == 2 && (edge1.IsSame( edges1.front())) != (edge2.IsSame( edges2.front()))) { reverseEdges( edges2, nbE ); @@ -728,8 +754,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - if ( !boundEdges.Add( *eIt1 )) continue; // already associated - InsertAssociation( *eIt1, *eIt2, theMap ); // assoc edges + if ( !InsertAssociation( *eIt1, *eIt2, theMap )) // assoc edges + continue; // already associated VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); InsertAssociation( VV1[0], VV2[0], theMap ); // assoc vertices @@ -738,6 +764,10 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Face nextFace1 = GetNextFace( edgeToFace1, *eIt1, face1 ); TopoDS_Face nextFace2 = GetNextFace( edgeToFace2, *eIt2, face2 ); if ( !nextFace1.IsNull() && !nextFace2.IsNull() ) { + if ( SMESH_MesherHelper::GetSubShapeOri( nextFace1, *eIt1 ) == eIt1->Orientation() ) + nextFace1.Reverse(); + if ( SMESH_MesherHelper::GetSubShapeOri( nextFace2, *eIt2 ) == eIt2->Orientation() ) + nextFace2.Reverse(); FE1.push_back( make_pair( nextFace1, *eIt1 )); FE2.push_back( make_pair( nextFace2, *eIt2 )); } @@ -819,8 +849,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // Associate shells // - int nbFaces1 = SMESH_MesherHelper:: Count( shell1, TopAbs_FACE, 0 ); - int nbFaces2 = SMESH_MesherHelper:: Count( shell2, TopAbs_FACE, 0 ); + int nbFaces1 = SMESH_MesherHelper::Count( shell1, TopAbs_FACE, 0 ); + int nbFaces2 = SMESH_MesherHelper::Count( shell2, TopAbs_FACE, 0 ); if ( nbFaces1 != nbFaces2 ) RETURN_BAD_RESULT("Different nb of faces found for shells"); if ( nbFaces1 > 0 ) { @@ -926,14 +956,14 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the v2e[0].UnBind( V[0] ); v2e[1].UnBind( V[1] ); InsertAssociation( e0, e1, theMap ); - MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0 )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1 )); + // MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0 )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1 )); V[0] = GetNextVertex( e0, V[0] ); V[1] = GetNextVertex( e1, V[1] ); if ( !V[0].IsNull() ) { InsertAssociation( V[0], V[1], theMap ); - MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( V[0] )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( V[1] )); + // MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( V[0] )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( V[1] )); } } else if ( nbE0 == 2 ) @@ -960,12 +990,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the InsertAssociation( e0b, e1b, theMap ); InsertAssociation( e0n, e1n, theMap ); InsertAssociation( v0n, v1n, theMap ); - MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0b )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1b )); - MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0n )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1n )); - MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( v0n )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( v1n )); + // MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0b )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1b )); + // MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0n )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1n )); + // MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( v0n )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( v1n )); v2e[0].UnBind( V[0] ); v2e[1].UnBind( V[1] ); V[0] = v0n; @@ -1011,6 +1041,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the InsertAssociation( edge1, prpEdge, theMap ); // insert with a proper orientation } InsertAssociation( theShape1, theShape2, theMap ); + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); return true; // done } } @@ -1081,11 +1112,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { InsertAssociation( *eIt1, *eIt2, theMap ); - VV1[0] = TopExp::FirstVertex( *eIt1, true ); - VV2[0] = TopExp::FirstVertex( *eIt2, true ); + VV1[0] = SMESH_MesherHelper::IthVertex( 0, *eIt1, true ); + VV2[0] = SMESH_MesherHelper::IthVertex( 0, *eIt2, true ); InsertAssociation( VV1[0], VV2[0], theMap ); } InsertAssociation( theShape1, theShape2, theMap ); + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); return true; } } @@ -1150,7 +1182,11 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( !VV1[1].IsNull() ) { InsertAssociation( VV1[0], VV2[0], theMap ); InsertAssociation( VV1[1], VV2[1], theMap ); - return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); + TShapeShapeMap::EAssocType asType = theMap._assocType; + theMap.SetAssocType( TShapeShapeMap::PROPAGATION ); + if ( FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) + return true; + theMap._assocType = asType; } } break; // try by vertex closeness @@ -1206,8 +1242,11 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the { InsertAssociation( VV1[0], VV1[0], theMap ); InsertAssociation( VV1[1], VV1[1], theMap ); - if (FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) + TShapeShapeMap::EAssocType asType = theMap._assocType; + theMap.SetAssocType( TShapeShapeMap::COMMON_VERTEX ); + if ( FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) return true; + theMap._assocType = asType; } } } @@ -1301,13 +1340,14 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the break; } } + theMap.SetAssocType( TShapeShapeMap::CLOSE_VERTEX ); InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap ); InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap ); - MESSAGE("Initial assoc VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 0 ] )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 0 ] )<< - "\nand VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 1 ] )<< - " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 1 ] )); + // MESSAGE("Initial assoc VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 0 ] )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 0 ] )<< + // "\nand VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 1 ] )<< + // " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 1 ] )); if ( theShape1.ShapeType() == TopAbs_EDGE ) { InsertAssociation( theShape1, theShape2, theMap ); return true; @@ -1325,6 +1365,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the * \param VV2 - vertices of face 2 associated with ones of face 1 * \param edges1 - out list of edges of face 1 * \param edges2 - out list of edges of face 2 + * \param isClosenessAssoc - is association starting by VERTEX closeness * \retval int - nb of edges in an outer wire in a success case, else zero */ //================================================================================ @@ -1334,7 +1375,8 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, const TopoDS_Face& face2, TopoDS_Vertex VV2[2], list< TopoDS_Edge > & edges1, - list< TopoDS_Edge > & edges2) + list< TopoDS_Edge > & edges2, + const bool isClosenessAssoc) { bool OK = false; list< int > nbEInW1, nbEInW2; @@ -1363,46 +1405,56 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, // Define if we need to reverse one of wires to make edges in lists match each other bool reverse = false; + const bool severalWires = ( nbEInW1.size() > 1 ); - if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) { + if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) + { reverse = true; - edgeIt = --edges1.end(); // check if the second vertex belongs to the first or last edge in the wire + edgeIt = --edges1.end(); // pointer to the last edge in the outer wire + if ( severalWires ) { + edgeIt = edges1.begin(); + std::advance( edgeIt, nbEInW1.front()-1 ); + } + if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt )) && + SMESH_Algo::isDegenerated( *edgeIt )) { + --edgeIt; // skip a degenerated edge (test 3D_mesh_Projection_00/A3) + } if ( !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { - bool KO = true; // belongs to none - if ( nbEInW1.size() > 1 ) { // several wires - edgeIt = edges1.begin(); - std::advance( edgeIt, nbEInW1.front()-1 ); - KO = !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); - } - if ( KO ) - CONT_BAD_RESULT("GetOrderedEdges() failed"); + CONT_BAD_RESULT("GetOrderedEdges() failed"); } } - if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) { + if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) + { reverse = !reverse; - edgeIt = --edges2.end(); - // move a degenerated edge from back to front - // http://www.salome-platform.org/forum/forum_11/173031193 - if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt ))) { - edges2.splice( edges2.begin(), edges2, edgeIt ); - edgeIt = --edges2.end(); - } // check if the second vertex belongs to the first or last edge in the wire + edgeIt = --edges2.end(); // pointer to the last edge in the outer wire + if ( severalWires ) { + edgeIt = edges2.begin(); + std::advance( edgeIt, nbEInW2.front()-1 ); + } + if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt )) && + SMESH_Algo::isDegenerated( *edgeIt )) { + --edgeIt; // skip a degenerated edge + } if ( !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { - bool KO = true; // belongs to none - if ( nbEInW2.size() > 1 ) { // several wires - edgeIt = edges2.begin(); - std::advance( edgeIt, nbEInW2.front()-1 ); - KO = !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); - } - if ( KO ) - CONT_BAD_RESULT("GetOrderedEdges() failed"); + CONT_BAD_RESULT("GetOrderedEdges() failed"); } } if ( reverse ) { reverseEdges( edges2 , nbEInW2.front()); + + if ( SMESH_Algo::isDegenerated( edges2.front() )) + { + // move a degenerated edge to the back of the outer wire + edgeIt = edges2.end(); + if ( severalWires ) { + edgeIt = edges2.begin(); + std::advance( edgeIt, nbEInW2.front() ); + } + edges2.splice( edgeIt, edges2, edges2.begin() ); + } if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) CONT_BAD_RESULT("GetOrderedEdges() failed"); @@ -1410,6 +1462,65 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, OK = true; } // loop algos getting an outer wire + + if ( OK && nbEInW1.front() > 4 ) // care of a case where faces are closed (23032) + { + // check if the first edges are seam ones + list< TopoDS_Edge >::iterator revSeam1, revSeam2; + revSeam1 = std::find( ++edges1.begin(), edges1.end(), edges1.front().Reversed()); + revSeam2 = edges2.end(); + if ( revSeam1 != edges1.end() ) + revSeam2 = std::find( ++edges2.begin(), edges2.end(), edges2.front().Reversed()); + if ( revSeam2 != edges2.end() ) // two seams detected + { + bool reverse = + std::distance( edges1.begin(), revSeam1 ) != std::distance( edges2.begin(), revSeam2 ); + if ( !reverse && isClosenessAssoc ) + { + // compare orientations of a non-seam edges using 3D closeness; + // look for a non-seam edges + list< TopoDS_Edge >::iterator edge1 = ++edges1.begin(); + list< TopoDS_Edge >::iterator edge2 = ++edges2.begin(); + for ( ; edge1 != edges1.end(); ++edge1, ++edge2 ) + { + if (( edge1 == revSeam1 ) || + ( SMESH_Algo::isDegenerated( *edge1 )) || + ( std::find( ++edges1.begin(), edges1.end(), edge1->Reversed()) != edges1.end() )) + continue; + gp_Pnt p1 = BRep_Tool::Pnt( VV1[0] ); + gp_Pnt p2 = BRep_Tool::Pnt( VV2[0] ); + gp_Vec vec2to1( p2, p1 ); + + gp_Pnt pp1[2], pp2[2]; + const double r = 0.2345; + double f,l; + Handle(Geom_Curve) C = BRep_Tool::Curve( *edge1, f,l ); + pp1[0] = C->Value( f * r + l * ( 1. - r )); + pp1[1] = C->Value( l * r + f * ( 1. - r )); + if ( edge1->Orientation() == TopAbs_REVERSED ) + std::swap( pp1[0], pp1[1] ); + C = BRep_Tool::Curve( *edge2, f,l ); + if ( C.IsNull() ) return 0; + pp2[0] = C->Value( f * r + l * ( 1. - r )).Translated( vec2to1 ); + pp2[1] = C->Value( l * r + f * ( 1. - r )).Translated( vec2to1 ); + if ( edge2->Orientation() == TopAbs_REVERSED ) + std::swap( pp2[0], pp2[1] ); + + double dist00 = pp1[0].SquareDistance( pp2[0] ); + double dist01 = pp1[0].SquareDistance( pp2[1] ); + reverse = ( dist00 > dist01 ); + break; + } + } + if ( reverse ) // make a seam counterpart be the first + { + list< TopoDS_Edge >::iterator outWireEnd = edges2.begin(); + std::advance( outWireEnd, nbEInW2.front() ); + edges2.splice( outWireEnd, edges2, edges2.begin(), ++revSeam2 ); + reverseEdges( edges2 , nbEInW2.front()); + } + } + } // Try to orient all (if !OK) or only internal wires (issue 0020996) by UV similarity @@ -1418,13 +1529,23 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, // Check that Vec(VV1[0],VV1[1]) in 2D on face1 is the same // as Vec(VV2[0],VV2[1]) on face2 double vTol = BRep_Tool::Tolerance( VV1[0] ); - BRepAdaptor_Surface surface1( face1, false ); + BRepAdaptor_Surface surface1( face1, true ); + BRepAdaptor_Surface surface2( face2, true ); + // TODO: use TrsfFinder2D to superpose the faces + gp_Pnt2d v0f1UV( surface1.FirstUParameter(), surface1.FirstVParameter() ); + gp_Pnt2d v0f2UV( surface2.FirstUParameter(), surface2.FirstVParameter() ); + gp_Pnt2d v1f1UV( surface1.LastUParameter(), surface1.LastVParameter() ); + gp_Pnt2d v1f2UV( surface2.LastUParameter(), surface2.LastVParameter() ); double vTolUV = surface1.UResolution( vTol ) + surface1.VResolution( vTol ); // let's be tolerant - gp_Pnt2d v0f1UV = BRep_Tool::Parameters( VV1[0], face1 ); - gp_Pnt2d v0f2UV = BRep_Tool::Parameters( VV2[0], face2 ); - gp_Pnt2d v1f1UV = BRep_Tool::Parameters( VV1[1], face1 ); - gp_Pnt2d v1f2UV = BRep_Tool::Parameters( VV2[1], face2 ); + // VV1[0] = TopExp::FirstVertex( edges1.front(), true ); // ori is important if face is closed + // VV1[1] = TopExp::LastVertex ( edges1.front(), true ); + // VV2[0] = TopExp::FirstVertex( edges2.front(), true ); + // VV2[1] = TopExp::LastVertex ( edges2.front(), true ); + // gp_Pnt2d v0f1UV = BRep_Tool::Parameters( VV1[0], face1 ); + // gp_Pnt2d v0f2UV = BRep_Tool::Parameters( VV2[0], face2 ); + // gp_Pnt2d v1f1UV = BRep_Tool::Parameters( VV1[1], face1 ); + // gp_Pnt2d v1f2UV = BRep_Tool::Parameters( VV2[1], face2 ); gp_Vec2d v01f1Vec( v0f1UV, v1f1UV ); gp_Vec2d v01f2Vec( v0f2UV, v1f2UV ); if ( Abs( v01f1Vec.X()-v01f2Vec.X()) < vTolUV && @@ -1443,7 +1564,6 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, list< int >::iterator nbE2, nbE1 = nbEInW1.begin(); list< TopoDS_Edge >::iterator edge2Beg, edge1Beg = edges1.begin(); if ( OK ) std::advance( edge1Beg, *nbE1++ ); - // reach an end of edges of a current wire1 list< TopoDS_Edge >::iterator edge2End, edge1End; // // find corresponding wires of face2 @@ -1471,33 +1591,35 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, std::advance( edge2End, *nbE2 ); if ( *nbE1 == *nbE2 && iW2 >= iW1 ) { - // rotate edge2 untill coincidence with edge1 in 2D + // rotate edge2 until coincides with edge1 in 2D int i = *nbE2; - while ( i-- > 0 && !sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + bool sameUV = false; + while ( !( sameUV = sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) && --i > 0 ) // move edge2Beg to place before edge2End edges2.splice( edge2End, edges2, edge2Beg++ ); - if ( edge2Beg != edges2.end() && - sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + if ( sameUV ) { if ( iW1 == 0 ) OK = true; // OK is for the first wire // reverse edges2 if needed if ( SMESH_MesherHelper::IsClosedEdge( *edge1Beg )) { - double f,l; - Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( *edge1Beg, face1,f,l ); - if ( edge1Beg->Orientation() == TopAbs_REVERSED ) - std::swap( f,l ); - gp_Pnt2d uv1 = dUV + c1->Value( f * 0.8 + l * 0.2 ).XY(); - - Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( *edge2Beg, face2,f,l ); - if ( edge2Beg->Orientation() == TopAbs_REVERSED ) - std::swap( f,l ); - gp_Pnt2d uv2 = c2->Value( f * 0.8 + l * 0.2 ); - - if ( uv1.Distance( uv2 ) > vTolUV ) - edge2Beg->Reverse(); + // Commented (so far?) as it's not checked if orientation must be same or reversed + // double f,l; + // Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( *edge1Beg, face1,f,l ); + // if ( edge1Beg->Orientation() == TopAbs_REVERSED ) + // std::swap( f,l ); + // gp_Pnt2d uv1 = dUV + c1->Value( f * 0.8 + l * 0.2 ).XY(); + + // Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( *edge2Beg, face2,f,l ); + // if ( edge2Beg->Orientation() == TopAbs_REVERSED ) + // std::swap( f,l ); + // gp_Pnt2d uv2 = c2->Value( f * 0.8 + l * 0.2 ); + // gp_Pnt2d uv3 = c2->Value( l * 0.8 + f * 0.2 ); + + // if ( uv1.SquareDistance( uv2 ) > uv1.SquareDistance( uv3 )) + // edge2Beg->Reverse(); } else { @@ -1518,7 +1640,7 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, break; } } - // prepare to the next wire loop + // prepare for the next wire loop edge2Beg = edge2End; } edge1Beg = edge1End; @@ -1751,7 +1873,7 @@ StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMes int prevChainSize = aChain.Extent(); if ( aChain.Add(anOppE) > prevChainSize ) { // ... anOppE is not in aChain // Add found edge to the chain oriented so that to - // have it co-directed with a forward MainEdge + // have it co-directed with a fromEdge TopAbs_Orientation ori = anE.Orientation(); if ( anOppE.Orientation() == fourEdges[found].Orientation() ) ori = TopAbs::Reverse( ori ); @@ -1814,7 +1936,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, helper1.SetSubShape( face1 ); helper2.SetSubShape( face2 ); - if ( helper1.HasSeam() != helper2.HasSeam() ) + if ( helper1.HasRealSeam() != helper2.HasRealSeam() ) RETURN_BAD_RESULT("Different faces' geometry"); // Data to call SMESH_MeshEditor::FindMatchingNodes(): @@ -2066,7 +2188,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, static_cast(node->GetPosition()); pos2nodes.insert( make_pair( pos->GetUParameter(), node )); } - if ( pos2nodes.size() != edgeSM->NbNodes() ) + if ((int) pos2nodes.size() != edgeSM->NbNodes() ) RETURN_BAD_RESULT("Equal params of nodes on edge " << smDS->ShapeToIndex( edge ) << " of face " << is2 ); } @@ -2204,7 +2326,7 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter string algoType = algo->GetName(); if ( algoType.substr(0, 11) != "Projection_") - return gen->Compute( *mesh, shape, /*shapeOnly=*/true ); + return gen->Compute( *mesh, shape, SMESH_Gen::SHAPE_ONLY ); // try to compute source mesh @@ -2245,7 +2367,7 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter srcMesh = mesh; if ( MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 ) && - gen->Compute( *mesh, shape, /*shapeOnly=*/true )) + gen->Compute( *mesh, shape, SMESH_Gen::SHAPE_ONLY )) return sm->IsMeshComputed(); return false; @@ -2267,7 +2389,7 @@ std::string StdMeshers_ProjectionUtils::SourceNotComputedError( SMESH_subMesh * if ( !sm || sm->GetAlgoState() != SMESH_subMesh::NO_ALGO ) return usualMessage; // algo is OK, anything else is KO. - // Try to find a type of all-dimentional algorithm that would compute the + // Try to find a type of all-dimensional algorithm that would compute the // given sub-mesh if it could be launched before projection const TopoDS_Shape shape = sm->GetSubShape(); const int shapeDim = SMESH_Gen::GetShapeDim( shape ); @@ -2448,7 +2570,7 @@ namespace StdMeshers_ProjectionUtils //================================================================================ /*! - * \brief Computes transformation beween two sets of 2D points using + * \brief Computes transformation between two sets of 2D points using * a least square approximation * * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" @@ -2504,13 +2626,13 @@ namespace StdMeshers_ProjectionUtils // cout << vec( 1 ) << "\t " << vec( 2 ) << endl // << vec( 3 ) << "\t " << vec( 4 ) << endl; - _trsf.SetTranslation( tgtGC ); + _trsf.SetTranslationPart( tgtGC ); _srcOrig = srcGC; - gp_Mat2d& M = const_cast< gp_Mat2d& >( _trsf.HVectorialPart()); + gp_Mat2d& M = const_cast< gp_Mat2d& >( _trsf.VectorialPart()); M( 1,1 ) = vec( 1 ); - M( 2,1 ) = vec( 2 ); - M( 1,2 ) = vec( 3 ); + M( 2,1 ) = vec( 2 ); // | 1 3 | -- is it correct ???????? + M( 1,2 ) = vec( 3 ); // | 2 4 | M( 2,2 ) = vec( 4 ); return true; @@ -2531,7 +2653,7 @@ namespace StdMeshers_ProjectionUtils //================================================================================ /*! - * \brief Computes transformation beween two sets of 3D points using + * \brief Computes transformation between two sets of 3D points using * a least square approximation * * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" @@ -2601,9 +2723,9 @@ namespace StdMeshers_ProjectionUtils // << vec( 7 ) << "\t " << vec( 8 ) << "\t " << vec( 9 ) << endl; _srcOrig = srcOrig; - _trsf.SetTranslation( tgtOrig ); + _trsf.SetTranslationPart( tgtOrig ); - gp_Mat& M = const_cast< gp_Mat& >( _trsf.HVectorialPart() ); + gp_Mat& M = const_cast< gp_Mat& >( _trsf.VectorialPart() ); M.SetRows( gp_XYZ( vec( 1 ), vec( 2 ), vec( 3 )), gp_XYZ( vec( 4 ), vec( 5 ), vec( 6 )), gp_XYZ( vec( 7 ), vec( 8 ), vec( 9 ))); @@ -2631,7 +2753,7 @@ namespace StdMeshers_ProjectionUtils gp_XYZ TrsfFinder3D::TransformVec( const gp_Vec& v ) const { - return v.XYZ().Multiplied( _trsf.HVectorialPart() ); + return v.XYZ().Multiplied( _trsf.VectorialPart() ); } //================================================================================ /*! @@ -2646,7 +2768,7 @@ namespace StdMeshers_ProjectionUtils { // seems to be defined via Solve() gp_XYZ newSrcOrig = _trsf.TranslationPart(); - gp_Mat& M = const_cast< gp_Mat& >( _trsf.HVectorialPart() ); + gp_Mat& M = const_cast< gp_Mat& >( _trsf.VectorialPart() ); const double D = M.Determinant(); if ( D < 1e-3 * ( newSrcOrig - _srcOrig ).Modulus() ) { @@ -2657,7 +2779,7 @@ namespace StdMeshers_ProjectionUtils return false; } gp_Mat Minv = M.Inverted(); - _trsf.SetTranslation( _srcOrig ); + _trsf.SetTranslationPart( _srcOrig ); _srcOrig = newSrcOrig; M = Minv; } @@ -2667,4 +2789,326 @@ namespace StdMeshers_ProjectionUtils } return true; } -} + + //================================================================================ + /*! + * \brief Add in-FACE nodes surrounding a given node to a queue + */ + //================================================================================ + + void Morph::AddCloseNodes( const SMDS_MeshNode* srcNode, + const BRepMesh_Triangle* bmTria, + const int srcFaceID, + TNodeTriaList & noTriQueue ) + { + // find in-FACE nodes + SMDS_ElemIteratorPtr elems = srcNode->GetInverseElementIterator(SMDSAbs_Face); + while ( elems->more() ) + { + const SMDS_MeshElement* elem = elems->next(); + if ( elem->getshapeId() == srcFaceID ) + { + for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i ) + { + const SMDS_MeshNode* n = elem->GetNode( i ); + if ( !n->isMarked() /*&& n->getshapeId() == srcFaceID*/ ) + noTriQueue.push_back( make_pair( n, bmTria )); + } + } + } + } + + //================================================================================ + /*! + * \brief Find a delauney triangle containing a given 2D point and return + * barycentric coordinates within the found triangle + */ + //================================================================================ + + const BRepMesh_Triangle* Morph::FindTriangle( const gp_XY& uv, + const BRepMesh_Triangle* bmTria, + double bc[3], + int triaNodes[3] ) + { + int nodeIDs[3]; + gp_XY nodeUVs[3]; + int linkIDs[3]; + Standard_Boolean ori[3]; + + while ( bmTria ) + { + // check bmTria + + _triaDS->ElementNodes( *bmTria, nodeIDs ); + nodeUVs[0] = _triaDS->GetNode( nodeIDs[0] ).Coord(); + nodeUVs[1] = _triaDS->GetNode( nodeIDs[1] ).Coord(); + nodeUVs[2] = _triaDS->GetNode( nodeIDs[2] ).Coord(); + + SMESH_MeshAlgos::GetBarycentricCoords( uv, + nodeUVs[0], nodeUVs[1], nodeUVs[2], + bc[0], bc[1] ); + if ( bc[0] >= 0 && bc[1] >= 0 && bc[0] + bc[1] <= 1 ) + { + bc[2] = 1 - bc[0] - bc[1]; + triaNodes[0] = nodeIDs[0]; + triaNodes[1] = nodeIDs[1]; + triaNodes[2] = nodeIDs[2]; + return bmTria; + } + + // look for a neighbor triangle, which is adjacent to a link intersected + // by a segment( triangle center -> uv ) + + gp_XY gc = ( nodeUVs[0] + nodeUVs[1] + nodeUVs[2] ) / 3.; + gp_XY seg = uv - gc; + + bmTria->Edges( linkIDs, ori ); + int triaID = _triaDS->IndexOf( *bmTria ); + bmTria = 0; + + for ( int i = 0; i < 3; ++i ) + { + const BRepMesh_PairOfIndex & triIDs = _triaDS->ElementsConnectedTo( linkIDs[i] ); + if ( triIDs.Extent() < 2 ) + continue; // no neighbor triangle + + // check if a link intersects gc2uv + const BRepMesh_Edge & link = _triaDS->GetLink( linkIDs[i] ); + const BRepMesh_Vertex & n1 = _triaDS->GetNode( link.FirstNode() ); + const BRepMesh_Vertex & n2 = _triaDS->GetNode( link.LastNode() ); + gp_XY uv1 = n1.Coord(); + gp_XY lin = n2.Coord() - uv1; // link direction + + double crossSegLin = seg ^ lin; + if ( Abs( crossSegLin ) < std::numeric_limits::min() ) + continue; // parallel + + double uSeg = ( uv1 - gc ) ^ lin / crossSegLin; + if ( 0. <= uSeg && uSeg <= 1. ) + { + bmTria = & _triaDS->GetElement( triIDs.Index( 1 + ( triIDs.Index(1) == triaID ))); + break; + } + } + } + return bmTria; + } + + //================================================================================ + /*! + * \brief Return a triangle sharing a given boundary node + * \param [in] iBndNode - index of the boundary node + * \return const BRepMesh_Triangle* - a found triangle + */ + //================================================================================ + + const BRepMesh_Triangle* Morph::GetTriangleNear( int iBndNode ) + { + const BRepMesh::ListOfInteger & linkIds = _triaDS->LinksConnectedTo( iBndNode ); + const BRepMesh_PairOfIndex & triaIds = _triaDS->ElementsConnectedTo( linkIds.First() ); + const BRepMesh_Triangle& tria = _triaDS->GetElement( triaIds.Index(1) ); + return &tria; + } + + //================================================================================ + /*! + * \brief triangulate the srcFace in 2D + * \param [in] srcWires - boundary of the src FACE + */ + //================================================================================ + + Morph::Morph(const TSideVector& srcWires) + { + _srcSubMesh = srcWires[0]->GetMesh()->GetSubMesh( srcWires[0]->Face() ); + + // compute _scale + { + BRepAdaptor_Surface surf( srcWires[0]->Face() ); + const int nbDiv = 100; + const double uRange = surf.LastUParameter() - surf.FirstUParameter(); + const double vRange = surf.LastVParameter() - surf.FirstVParameter(); + const double dU = uRange / nbDiv; + const double dV = vRange / nbDiv; + double u = surf.FirstUParameter(), v = surf.FirstVParameter(); + gp_Pnt p0U = surf.Value( u, v ), p0V = p0U; + double lenU = 0, lenV = 0; + for ( ; u < surf.LastUParameter(); u += dU, v += dV ) + { + gp_Pnt p1U = surf.Value( u, surf.FirstVParameter() ); + lenU += p1U.Distance( p0U ); + p0U = p1U; + gp_Pnt p1V = surf.Value( surf.FirstUParameter(), v ); + lenV += p1V.Distance( p0V ); + p0V = p1V; + } + _scale.SetCoord( lenU / uRange, lenV / vRange ); + } + + // count boundary points + int iP = 1, nbP = 0; + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + nbP += srcWires[iW]->NbPoints() - 1; // 1st and last points coincide + + _bndSrcNodes.resize( nbP + 1 ); _bndSrcNodes[0] = 0; + + // fill boundary points + BRepMesh::Array1OfVertexOfDelaun srcVert( 1, 1 + nbP ); + BRepMesh_Vertex v( 0, 0, BRepMesh_Frontier ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + const UVPtStructVec& srcPnt = srcWires[iW]->GetUVPtStruct(); + for ( int i = 0, nb = srcPnt.size() - 1; i < nb; ++i, ++iP ) + { + _bndSrcNodes[ iP ] = srcPnt[i].node; + srcPnt[i].node->setIsMarked( true ); + + v.ChangeCoord() = srcPnt[i].UV().Multiplied( _scale ); + srcVert( iP ) = v; + } + } + // triangulate the srcFace in 2D + BRepMesh_Delaun delauney( srcVert ); + _triaDS = delauney.Result(); + } + + //================================================================================ + /*! + * \brief Move non-marked target nodes + * \param [in,out] tgtHelper - helper + * \param [in] tgtWires - boundary nodes of the target FACE; must be in the + * same order as the nodes in srcWires given in the constructor + * \param [in] src2tgtNodes - map of src -> tgt nodes + * \param [in] moveAll - to move all nodes; if \c false, move only non-marked nodes + * \return bool - Ok or not + */ + //================================================================================ + + bool Morph::Perform(SMESH_MesherHelper& tgtHelper, + const TSideVector& tgtWires, + Handle(ShapeAnalysis_Surface) tgtSurface, + const TNodeNodeMap& src2tgtNodes, + const bool moveAll) + { + // get tgt boundary points corresponding to _bndSrcNodes + size_t nbP = 0; + for ( size_t iW = 0; iW < tgtWires.size(); ++iW ) + nbP += tgtWires[iW]->NbPoints() - 1; // 1st and last points coincide + if ( nbP != _bndSrcNodes.size() - 1 ) + return false; + + BRepMesh::Array1OfVertexOfDelaun tgtVert( 1, 1 + nbP ); + BRepMesh_Vertex v( 0, 0, BRepMesh_Frontier ); + for ( size_t iW = 0, iP = 1; iW < tgtWires.size(); ++iW ) + { + const UVPtStructVec& tgtPnt = tgtWires[iW]->GetUVPtStruct(); + for ( int i = 0, nb = tgtPnt.size() - 1; i < nb; ++i, ++iP ) + { + v.ChangeCoord() = tgtPnt[i].UV().Multiplied( _scale ); + tgtVert( iP ) = v; + } + } + + const TopoDS_Face& srcFace = TopoDS::Face( _srcSubMesh->GetSubShape() ); + const int srcFaceID = _srcSubMesh->GetId(); + SMESHDS_Mesh* tgtMesh = tgtHelper.GetMeshDS(); + const SMDS_MeshNode *srcNode, *tgtNode; + const BRepMesh_Triangle *bmTria; + + // un-mark internal src nodes; later we will mark moved nodes + int nbSrcNodes = 0; + SMDS_NodeIteratorPtr nIt = _srcSubMesh->GetSubMeshDS()->GetNodes(); + if ( !nIt || !nIt->more() ) return true; + if ( moveAll ) + { + nbSrcNodes = _srcSubMesh->GetSubMeshDS()->NbNodes(); + while ( nIt->more() ) + nIt->next()->setIsMarked( false ); + } + else + { + while ( nIt->more() ) + nbSrcNodes += int( !nIt->next()->isMarked() ); + } + + // Move tgt nodes + + double bc[3]; // barycentric coordinates + int nodeIDs[3]; + bool checkUV = true; + const SMDS_FacePosition* pos; + + // a queue of nodes with starting triangles + TNodeTriaList noTriQueue; + size_t iBndSrcN = 1; + + while ( nbSrcNodes > 0 ) + { + while ( !noTriQueue.empty() ) + { + srcNode = noTriQueue.front().first; + bmTria = noTriQueue.front().second; + noTriQueue.pop_front(); + if ( srcNode->isMarked() ) + continue; + --nbSrcNodes; + srcNode->setIsMarked( true ); + + // find a delauney triangle containing the src node + gp_XY uv = tgtHelper.GetNodeUV( srcFace, srcNode, NULL, &checkUV ); + uv *= _scale; + bmTria = FindTriangle( uv, bmTria, bc, nodeIDs ); + if ( !bmTria ) + continue; + + // compute new coordinates for a corresponding tgt node + gp_XY uvNew( 0., 0. ), nodeUV; + for ( int i = 0; i < 3; ++i ) + uvNew += bc[i] * tgtVert( nodeIDs[i]).Coord(); + uvNew.SetCoord( uvNew.X() / _scale.X(), + uvNew.Y() / _scale.Y() ); + gp_Pnt xyz = tgtSurface->Value( uvNew ); + + // find and move tgt node + TNodeNodeMap::const_iterator n2n = src2tgtNodes.find( srcNode ); + if ( n2n == src2tgtNodes.end() ) continue; + tgtNode = n2n->second; + tgtMesh->MoveNode( tgtNode, xyz.X(), xyz.Y(), xyz.Z() ); + + if (( pos = dynamic_cast< const SMDS_FacePosition* >( tgtNode->GetPosition() ))) + const_cast( pos )->SetParameters( uvNew.X(), uvNew.Y() ); + + AddCloseNodes( srcNode, bmTria, srcFaceID, noTriQueue ); + } + + if ( nbSrcNodes > 0 ) + { + // assure that all src nodes are visited + for ( ; iBndSrcN < _bndSrcNodes.size() && noTriQueue.empty(); ++iBndSrcN ) + { + const BRepMesh_Triangle* tria = GetTriangleNear( iBndSrcN ); + AddCloseNodes( _bndSrcNodes[ iBndSrcN ], tria, srcFaceID, noTriQueue ); + } + if ( noTriQueue.empty() ) + { + SMDS_NodeIteratorPtr nIt = _srcSubMesh->GetSubMeshDS()->GetNodes(); + while ( nIt->more() ) + { + srcNode = nIt->next(); + if ( !srcNode->isMarked() ) + noTriQueue.push_back( make_pair( srcNode, bmTria )); + } + } + } + } + + return true; + + } // Morph::Perform + + gp_XY Morph::GetBndUV(const int iNode) const + { + return _triaDS->GetNode( iNode ).Coord(); + } + + +} // namespace StdMeshers_ProjectionUtils