Salome HOME
Fix regressions caused by improvements
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_2D.cxx
index af482db570edb7349bba6a14356b301781b18a18..87572c18f40434ceaa3e70cdc6b57de13e21dd5b 100644 (file)
@@ -58,6 +58,7 @@
 #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>
@@ -393,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 ));
   }
 
   //================================================================================
@@ -439,32 +441,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
@@ -474,7 +451,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 );
@@ -485,7 +461,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
           {
@@ -501,56 +478,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() )
-            {
-              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
+            vector< const SMDS_MeshNode* >::iterator tn = tgtNodes.begin();
+            //if ( srcWire->Edge(iE).Orientation() == tgtWire->Edge(iE).Orientation() )
             {
-              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();
@@ -667,7 +646,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 );
@@ -952,10 +931,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;
+  }
+
+  //================================================================================
+  /*!
+   * \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 true;
 
-  } // bool projectBy2DSimilarity(...)
+  } // bool projectQuads(...)
 
   //================================================================================
   /*!
@@ -1126,6 +1260,12 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
                                       shape2ShapeMap, _src2tgtNodes, is1DComputed);
   }
+  if ( !projDone )
+  {
+    // projection in case of quadrilateral faces
+    // projDone = projectQuads( tgtFace, srcFace, tgtWires, srcWires,
+    //                          shape2ShapeMap, _src2tgtNodes, is1DComputed);
+  }
 
   helper.SetSubShape( tgtFace );