Salome HOME
fix file header (comments)
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_2D.cxx
index f1326ad5e7ef8e3eddc651a9c9bf6601ea10db19..a61d64a0e879563d0bd94e58e886a6c1ae67d7aa 100644 (file)
@@ -1,4 +1,4 @@
-//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+//  Copyright (C) 2007-2010  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
@@ -19,6 +19,7 @@
 //
 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
 //  SMESH SMESH : implementaion of SMESH idl descriptions
 // File      : StdMeshers_Projection_2D.cxx
 // Module    : SMESH
 
 #include "StdMeshers_ProjectionSource2D.hxx"
 #include "StdMeshers_ProjectionUtils.hxx"
+#include "StdMeshers_FaceSide.hxx"
 
+#include "SMDS_EdgePosition.hxx"
+#include "SMDS_FacePosition.hxx"
 #include "SMESHDS_Hypothesis.hxx"
 #include "SMESHDS_SubMesh.hxx"
 #include "SMESH_Block.hxx"
+#include "SMESH_Comment.hxx"
 #include "SMESH_Gen.hxx"
 #include "SMESH_Mesh.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_Pattern.hxx"
 #include "SMESH_subMesh.hxx"
 #include "SMESH_subMeshEventListener.hxx"
-#include "SMESH_Comment.hxx"
-#include "SMDS_EdgePosition.hxx"
 
 #include "utilities.h"
 
@@ -50,6 +53,8 @@
 #include <TopExp_Explorer.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <TopoDS.hxx>
+#include <gp_Ax2.hxx>
+#include <gp_Ax3.hxx>
 
 
 using namespace std;
@@ -67,7 +72,7 @@ StdMeshers_Projection_2D::StdMeshers_Projection_2D(int hypId, int studyId, SMESH
   :SMESH_2D_Algo(hypId, studyId, gen)
 {
   _name = "Projection_2D";
-  _shapeType = (1 << TopAbs_FACE);     // 1 bit per shape type
+  _shapeType = (1 << TopAbs_FACE);      // 1 bit per shape type
 
   _compatibleHypothesis.push_back("ProjectionSource2D");
   _sourceHypo = 0;
@@ -130,40 +135,40 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh&
       TopoDS_Shape edge = TAssocTool::GetEdgeByVertices
         ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) );
       if ( edge.IsNull() ||
-           !TAssocTool::IsSubShape( edge, srcMesh ) ||
-           !TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() ))
+           !SMESH_MesherHelper::IsSubShape( edge, srcMesh ) ||
+           !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() ))
       {
         theStatus = HYP_BAD_PARAMETER;
         SCRUTE((edge.IsNull()));
-        SCRUTE((TAssocTool::IsSubShape( edge, srcMesh )));
-        SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() )));
+        SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh )));
+        SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() )));
       }
       else
       {
         // target vertices
         edge = TAssocTool::GetEdgeByVertices
           ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) );
-        if ( edge.IsNull() || !TAssocTool::IsSubShape( edge, tgtMesh ))
+        if ( edge.IsNull() || !SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))
         {
           theStatus = HYP_BAD_PARAMETER;
           SCRUTE((edge.IsNull()));
-          SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh )));
+          SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh )));
         }
         // PAL16203
         else if ( !_sourceHypo->IsCompoundSource() &&
-                  !TAssocTool::IsSubShape( edge, theShape ))
+                  !SMESH_MesherHelper::IsSubShape( edge, theShape ))
         {
           theStatus = HYP_BAD_PARAMETER;
-          SCRUTE((TAssocTool::IsSubShape( edge, theShape )));
+          SCRUTE((SMESH_MesherHelper::IsSubShape( edge, theShape )));
         }
       }
     }
     // check a source face
-    if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) ||
+    if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) ||
          ( srcMesh == tgtMesh && theShape == _sourceHypo->GetSourceFace() ))
     {
       theStatus = HYP_BAD_PARAMETER;
-      SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh )));
+      SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh )));
       SCRUTE((srcMesh == tgtMesh));
       SCRUTE(( theShape == _sourceHypo->GetSourceFace() ));
     }
@@ -177,12 +182,11 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh&
 
 namespace {
 
-
   //================================================================================
   /*!
    * \brief define if a node is new or old
-    * \param node - node to check
-    * \retval bool - true if the node existed before Compute() is called
+   * \param node - node to check
+   * \retval bool - true if the node existed before Compute() is called
    */
   //================================================================================
 
@@ -339,7 +343,7 @@ namespace {
           RETURN_BAD_RESULT("Bad node position type: node " << node->GetID() <<
                             " pos type " << node->GetPosition()->GetTypeOfPosition());
         const SMDS_EdgePosition* pos =
-          static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
+          static_cast<const SMDS_EdgePosition*>(node->GetPosition());
         u2nodes.insert( make_pair( pos->GetUParameter(), node ));
         seamNodes.insert( node );
       }
@@ -356,12 +360,8 @@ namespace {
 
   //================================================================================
   /*!
-   * \brief Preform projection in case if tgtFace.IsPartner( srcFace )
-   *  \param tgtFace - target face
-   *  \param srcFace - source face
-   *  \param tgtMesh - target mesh
-   *  \param srcMesh - source mesh
-   *  \retval bool - true if succeeded
+   * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case
+   * if projection by transformation is possible
    */
   //================================================================================
 
@@ -371,8 +371,99 @@ namespace {
                       SMESH_Mesh *                      srcMesh,
                       const TAssocTool::TShapeShapeMap& shape2ShapeMap)
   {
-    if ( !tgtFace.IsPartner( srcFace ))
-      return false;
+    MESSAGE("projectPartner");
+    const double tol = 1.e-7*srcMesh->GetMeshDS()->getMaxDim();
+
+    gp_Trsf trsf; // transformation to get location of target nodes from source ones
+    if ( tgtFace.IsPartner( srcFace ))
+    {
+      gp_Trsf srcTrsf = srcFace.Location();
+      gp_Trsf tgtTrsf = tgtFace.Location();
+      trsf = srcTrsf.Inverted() * tgtTrsf;
+    }
+    else
+    {
+      // Try to find the transformation
+
+      // make any local coord systems of src and tgt faces
+      vector<gp_Pnt> srcPP, tgtPP; // 3 points on face boundaries to make axes of CS
+      SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace );
+      SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false);
+      srcSM = smIt->next(); // sm of a vertex
+      while ( smIt->more() && srcPP.size() < 3 )
+      {
+        srcSM = smIt->next();
+        SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
+        if ( !srcSmds ) continue;
+        SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
+        while ( nIt->more() )
+        {
+          SMESH_TNodeXYZ p ( nIt->next());
+          bool pOK = false;
+          switch ( srcPP.size() )
+          {
+          case 0: pOK = true; break;
+
+          case 1: pOK = ( srcPP[0].SquareDistance( p ) > 10*tol ); break;
+            
+          case 2:
+            {
+              gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p );
+              // pOK = !p0p1.IsParallel( p0p, tol );
+              pOK = !p0p1.IsParallel( p0p, 3.14/20 ); // angle min 18 degrees
+              break;
+            }
+          }
+          if ( !pOK )
+            continue;
+
+          // find corresponding point on target shape
+          pOK = false;
+          gp_Pnt tgtP;
+          const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape() );
+          if ( tgtShape.ShapeType() == TopAbs_VERTEX )
+          {
+            tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape ));
+            pOK = true;
+            //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl;
+          }
+          else if ( tgtPP.size() > 0 )
+          {
+            if ( SMESHDS_SubMesh* tgtSmds = tgtMesh->GetMeshDS()->MeshElements( tgtShape ))
+            {
+              double srcDist = srcPP[0].Distance( p );
+              double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape ));
+              if (eTol < tol) eTol = tol;
+              SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes();
+              while ( nItT->more() && !pOK )
+              {
+                const SMDS_MeshNode* n = nItT->next();
+                tgtP = SMESH_TNodeXYZ( n );
+                pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol );
+                //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl;
+              }
+            }
+          }
+          if ( !pOK )
+            continue;
+
+          srcPP.push_back( p );
+          tgtPP.push_back( tgtP );
+        }
+      }
+      if ( srcPP.size() != 3 )
+        return false;
+
+      // make transformation
+      gp_Trsf fromTgtCS, toSrcCS; // from/to global CS
+      gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2]));
+      gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2]));
+      toSrcCS  .SetTransformation( gp_Ax3( srcCS ));
+      fromTgtCS.SetTransformation( gp_Ax3( tgtCS ));
+      fromTgtCS.Invert();
+
+      trsf = fromTgtCS * toSrcCS;
+    }
 
     // Fill map of src to tgt nodes with nodes on edges
 
@@ -382,8 +473,6 @@ namespace {
     for ( TopExp_Explorer srcEdge( srcFace, TopAbs_EDGE); srcEdge.More(); srcEdge.Next() )
     {
       const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge.Current() );
-      if ( !tgtEdge.IsPartner( srcEdge.Current() ))
-        return false;
 
       map< double, const SMDS_MeshNode* > srcNodes, tgtNodes;
       if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMesh->GetMeshDS(),
@@ -399,6 +488,30 @@ namespace {
            srcNodes.size() != tgtNodes.size())
         return false;
 
+      if ( !tgtEdge.IsPartner( srcEdge.Current() ))
+      {
+        // check that transformation is OK by three nodes
+        gp_Pnt p0S = SMESH_TNodeXYZ( (srcNodes.begin())  ->second);
+        gp_Pnt p1S = SMESH_TNodeXYZ( (srcNodes.rbegin()) ->second);
+        gp_Pnt p2S = SMESH_TNodeXYZ( (++srcNodes.begin())->second);
+
+        gp_Pnt p0T = SMESH_TNodeXYZ( (tgtNodes.begin())  ->second);
+        gp_Pnt p1T = SMESH_TNodeXYZ( (tgtNodes.rbegin()) ->second);
+        gp_Pnt p2T = SMESH_TNodeXYZ( (++tgtNodes.begin())->second);
+
+        // transform source points, they must coincide with target ones
+        if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ||
+             p1T.SquareDistance( p1S.Transformed( trsf )) > tol ||
+             p2T.SquareDistance( p2S.Transformed( trsf )) > tol )
+        {
+          //cout << "KO trsf, 3 dist: "
+          //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
+          //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
+          //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
+          return false;
+        }
+      }
+
       map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
       map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin();
       for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn)
@@ -407,46 +520,194 @@ namespace {
 
     // Make new faces
 
-    // transformation to get location of target nodes from source ones
-    gp_Trsf srcTrsf = srcFace.Location();
-    gp_Trsf tgtTrsf = tgtFace.Location();
-    gp_Trsf trsf = srcTrsf.Inverted() * tgtTrsf;
-
     // prepare the helper adding quadratic elements if necessary
     SMESH_MesherHelper helper( *tgtMesh );
+    helper.SetSubShape( tgtFace );
     helper.IsQuadraticSubMesh( tgtFace );
     helper.SetElementsOnShape( true );
 
+    SMESH_MesherHelper srcHelper( *srcMesh );
+    srcHelper.SetSubShape( srcFace );
+
     const SMDS_MeshNode* nullNode = 0;
 
     SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
     SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
+    vector< const SMDS_MeshNode* > tgtNodes;
     while ( elemIt->more() ) // loop on all mesh faces on srcFace
     {
       const SMDS_MeshElement* elem = elemIt->next();
-      vector< const SMDS_MeshNode* > tgtFaceNodes;
-      tgtFaceNodes.reserve( elem->NbNodes() );
-      SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
-      while ( nodeIt->more() ) // loop on nodes of the source element
+      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 = (const SMDS_MeshNode*) nodeIt->next();
+        const SMDS_MeshNode* srcNode = elem->GetNode(i);
         srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
         if ( srcN_tgtN->second == nullNode )
         {
           // create a new node
           gp_Pnt tgtP = gp_Pnt(srcNode->X(),srcNode->Y(),srcNode->Z()).Transformed( trsf );
-          srcN_tgtN->second = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+          SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+          srcN_tgtN->second = n;
+
+          gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
+                                                elem->GetNode( helper.WrapIndex(i+1,nbN)));
+          n->SetPosition( new SMDS_FacePosition( srcUV.X(), srcUV.Y() ));
         }
-        tgtFaceNodes.push_back( srcN_tgtN->second );
+        tgtNodes[i] = srcN_tgtN->second;
       }
       // create a new face (with reversed orientation)
-      if ( tgtFaceNodes.size() == 3 )
-        helper.AddFace( tgtFaceNodes[0],tgtFaceNodes[2],tgtFaceNodes[1]);
-      else
-        helper.AddFace( tgtFaceNodes[0],tgtFaceNodes[3],tgtFaceNodes[2],tgtFaceNodes[1]);
+      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;
+      }
     }
     return true;
-  }
+
+  } //   bool projectPartner()
+
+  //================================================================================
+  /*!
+   * \brief Preform projection in case if the faces are similar in 2D space
+   */
+  //================================================================================
+
+  bool projectBy2DSimilarity(const TopoDS_Face&                tgtFace,
+                             const TopoDS_Face&                srcFace,
+                             SMESH_Mesh *                      tgtMesh,
+                             SMESH_Mesh *                      srcMesh,
+                             const TAssocTool::TShapeShapeMap& shape2ShapeMap)
+  {
+    // 1) Preparation
+
+    // get ordered src EDGEs
+    TError err;
+    TSideVector srcWires =
+      StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*theIgnoreMediumNodes = */false, err);
+    if ( err && !err->IsOK() )
+      return false;
+
+    // make corresponding sequence of tgt EDGEs
+    TSideVector tgtWires( srcWires.size() );
+    for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
+    {
+      list< TopoDS_Edge > tgtEdges;
+      StdMeshers_FaceSidePtr srcWire = srcWires[iW];
+      for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
+        tgtEdges.push_back( TopoDS::Edge( shape2ShapeMap( srcWire->Edge( iE ))));
+
+      tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
+                                                     /*theIsForward = */ true,
+                                                     /*theIgnoreMediumNodes = */false));
+      if ( srcWires[iW]->GetUVPtStruct().size() !=
+           tgtWires[iW]->GetUVPtStruct().size())
+        return false;
+    }
+
+    // 2) Find transformation
+
+    gp_Trsf2d trsf;
+    {
+      // get ordered nodes data
+      const vector<UVPtStruct>& srcUVs = srcWires[0]->GetUVPtStruct();
+      const vector<UVPtStruct>& tgtUVs = tgtWires[0]->GetUVPtStruct();
+
+      // get 2 pairs of corresponding UVs
+      gp_XY srcP0( srcUVs[0].u, srcUVs[0].v );
+      gp_XY srcP1( srcUVs[1].u, srcUVs[1].v );
+      gp_XY tgtP0( tgtUVs[0].u, tgtUVs[0].v );
+      gp_XY tgtP1( tgtUVs[1].u, tgtUVs[1].v );
+
+      // make transformation
+      gp_Trsf2d fromTgtCS, toSrcCS; // from/to global CS
+      gp_Ax2d srcCS( srcP0, gp_Vec2d( srcP0, srcP1 ));
+      gp_Ax2d tgtCS( tgtP0, gp_Vec2d( tgtP0, tgtP1 ));
+      toSrcCS  .SetTransformation( srcCS );
+      fromTgtCS.SetTransformation( tgtCS );
+      fromTgtCS.Invert();
+
+      trsf = fromTgtCS * toSrcCS;
+
+      // check transformation
+      const double tol = 1e-5 * gp_Vec2d( srcP0, srcP1 ).Magnitude();
+      const int nbCheckPnt = Min( 10, srcUVs.size()-2 );
+      const int dP = ( srcUVs.size()-2 ) / nbCheckPnt;
+      for ( unsigned iP = 2; iP < srcUVs.size(); iP += dP )
+      {
+        gp_Pnt2d srcUV( srcUVs[iP].u, srcUVs[iP].v );
+        gp_Pnt2d tgtUV( tgtUVs[iP].u, tgtUVs[iP].v );
+        gp_Pnt2d tgtUV2 = srcUV.Transformed( trsf );
+        if ( tgtUV.Distance( tgtUV2 ) > tol )
+          return false;
+      }
+    }
+
+    // 3) Projection
+
+    typedef map<const SMDS_MeshNode* , const SMDS_MeshNode*, TIDCompare> TN2NMap;
+    TN2NMap src2tgtNodes;
+    TN2NMap::iterator srcN_tgtN;
+
+    // fill src2tgtNodes in with nodes on EDGEs
+    for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
+    {
+      const vector<UVPtStruct>& srcUVs = srcWires[iW]->GetUVPtStruct();
+      const vector<UVPtStruct>& tgtUVs = tgtWires[iW]->GetUVPtStruct();
+      for ( unsigned i = 0; i < srcUVs.size(); ++i )
+        src2tgtNodes.insert( make_pair( srcUVs[i].node, tgtUVs[i].node ));
+    }
+
+    // make elements
+    SMESH_MesherHelper helper( *tgtMesh );
+    helper.SetSubShape( tgtFace );
+    helper.IsQuadraticSubMesh( tgtFace );
+    helper.SetElementsOnShape( true );
+    Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace );
+    
+    SMESH_MesherHelper srcHelper( *srcMesh );
+    srcHelper.SetSubShape( srcFace );
+
+    const SMDS_MeshNode* nullNode = 0;
+
+    SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
+    SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
+    vector< const SMDS_MeshNode* > tgtNodes;
+    bool uvOK;
+    while ( elemIt->more() ) // loop on all mesh faces on srcFace
+    {
+      const SMDS_MeshElement* elem = elemIt->next();
+      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);
+        srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
+        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 tgtUV = srcUV.Transformed( trsf );
+          gp_Pnt   tgtP  = tgtSurface->Value( tgtUV.X(), tgtUV.Y() );
+          SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+          n->SetPosition( new SMDS_FacePosition( tgtUV.X(), tgtUV.Y() ));
+          srcN_tgtN->second = n;
+        }
+        tgtNodes[i] = srcN_tgtN->second;
+      }
+      // 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;
+      }
+    }
+    return true;
+
+  } // bool projectBy2DSimilarity()
+
 
 } // namespace
 
@@ -458,6 +719,7 @@ namespace {
 
 bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
 {
+  MESSAGE("Projection_2D Compute");
   if ( !_sourceHypo )
     return false;
 
@@ -504,6 +766,9 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
   if ( projectPartner( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap ))
     return true;
 
+  if ( projectBy2DSimilarity( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap ))
+    return true;
+
   // --------------------
   // Prepare to mapping 
   // --------------------
@@ -545,9 +810,9 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() );
   TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1 ));
 
-  if ( !TAssocTool::IsSubShape( srcV1, srcFace ))
+  if ( !SMESH_MesherHelper::IsSubShape( srcV1, srcFace ))
     RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->());
-  if ( !TAssocTool::IsSubShape( tgtV1, tgtFace ))
+  if ( !SMESH_MesherHelper::IsSubShape( tgtV1, tgtFace ))
     RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->());
 
   // try to find out orientation by order of edges
@@ -644,7 +909,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
       }
       case  SMDS_TOP_EDGE:   {
         const SMDS_EdgePosition* pos =
-          static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
+          static_cast<const SMDS_EdgePosition*>(node->GetPosition());
         pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
         break;
       }
@@ -748,8 +1013,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
 //=======================================================================
 
 bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh& theMesh,
-                                       const TopoDS_Shape& theShape,
-                                       MapShapeNbElems& aResMap)
+                                        const TopoDS_Shape& theShape,
+                                        MapShapeNbElems& aResMap)
 {
   if ( !_sourceHypo )
     return false;
@@ -785,29 +1050,29 @@ bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh& theMesh,
     return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
 
 
-  std::vector<int> aVec(17);
-  for(int i=0; i<17; i++) aVec[i] = 0;
+  std::vector<int> aVec(SMDSEntity_Last);
+  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i] = 0;
 
-  aVec[0] = srcSubMesh->GetSubMeshDS()->NbNodes();
+  aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes();
 
   //bool quadratic = false;
   SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
   while ( elemIt->more() ) {
     const SMDS_MeshElement* E  = elemIt->next();
     if( E->NbNodes()==3 ) {
-      aVec[3]++;
+      aVec[SMDSEntity_Triangle]++;
     }
     else if( E->NbNodes()==4 ) {
-      aVec[5]++;
+      aVec[SMDSEntity_Quadrangle]++;
     }
     else if( E->NbNodes()==6 && E->IsQuadratic() ) {
-      aVec[4]++;
+      aVec[SMDSEntity_Quad_Triangle]++;
     }
     else if( E->NbNodes()==8 && E->IsQuadratic() ) {
-      aVec[6]++;
+      aVec[SMDSEntity_Quad_Quadrangle]++;
     }
     else {
-      aVec[7]++;
+      aVec[SMDSEntity_Polygon]++;
     }
   }