Salome HOME
23514: EDF 16031 - SMESH freezes
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_2D.cxx
index 10f86269668b36670de022da3e301bdd75017567..64ce054c5d9d6a2385c97e980f0d8e6de654156e 100644 (file)
@@ -426,6 +426,7 @@ namespace {
                   const TopoDS_Face&                 srcFace,
                   SMESH_Mesh *                       tgtMesh,
                   SMESH_Mesh *                       srcMesh,
+                  SMESH_MesherHelper*                tgtHelper,
                   const TAssocTool::TShapeShapeMap&  shape2ShapeMap,
                   TSideVector&                       srcWires,
                   TSideVector&                       tgtWires,
@@ -436,7 +437,7 @@ namespace {
 
     // get ordered src EDGEs
     TError err;
-    srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err);
+    srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err );
     if (( err && !err->IsOK() ) ||
         ( srcWires.empty() ))
       return err;
@@ -445,8 +446,6 @@ namespace {
          << tgtMesh->GetMeshDS()->ShapeToIndex( tgtFace ) << " <- "
          << srcMesh->GetMeshDS()->ShapeToIndex( srcFace ) << endl;
 #endif
-    SMESH_MesherHelper srcHelper( *srcMesh );
-    srcHelper.SetSubShape( srcFace );
 
     // make corresponding sequence of tgt EDGEs
     tgtWires.resize( srcWires.size() );
@@ -493,7 +492,8 @@ namespace {
 
       tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
                                                      /*theIsForward = */ true,
-                                                     /*theIgnoreMediumNodes = */false));
+                                                     /*theIgnoreMediumNodes = */false,
+                                                     tgtHelper ));
       StdMeshers_FaceSidePtr tgtWire = tgtWires[ iW ];
 
       // Fill map of src to tgt nodes with nodes on edges
@@ -517,9 +517,11 @@ namespace {
         else
         {
           const bool skipMedium = true, isFwd = true;
-          StdMeshers_FaceSide srcEdge( srcFace, srcWire->Edge(iE), srcMesh, isFwd, skipMedium);
-          StdMeshers_FaceSide tgtEdge( tgtFace, tgtWire->Edge(iE), tgtMesh, isFwd, skipMedium);
-          
+          StdMeshers_FaceSide srcEdge( srcFace, srcWire->Edge(iE),
+                                       srcMesh, isFwd, skipMedium, srcWires[0]->FaceHelper() );
+          StdMeshers_FaceSide tgtEdge( tgtFace, tgtWire->Edge(iE),
+                                       tgtMesh, isFwd, skipMedium, tgtHelper);
+
           vector< const SMDS_MeshNode* > srcNodes = srcEdge.GetOrderedNodes();
           vector< const SMDS_MeshNode* > tgtNodes = tgtEdge.GetOrderedNodes();
 
@@ -553,7 +555,7 @@ namespace {
 
   //================================================================================
   /*!
-   * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case
+   * \brief Perform projection in case if tgtFace.IsPartner( srcFace ) and in case
    * if projection by 3D transformation is possible
    */
   //================================================================================
@@ -566,11 +568,11 @@ namespace {
                       TAssocTool::TNodeNodeMap&          src2tgtNodes,
                       const bool                         is1DComputed)
   {
-    SMESH_Mesh *    tgtMesh = tgtWires[0]->GetMesh();
-    SMESH_Mesh *    srcMesh = srcWires[0]->GetMesh();
-    SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
-    SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
-    SMESH_MesherHelper helper( *tgtMesh );
+    SMESH_Mesh *       tgtMesh = tgtWires[0]->GetMesh();
+    SMESH_Mesh *       srcMesh = srcWires[0]->GetMesh();
+    SMESHDS_Mesh*    tgtMeshDS = tgtMesh->GetMeshDS();
+    SMESHDS_Mesh*    srcMeshDS = srcMesh->GetMeshDS();
+    SMESH_MesherHelper* helper = tgtWires[0]->FaceHelper();
 
     const double tol = 1.e-7 * srcMeshDS->getMaxDim();
 
@@ -647,7 +649,7 @@ namespace {
                          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 );
+        GeomAPI_ProjectPointOnSurf& proj = helper->GetProjector( tgtFace, loc, 0.1*tol );
         if ( !loc.IsIdentity() )
           tgtTrsfP.Transform( loc.Transformation().Inverted() );
         proj.Perform( tgtTrsfP );
@@ -662,16 +664,14 @@ namespace {
     // Make new faces
 
     // prepare the helper to adding quadratic elements if necessary
-    //helper.SetSubShape( tgtFace );
-    helper.IsQuadraticSubMesh( tgtFace );
+    helper->IsQuadraticSubMesh( tgtFace );
 
     SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace );
     if ( !is1DComputed && srcSubDS->NbElements() )
-      helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
+      helper->SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
 
-    SMESH_MesherHelper srcHelper( *srcMesh );
-    srcHelper.SetSubShape( srcFace );
-    SMESH_MesherHelper edgeHelper( *tgtMesh );
+    SMESH_MesherHelper* srcHelper = srcWires[0]->FaceHelper();
+    SMESH_MesherHelper  edgeHelper( *tgtMesh );
     edgeHelper.ToFixNodeParameters( true );
 
     const SMDS_MeshNode* nullNode = 0;
@@ -690,7 +690,7 @@ namespace {
       const SMDS_MeshElement* elem = elemIt->next();
       const int nbN = elem->NbCornerNodes(); 
       tgtNodes.resize( nbN );
-      helper.SetElementsOnShape( false );
+      helper->SetElementsOnShape( false );
       for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
       {
         const SMDS_MeshNode* srcNode = elem->GetNode(i);
@@ -699,21 +699,21 @@ namespace {
         {
           // create a new node
           gp_Pnt tgtP = trsf.Transform( SMESH_TNodeXYZ( srcNode ));
-          SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+          SMDS_MeshNode* n = helper->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
           srcN_tgtN->second = n;
           switch ( srcNode->GetPosition()->GetTypeOfPosition() )
           {
           case SMDS_TOP_FACE:
           {
-            gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode );
-            tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), srcUV.X(), srcUV.Y() );
+            gp_Pnt2d srcUV = srcHelper->GetNodeUV( srcFace, srcNode );
+            tgtMeshDS->SetNodeOnFace( n, helper->GetSubShapeID(), srcUV.X(), srcUV.Y() );
             break;
           }
           case SMDS_TOP_EDGE:
           {
             const TopoDS_Edge& srcE = TopoDS::Edge( srcMeshDS->IndexToShape( srcNode->getshapeId()));
             const TopoDS_Edge& tgtE = TopoDS::Edge( shape2ShapeMap( srcE, /*isSrc=*/true ));
-            double srcU = srcHelper.GetNodeU( srcE, srcNode );
+            double srcU = srcHelper->GetNodeU( srcE, srcNode );
             tgtMeshDS->SetNodeOnEdge( n, tgtE, srcU );
             if ( !tgtFace.IsPartner( srcFace ))
             {
@@ -749,14 +749,14 @@ namespace {
         tgtNodes[i] = srcN_tgtN->second;
       }
       // create a new face
-      helper.SetElementsOnShape( true );
+      helper->SetElementsOnShape( true );
       switch ( nbN )
       {
-      case 3: helper.AddFace(tgtNodes[0], tgtNodes[tri1], tgtNodes[tri2]); break;
-      case 4: helper.AddFace(tgtNodes[0], tgtNodes[quad1], tgtNodes[2], tgtNodes[quad3]); break;
+      case 3: helper->AddFace(tgtNodes[0], tgtNodes[tri1], tgtNodes[tri2]); break;
+      case 4: helper->AddFace(tgtNodes[0], tgtNodes[quad1], tgtNodes[2], tgtNodes[quad3]); break;
       default:
         if ( isReverse ) std::reverse( tgtNodes.begin(), tgtNodes.end() );
-        helper.AddPolygonalFace( tgtNodes );
+        helper->AddPolygonalFace( tgtNodes );
       }
     }
 
@@ -764,7 +764,7 @@ namespace {
 
     if ( !tgtFace.IsPartner( srcFace ) )
     {
-      helper.ToFixNodeParameters( true );
+      helper->ToFixNodeParameters( true );
 
       int nbOkPos = 0;
       const double tol2d = 1e-12;
@@ -777,8 +777,8 @@ 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 )) &&
+          gp_XY uv = helper->GetNodeUV( tgtFace, n ), uvBis = uv;
+          if (( helper->CheckNodeUV( tgtFace, n, uv, tol )) &&
               (( uv - uvBis ).SquareModulus() < tol2d ))
             ++nbOkPos;
           else
@@ -803,7 +803,7 @@ namespace {
 
   //================================================================================
   /*!
-   * \brief Preform projection in case if the faces are similar in 2D space
+   * \brief Perform projection in case if the faces are similar in 2D space
    */
   //================================================================================
 
@@ -898,18 +898,16 @@ namespace {
 
     SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
 
-    SMESH_MesherHelper helper( *tgtMesh );
-    helper.SetSubShape( tgtFace );
+    SMESH_MesherHelper* helper = tgtWires[0]->FaceHelper();
     if ( is1DComputed )
-      helper.IsQuadraticSubMesh( tgtFace );
+      helper->IsQuadraticSubMesh( tgtFace );
     else
-      helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
-    helper.SetElementsOnShape( true );
+      helper->SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
+    helper->SetElementsOnShape( true );
     Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace );
     SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
 
-    SMESH_MesherHelper srcHelper( *srcMesh );
-    srcHelper.SetSubShape( srcFace );
+    SMESH_MesherHelper* srcHelper = srcWires[0]->FaceHelper();
 
     const SMDS_MeshNode* nullNode = 0;
     TAssocTool::TNodeNodeMap::iterator srcN_tgtN;
@@ -920,7 +918,7 @@ namespace {
     while ( elemIt->more() ) // loop on all mesh faces on srcFace
     {
       const SMDS_MeshElement* elem = elemIt->next();
-      const int nbN = elem->NbCornerNodes(); 
+      const int nbN = elem->NbCornerNodes();
       tgtNodes.resize( nbN );
       for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
       {
@@ -929,27 +927,27 @@ namespace {
         if ( srcN_tgtN->second == nullNode )
         {
           // create a new node
-          gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
-                                                elem->GetNode( helper.WrapIndex(i+1,nbN)), &uvOK);
+          gp_Pnt2d srcUV = srcHelper->GetNodeUV( srcFace, srcNode,
+                                                 elem->GetNode( helper->WrapIndex(i+1,nbN)), &uvOK);
           gp_Pnt2d   tgtUV = trsf.Transform( srcUV );
           gp_Pnt      tgtP = tgtSurface->Value( tgtUV.X(), tgtUV.Y() );
           SMDS_MeshNode* n = tgtMeshDS->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
           switch ( srcNode->GetPosition()->GetTypeOfPosition() )
           {
           case SMDS_TOP_FACE: {
-            tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), tgtUV.X(), tgtUV.Y() );
+            tgtMeshDS->SetNodeOnFace( n, helper->GetSubShapeID(), tgtUV.X(), tgtUV.Y() );
             break;
           }
           case SMDS_TOP_EDGE: {
-            TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
+            TopoDS_Shape srcEdge = srcHelper->GetSubShapeByNode( srcNode, srcHelper->GetMeshDS() );
             TopoDS_Edge  tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true ));
             double U = Precision::Infinite();
-            helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
+            helper->CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
             tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U );
             break;
           }
           case SMDS_TOP_VERTEX: {
-            TopoDS_Shape srcV = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
+            TopoDS_Shape srcV = srcHelper->GetSubShapeByNode( srcNode, srcHelper->GetMeshDS() );
             TopoDS_Shape tgtV = shape2ShapeMap( srcV, /*isSrc=*/true );
             tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV ));
             break;
@@ -963,8 +961,8 @@ namespace {
       // create a new face (with reversed orientation)
       switch ( nbN )
       {
-      case 3: helper.AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break;
-      case 4: helper.AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break;
+      case 3: helper->AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break;
+      case 4: helper->AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break;
       }
     }  // loop on all mesh faces on srcFace
 
@@ -973,7 +971,7 @@ namespace {
 
   //================================================================================
   /*!
-   * \brief Preform projection in case of quadrilateral faces
+   * \brief Perform projection in case of quadrilateral faces
    */
   //================================================================================
 
@@ -1070,7 +1068,7 @@ namespace {
     //       }
     //       else 
     //       {
-    //         // find XY of src node withing the quadrilateral srcFace
+    //         // find XY of src node within the quadrilateral srcFace
     //         if ( !block.ComputeParameters( SMESH_TNodeXYZ( srcNode ),
     //                                        tgtNodeOrXY.second, srcFaceBID ))
     //           return false;
@@ -1082,8 +1080,7 @@ namespace {
 
     // // as all XY are computed, create tgt nodes and faces
 
-    // SMESH_MesherHelper helper( *tgtMesh );
-    // helper.SetSubShape( tgtFace );
+    // SMESH_MesherHelper helper = *tgtWires[0]->FaceHelper();
     // if ( is1DComputed )
     //   helper.IsQuadraticSubMesh( tgtFace );
     // else
@@ -1091,8 +1088,7 @@ namespace {
     // helper.SetElementsOnShape( true );
     // Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace );
 
-    // SMESH_MesherHelper srcHelper( *srcMesh );
-    // srcHelper.SetSubShape( srcFace );
+    // SMESH_MesherHelper srcHelper = *srcWires[0]->FaceHelper();
 
     // vector< const SMDS_MeshNode* > tgtNodes;
     // gp_XY uv;
@@ -1137,7 +1133,7 @@ namespace {
   {
     SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() );
 
-    if ( helper.IsDistorted2D( faceSM, /*checkUV=*/true ))
+    //if ( helper.IsDistorted2D( faceSM, /*checkUV=*/true ))
     {
       SMESH_MeshEditor editor( helper.GetMesh() );
       SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS();
@@ -1183,240 +1179,6 @@ namespace {
     return true;
   }
 
-  typedef list< pair< const SMDS_MeshNode*, const BRepMesh_Triangle* > > TNodeTriaList;
-
-  //================================================================================
-  /*!
-   * \brief Add in-FACE nodes surrounding a given node to a queue
-   */
-  //================================================================================
-
-  void 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() )
-            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* findTriangle( const gp_XY&                            uv,
-                                         const BRepMesh_Triangle*                bmTria,
-                                         Handle(BRepMesh_DataStructureOfDelaun)& triaDS,
-                                         double                                  bc[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];
-        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<double>::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 Morph mesh on the target face to lie within FACE boundary w/o distortion
-   *
-   * algo:
-   * - make a CDT on the src FACE
-   * - find a triangle containing a src node and get its barycentric coordinates
-   * - move the node to a point with the same barycentric coordinates in a corresponding
-   *   tgt triangle
-   */
-  //================================================================================
-
-  bool morph( SMESH_MesherHelper&             tgtHelper,
-              const TopoDS_Face&              tgtFace,
-              const TopoDS_Face&              srcFace,
-              const TSideVector&              tgtWires,
-              const TSideVector&              srcWires,
-              const TAssocTool::TNodeNodeMap& src2tgtNodes )
-  {
-    if ( srcWires.size() != tgtWires.size() ) return false;
-    if ( srcWires.size() == 1 ) return false; // tmp
-
-    // 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
-
-    // fill boundary points
-    BRepMesh::Array1OfVertexOfDelaun srcVert( 1, 1 + nbP ), tgtVert( 1, 1 + nbP );
-    vector< const SMDS_MeshNode* > bndSrcNodes( nbP + 1 ); bndSrcNodes[0] = 0;
-    BRepMesh_Vertex v( 0, 0, BRepMesh_Frontier );
-    for ( size_t iW = 0; iW < srcWires.size(); ++iW )
-    {
-      const UVPtStructVec& srcPnt = srcWires[iW]->GetUVPtStruct();
-      const UVPtStructVec& tgtPnt = tgtWires[iW]->GetUVPtStruct();
-      if ( srcPnt.size() != tgtPnt.size() ) return false;
-
-      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();
-        srcVert( iP )   = v;
-        v.ChangeCoord() = tgtPnt[i].UV();
-        tgtVert( iP )   = v;
-      }
-    }
-    // triangulate the srcFace in 2D
-    BRepMesh_Delaun delauney( srcVert );
-    Handle(BRepMesh_DataStructureOfDelaun) triaDS = delauney.Result();
-
-    Handle(ShapeAnalysis_Surface) tgtSurface = tgtHelper.GetSurface( tgtFace );
-    SMESHDS_Mesh* srcMesh = srcWires[0]->GetMesh()->GetMeshDS();
-    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
-    SMDS_NodeIteratorPtr nIt = srcMesh->MeshElements( srcFace )->GetNodes();
-    if ( !nIt || !nIt->more() ) return true;
-    while ( nIt->more() )
-      ( srcNode = nIt->next() )->setIsMarked( false );
-
-    // initialize a queue of nodes with starting triangles
-    const int srcFaceID = srcNode->getshapeId();
-    TNodeTriaList noTriQueue;
-    size_t iBndSrcN = 1;
-    for ( ; iBndSrcN < bndSrcNodes.size() &&  noTriQueue.empty();  ++iBndSrcN )
-    {
-      // get a triangle
-      const BRepMesh::ListOfInteger & linkIds = triaDS->LinksConnectedTo( iBndSrcN );
-      const BRepMesh_PairOfIndex &    triaIds = triaDS->ElementsConnectedTo( linkIds.First() );
-      const BRepMesh_Triangle&           tria = triaDS->GetElement( triaIds.Index(1) );
-
-      addCloseNodes( bndSrcNodes[ iBndSrcN ], &tria, srcFaceID, noTriQueue );
-    }
-
-    // Move tgt nodes
-
-    double bc[3]; // barycentric coordinates
-    int    nodeIDs[3];
-    bool   checkUV = true;
-    const SMDS_FacePosition* pos;
-
-    while ( !noTriQueue.empty() )
-    {
-      srcNode = noTriQueue.front().first;
-      bmTria  = noTriQueue.front().second;
-      noTriQueue.pop_front();
-      if ( srcNode->isMarked() )
-        continue;
-      srcNode->setIsMarked( true );
-
-      // find a delauney triangle containing the src node
-      gp_XY uv = tgtHelper.GetNodeUV( srcFace, srcNode, NULL, &checkUV );
-      bmTria = findTriangle( uv, bmTria, triaDS, bc );
-      if ( !bmTria )
-        continue;
-
-      // compute new coordinates for a corresponding tgt node
-      gp_XY uvNew( 0., 0. ), nodeUV;
-      triaDS->ElementNodes( *bmTria, nodeIDs );
-      for ( int i = 0; i < 3; ++i )
-        uvNew += bc[i] * tgtVert( nodeIDs[i]).Coord();
-      gp_Pnt xyz = tgtSurface->Value( uvNew );
-
-      // find and move tgt node
-      TAssocTool::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<SMDS_FacePosition*>( pos )->SetParameters( uvNew.X(), uvNew.Y() );
-
-      addCloseNodes( srcNode, bmTria, srcFaceID, noTriQueue );
-
-      // assure that all src nodes are visited
-      for ( ; iBndSrcN < bndSrcNodes.size() &&  noTriQueue.empty();  ++iBndSrcN )
-      {
-        const BRepMesh::ListOfInteger & linkIds = triaDS->LinksConnectedTo( iBndSrcN );
-        const BRepMesh_PairOfIndex &    triaIds = triaDS->ElementsConnectedTo( linkIds.First() );
-        const BRepMesh_Triangle&           tria = triaDS->GetElement( triaIds.Index(1) );
-        addCloseNodes( bndSrcNodes[ iBndSrcN ], &tria, srcFaceID, noTriQueue );
-      }
-    }
-
-    return true;
-  }
-
   //=======================================================================
   /*
    * Set initial association of VERTEXes for the case of projection
@@ -1541,7 +1303,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
   // get ordered src and tgt EDGEs
   TSideVector srcWires, tgtWires;
   bool is1DComputed = false; // if any tgt EDGE is meshed
-  TError err = getWires( tgtFace, srcFace, tgtMesh, srcMesh,
+  TError err = getWires( tgtFace, srcFace, tgtMesh, srcMesh, &helper,
                          shape2ShapeMap, srcWires, tgtWires, _src2tgtNodes, is1DComputed );
   if ( err && !err->IsOK() )
     return error( err );
@@ -1618,11 +1380,12 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
       TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front();
       TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 );
       reverse = ( ! srcE1.IsSame( srcE1bis ));
-      if ( reverse &&
-           //_sourceHypo->HasVertexAssociation() &&
+      if ( ( reverse || srcE1.Orientation() != srcE1bis.Orientation() ) &&
            nbEdgesInWires.front() > 2 &&
            helper.IsRealSeam( tgtEdges.front() ))
       {
+        if ( srcE1.Orientation() != srcE1bis.Orientation() )
+          reverse = true;
         // projection to a face with seam EDGE; pb is that GetOrderedEdges()
         // always puts a seam EDGE first (if possible) and as a result
         // we can't use only theReverse flag to correctly associate source
@@ -1935,9 +1698,11 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     // boundary, also bad face can be created if EDGEs already discretized
     // --> fix bad faces by smoothing
     // ----------------------------------------------------------------
-    if ( helper.IsDistorted2D( tgtSubMesh, /*checkUV=*/false ))
+    if ( helper.IsDistorted2D( tgtSubMesh, /*checkUV=*/false, &helper ))
     {
-      morph( helper, tgtFace, srcFace, tgtWires, srcWires, _src2tgtNodes );
+      TAssocTool::Morph morph( srcWires );
+      morph.Perform( helper, tgtWires, helper.GetSurface( tgtFace ),
+                     _src2tgtNodes, /*moveAll=*/true );
 
       if ( !fixDistortedFaces( helper, tgtWires ))
         return error("Invalid mesh generated");