Salome HOME
IPAL52980: Wire Discretization with Table density fails
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_2D.cxx
index 853875c5d2d300c895ce88d4cb94b6884c6f4a26..0e7d3ff2065732b48bbf6f251986c91d3d0c87cd 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  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
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <TopTools_MapOfShape.hxx>
 #include <TopoDS.hxx>
+#include <TopoDS_Solid.hxx>
 #include <gp_Ax2.hxx>
 #include <gp_Ax3.hxx>
+#include <gp_GTrsf.hxx>
 
 
 using namespace std;
@@ -392,15 +394,16 @@ namespace {
   {
     double f,l;
     Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( E1, F, f, l );
-    gp_Pnt2d uvLast1 = c1->Value( E1.Orientation() == TopAbs_REVERSED ? f : l );
+    gp_Pnt2d uvFirst1 = c1->Value( f );
+    gp_Pnt2d uvLast1  = c1->Value( l );
 
     Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( E2, F, f, l );
-    gp_Pnt2d uvFirst2 = c2->Value( f );
-    gp_Pnt2d uvLast2  = c2->Value( l );
-    double tol2 = 1e-5 * uvLast2.SquareDistance( uvFirst2 );
+    gp_Pnt2d uvFirst2 = c2->Value( E2.Orientation() == TopAbs_REVERSED ? l : f );
+    double tol2 = Max( Precision::PConfusion() * Precision::PConfusion(),
+                       1e-5 * uvLast1.SquareDistance( uvFirst1 ));
 
-    return (( uvLast1.SquareDistance( uvFirst2 ) < tol2 ) ||
-            ( uvLast1.SquareDistance( uvLast2 ) < tol2 ));
+    return (( uvFirst2.SquareDistance( uvFirst1 ) < tol2 ) ||
+            ( uvFirst2.SquareDistance( uvLast1  ) < tol2 ));
   }
 
   //================================================================================
@@ -420,15 +423,13 @@ namespace {
                   TAssocTool::TNodeNodeMap&          src2tgtNodes,
                   bool&                              is1DComputed)
   {
-    SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
-    SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
-
     src2tgtNodes.clear();
 
     // get ordered src EDGEs
     TError err;
     srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err);
-    if ( err && !err->IsOK() || srcWires.empty() )
+    if (( err && !err->IsOK() ) ||
+        ( srcWires.empty() ))
       return err;
 
     SMESH_MesherHelper srcHelper( *srcMesh );
@@ -438,32 +439,7 @@ namespace {
     tgtWires.resize( srcWires.size() );
     for ( size_t iW = 0; iW < srcWires.size(); ++iW )
     {
-      // 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
@@ -473,7 +449,6 @@ 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 );
@@ -484,7 +459,8 @@ namespace {
           {
             list< TopoDS_Edge >::iterator eIt = tgtEdges.begin();
             std::advance( eIt, index-1 );
-            eIt->Reverse();
+            if ( are2dConnected( tgtEdges.back(), *eIt, tgtFace ))
+              eIt->Reverse();
           }
           else
           {
@@ -500,56 +476,58 @@ namespace {
             tgtE = nE.second;
         }
         tgtEdges.push_back( tgtE );
+      }
 
+      tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
+                                                     /*theIsForward = */ true,
+                                                     /*theIgnoreMediumNodes = */false));
+      StdMeshers_FaceSidePtr tgtWire = tgtWires[ iW ];
 
-        // Fill map of src to tgt nodes with nodes on edges
+      // Fill map of src to tgt nodes with nodes on edges
 
-        if ( srcMesh->GetSubMesh( srcE )->IsEmpty() ||
-             tgtMesh->GetSubMesh( tgtE )->IsEmpty() )
+      for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
+      {
+        if ( srcMesh->GetSubMesh( srcWire->Edge(iE) )->IsEmpty() ||
+             tgtMesh->GetSubMesh( tgtWire->Edge(iE) )->IsEmpty() )
         {
           // add nodes on VERTEXes for a case of not meshes EDGEs
-          const TopoDS_Shape&  srcV = SMESH_MesherHelper::IthVertex( 0, srcE );
-          const TopoDS_Shape&  tgtV = shape2ShapeMap( srcV, /*isSrc=*/true );
-          const SMDS_MeshNode* srcN = SMESH_Algo::VertexNode( TopoDS::Vertex( srcV ), srcMeshDS );
-          const SMDS_MeshNode* tgtN = SMESH_Algo::VertexNode( TopoDS::Vertex( tgtV ), tgtMeshDS );
+          const SMDS_MeshNode* srcN = srcWire->VertexNode( iE );
+          const SMDS_MeshNode* tgtN = tgtWire->VertexNode( iE );
           if ( srcN && tgtN )
             src2tgtNodes.insert( make_pair( srcN, tgtN ));
         }
         else
         {
-          const bool skipMediumNodes = true;
-          map< double, const SMDS_MeshNode* > srcNodes, 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");
+          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);
+          
+          vector< const SMDS_MeshNode* > srcNodes = srcEdge.GetOrderedNodes();
+          vector< const SMDS_MeshNode* > tgtNodes = tgtEdge.GetOrderedNodes();
 
           if (( srcNodes.size() != tgtNodes.size() ) && tgtNodes.size() > 0 )
             return SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH,
                                             "Different number of nodes on edges");
           if ( !tgtNodes.empty() )
           {
-            map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
-            if ( srcE.Orientation() == tgtE.Orientation() )
+            vector< const SMDS_MeshNode* >::iterator tn = tgtNodes.begin();
+            //if ( srcWire->Edge(iE).Orientation() == tgtWire->Edge(iE).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 ));
+              vector< const SMDS_MeshNode* >::iterator sn = srcNodes.begin();
+              for ( ; tn != tgtNodes.end(); ++tn, ++sn)
+                src2tgtNodes.insert( make_pair( *sn, *tn ));
             }
+            // else
+            // {
+            //   vector< const SMDS_MeshNode* >::reverse_iterator sn = srcNodes.rbegin();
+            //   for ( ; tn != tgtNodes.end(); ++tn, ++sn)
+            //     src2tgtNodes.insert( make_pair( *sn, *tn ));
+            // }
             is1DComputed = true;
           }
         }
       } // loop on EDGEs of a WIRE
 
-      tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
-                                                     /*theIsForward = */ true,
-                                                     /*theIgnoreMediumNodes = */false));
     } // loop on WIREs
 
     return TError();
@@ -580,18 +558,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() );
-      if ( tgtP.Distance( trsf.Transform( srcP )) > tol )
-        trsf.Set( tgtTrsf.Inverted() * srcTrsf );
+      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
 
@@ -605,7 +589,7 @@ namespace {
         const double minSegLen = srcWires[iW]->Length() / totNbSeg;
         for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE )
         {
-          int nbSeg    = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen ));
+          size_t nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen ));
           double srcU  = srcWires[iW]->FirstParameter( iE );
           double tgtU  = tgtWires[iW]->FirstParameter( iE );
           double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg;
@@ -626,7 +610,6 @@ namespace {
 
       // check trsf
 
-      bool trsfIsOK = true;
       const int nbTestPnt = 20;
       const size_t  iStep = Max( 1, int( srcPnts.size() / nbTestPnt ));
       // check boundary
@@ -661,7 +644,7 @@ namespace {
     // Make new faces
 
     // prepare the helper to adding quadratic elements if necessary
-    helper.SetSubShape( tgtFace );
+    //helper.SetSubShape( tgtFace );
     helper.IsQuadraticSubMesh( tgtFace );
 
     SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace );
@@ -838,14 +821,14 @@ namespace {
         // find trsf
         const int totNbSeg = 50;
         vector< gp_XY > srcPnts, tgtPnts;
-        srcPnts.resize( totNbSeg );
-        tgtPnts.resize( totNbSeg );
+        srcPnts.reserve( totNbSeg );
+        tgtPnts.reserve( totNbSeg );
         for ( size_t iW = 0; iW < srcWires.size(); ++iW )
         {
           const double minSegLen = srcWires[iW]->Length() / totNbSeg;
           for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE )
           {
-            int nbSeg    = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen ));
+            size_t nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen ));
             double srcU  = srcWires[iW]->FirstParameter( iE );
             double tgtU  = tgtWires[iW]->FirstParameter( iE );
             double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg;
@@ -935,6 +918,7 @@ namespace {
             tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV ));
             break;
           }
+          default:;
           }
           srcN_tgtN->second = n;
         }
@@ -946,10 +930,165 @@ 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;
       }
-    }
+    }  // loop on all mesh faces on srcFace
+
     return true;
+  }
 
-  } // bool projectBy2DSimilarity(...)
+  //================================================================================
+  /*!
+   * \brief Preform projection in case of quadrilateral faces
+   */
+  //================================================================================
+
+  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)
+  {
+    // 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
+
+    // // load EDGEs to SMESH_Block
+
+    // 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) );
+
+    // 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* elem = elemIt->next();
+    //   TFaceConn& tgtNodes = newFacesVec[ iFaceSrc++ ];
+
+    //   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 );
+
+    // 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 )
+    //   {
+    //     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
+    //   }
+    //   switch ( tgtNodes.size() )
+    //   {
+    //   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 false; //true;
+
+  } // bool projectQuads(...)
 
   //================================================================================
   /*!
@@ -1008,6 +1147,51 @@ namespace {
     return true;
   }
 
+  //=======================================================================
+  /*
+   * Set initial association of VERTEXes for the case of projection
+   * from a quadrangle FACE to a closed FACE, where opposite src EDGEs
+   * have different nb of segments
+   */
+  //=======================================================================
+
+  void initAssoc4Quad2Closed(const TopoDS_Shape&          tgtFace,
+                             SMESH_MesherHelper&          tgtHelper,
+                             const TopoDS_Shape&          srcFace,
+                             SMESH_Mesh*                  srcMesh,
+                             TAssocTool::TShapeShapeMap & assocMap)
+  {
+    if ( !tgtHelper.HasRealSeam() || srcFace.ShapeType() != TopAbs_FACE )
+      return; // no seam edge
+    list< TopoDS_Edge > tgtEdges, srcEdges;
+    list< int > tgtNbEW, srcNbEW;
+    int tgtNbW = SMESH_Block::GetOrderedEdges( TopoDS::Face( tgtFace ), tgtEdges, tgtNbEW );
+    int srcNbW = SMESH_Block::GetOrderedEdges( TopoDS::Face( srcFace ), srcEdges, srcNbEW );
+    if ( tgtNbW != 1 || srcNbW != 1 ||
+         tgtNbEW.front() != 4 || srcNbEW.front() != 4 )
+      return; // not quads
+
+    int srcNbSeg[4];
+    list< TopoDS_Edge >::iterator edgeS = srcEdges.begin(), edgeT = tgtEdges.begin();
+    for ( int i = 0; edgeS != srcEdges.end(); ++i, ++edgeS )
+      if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( *edgeS ))
+        srcNbSeg[ i ] = sm->NbNodes();
+      else
+        return; // not meshed
+    if ( srcNbSeg[0] == srcNbSeg[2] && srcNbSeg[1] == srcNbSeg[3] )
+      return; // same nb segments
+    if ( srcNbSeg[0] != srcNbSeg[2] && srcNbSeg[1] != srcNbSeg[3] )
+      return; // all different nb segments
+
+    edgeS = srcEdges.begin();
+    if ( srcNbSeg[0] != srcNbSeg[2] )
+      ++edgeS;
+    TAssocTool::InsertAssociation( tgtHelper.IthVertex( 0,*edgeT ),
+                                   tgtHelper.IthVertex( 0,*edgeS ), assocMap );
+    TAssocTool::InsertAssociation( tgtHelper.IthVertex( 1,*edgeT ),
+                                   tgtHelper.IthVertex( 1,*edgeS ), assocMap );
+  }
+
 } // namespace
 
 
@@ -1020,7 +1204,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
 {
   _src2tgtNodes.clear();
 
-  MESSAGE("Projection_2D Compute");
   if ( !_sourceHypo )
     return false;
 
@@ -1039,8 +1222,12 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
   TopoDS_Face   tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
   TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
 
+  helper.SetSubShape( tgtFace );
+
   TAssocTool::TShapeShapeMap shape2ShapeMap;
   TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap );
+  if ( shape2ShapeMap.IsEmpty() )
+    initAssoc4Quad2Closed( tgtFace, helper, srcShape, srcMesh, shape2ShapeMap );
   if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
                                              shape2ShapeMap)  ||
        !shape2ShapeMap.IsBound( tgtFace ))
@@ -1118,10 +1305,15 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
   {
     // projection in case if the faces are similar in 2D space
     projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
-                                      shape2ShapeMap, _src2tgtNodes, is1DComputed);
+                                      shape2ShapeMap, _src2tgtNodes, is1DComputed );
+  }
+  if ( !projDone )
+  {
+    // projection in case of quadrilateral faces
+    // NOT IMPLEMENTED, returns false
+    projDone = projectQuads( tgtFace, srcFace, tgtWires, srcWires,
+                             shape2ShapeMap, _src2tgtNodes, is1DComputed);
   }
-
-  helper.SetSubShape( tgtFace );
 
   // it will remove mesh built on edges and vertices in failure case
   MeshCleaner cleaner( tgtSubMesh );
@@ -1247,10 +1439,19 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
         }
       }
     }
-    else if ( nbEdgesInWires.front() == 1 )
+    else if ( nbEdgesInWires.front() == 1 ) // a sole edge in a wire
     {
-      // TODO::Compare orientation of curves in a sole edge
-      //RETURN_BAD_RESULT("Not implemented case");
+      TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front();
+      for ( size_t iW = 0; iW < srcWires.size(); ++iW )
+      {
+        StdMeshers_FaceSidePtr srcWire = srcWires[iW];
+        for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
+          if ( srcE1.IsSame( srcWire->Edge( iE )))
+          {
+            reverse = ( tgtE1.Orientation() != tgtWires[iW]->Edge( iE ).Orientation() );
+            break;
+          }
+      }
     }
     else
     {
@@ -1283,6 +1484,9 @@ 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");
 
+  } // end of projection using Pattern mapping
+
+  {
     // -------------------------------------------------------------------------
     // mapper doesn't take care of nodes already existing on edges and vertices,
     // so we must merge nodes created by it with existing ones
@@ -1322,7 +1526,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
         continue; // do not treat sm of degen VERTEX
       }
 
-      // Sort new and old nodes of a submesh separately
+      // Sort new and old nodes of a sub-mesh separately
 
       bool isSeam = helper.IsRealSeam( sm->GetId() );
 
@@ -1446,6 +1650,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     // The mapper can't create quadratic elements, so convert if needed
     // ----------------------------------------------------------------
 
+    SMDS_ElemIteratorPtr faceIt;
     faceIt         = srcSubMesh->GetSubMeshDS()->GetElements();
     bool srcIsQuad = faceIt->next()->IsQuadratic();
     faceIt         = tgtSubMesh->GetSubMeshDS()->GetElements();
@@ -1459,8 +1664,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
 
       editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false);
     }
-
-  } // end of projection using Pattern mapping
+  } // end of coincident nodes and quadratic elements treatment
 
 
   if ( !projDone || is1DComputed )