Salome HOME
Projection 2D failure due to incorrect detection of distorted result faces
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_2D.cxx
index 78c16a4ebd35632b268b396ad0999bb8a545c9a6..7b3d1e1e1f157ff9157f722b9978e02af6f1dcdd 100644 (file)
@@ -568,6 +568,7 @@ namespace {
       vector< gp_XYZ > srcPnts, tgtPnts;
       srcPnts.reserve( totNbSeg );
       tgtPnts.reserve( totNbSeg );
+      gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 );
       for ( size_t iW = 0; iW < srcWires.size(); ++iW )
       {
         const double minSegLen = srcWires[iW]->Length() / totNbSeg;
@@ -584,6 +585,8 @@ namespace {
             tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() );
             srcU += srcDu;
             tgtU += tgtDu;
+            srcBC += srcPnts.back();
+            tgtBC += tgtPnts.back();
           }
         }
       }
@@ -596,6 +599,8 @@ namespace {
       const int nbTestPnt = 20;
       const size_t  iStep = Max( 1, int( srcPnts.size() / nbTestPnt ));
       // check boundary
+      gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() );
+      trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol );
       for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep )
       {
         gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] );
@@ -606,8 +611,8 @@ namespace {
       {
         BRepAdaptor_Surface srcSurf( srcFace );
         gp_Pnt srcP =
-          srcSurf.Value( 0.5 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ),
-                         0.5 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() ));
+          srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ),
+                         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 );
@@ -706,7 +711,12 @@ namespace {
 
     if ( !tgtFace.IsPartner( srcFace ) )
     {
+      SMESH_MesherHelper edgeHelper( *tgtMesh );
+      edgeHelper.ToFixNodeParameters( true );
+      helper.ToFixNodeParameters( true );
+
       int nbOkPos = 0;
+      bool toCheck = true;
       const double tol2d = 1e-12;
       srcN_tgtN = src2tgtNodes.begin();
       for ( ; srcN_tgtN != src2tgtNodes.end(); ++srcN_tgtN )
@@ -716,22 +726,20 @@ 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 )) &&
-              (( uv - uvBis ).SquareModulus() < tol2d )    &&
-              ( ++nbOkPos > 10 ))
-            return true;
+              (( uv - uvBis ).SquareModulus() < tol2d ))
+            ++nbOkPos;
           else
-            nbOkPos = 0;
+            nbOkPos = -((int) src2tgtNodes.size() );
           break;
         }
         case SMDS_TOP_EDGE:
         {
           const TopoDS_Edge & tgtE = TopoDS::Edge( tgtMeshDS->IndexToShape( n->getshapeId() ));
-          double u = helper.GetNodeU( tgtE, n ), uBis = u;
-          if (( !helper.CheckNodeU( tgtE, n, u, tol )) ||
-              (( u - uBis ) < tol2d ))
-            nbOkPos = 0;
+          edgeHelper.SetSubShape( tgtE );
+          edgeHelper.GetNodeU( tgtE, n, 0, &toCheck );
           break;
         }
         default:;
@@ -885,10 +893,9 @@ namespace {
           case SMDS_TOP_EDGE: {
             TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
             TopoDS_Edge  tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true ));
-            tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ));
-            double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode );
+            double U = Precision::Infinite();
             helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
-            n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U )));
+            tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U );
             break;
           }
           case SMDS_TOP_VERTEX: {
@@ -919,80 +926,25 @@ namespace {
    */
   //================================================================================
 
-  void fixDistortedFaces( SMESH_MesherHelper& helper,
-                          TSideVector&        )
+  bool fixDistortedFaces( SMESH_MesherHelper& helper,
+                          TSideVector&        tgtWires )
   {
-    // Detect bad faces
-
-    bool haveBadFaces = false;
-
-    const TopoDS_Face&  F = TopoDS::Face( helper.GetSubShape() );
-    SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F );
-    if ( !smDS || smDS->NbElements() == 0 ) return;
-
-    SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
-    double prevArea2D = 0;
-    vector< const SMDS_MeshNode* > nodes;
-    vector< gp_XY >                uv;
-    while ( faceIt->more() && !haveBadFaces )
-    {
-      const SMDS_MeshElement* face = faceIt->next();
-
-      // get nodes
-      nodes.resize( face->NbCornerNodes() );
-      SMDS_MeshElement::iterator n = face->begin_nodes();
-      for ( size_t i = 0; i < nodes.size(); ++n, ++i )
-        nodes[ i ] = *n;
-
-      // avoid elems on degenarate shapes as UV on them can be wrong
-      if ( helper.HasDegeneratedEdges() )
-      {
-        bool isOnDegen = false;
-        for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i )
-          isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() );
-        if ( isOnDegen )
-          continue;
-      }
-      // prepare to getting UVs
-      const SMDS_MeshNode* inFaceNode = 0;
-      if ( helper.HasSeam() )
-        for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i )
-          if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() ))
-            inFaceNode = nodes[ i ];
-
-      // get UVs
-      uv.resize( nodes.size() );
-      for ( size_t i = 0; i < nodes.size(); ++i )
-        uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode );
-
-      // compare orientation of triangles
-      for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT )
-      {
-        gp_XY v1 = uv[ iT+1 ] - uv[ 0 ];
-        gp_XY v2 = uv[ iT+2 ] - uv[ 0 ];
-        double area2D = v2 ^ v1;
-        if (( haveBadFaces = ( area2D * prevArea2D < 0 )))
-          break;
-        prevArea2D = area2D;
-      }
-    }
+    SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() );
 
-    // Fix faces
-
-    if ( haveBadFaces )
+    if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false ))
     {
       SMESH_MeshEditor editor( helper.GetMesh() );
+      SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS();
+      const TopoDS_Face&  F = TopoDS::Face( faceSM->GetSubShape() );
 
       TIDSortedElemSet faces;
+      SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
       for ( faceIt = smDS->GetElements(); faceIt->more(); )
         faces.insert( faces.end(), faceIt->next() );
 
       // choose smoothing algo
       //SMESH_MeshEditor:: SmoothMethod algo = SMESH_MeshEditor::CENTROIDAL;
       bool isConcaveBoundary = false;
-      TError err;
-      TSideVector tgtWires =
-        StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(),/*skipMediumNodes=*/0, err);
       for ( size_t iW = 0; iW < tgtWires.size() && !isConcaveBoundary; ++iW )
       {
         TopoDS_Edge prevEdge = tgtWires[iW]->Edge( tgtWires[iW]->NbEdges() - 1 );
@@ -1017,7 +969,12 @@ namespace {
       set<const SMDS_MeshNode*> fixedNodes;
       editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10,
                      /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar);
+
+      helper.ToFixNodeParameters( true );
+
+      return !helper.IsDistorted2D( faceSM, /*checkUV=*/true );
     }
+    return true;
   }
 
 } // namespace
@@ -1100,25 +1057,28 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
   if ( err && !err->IsOK() )
     return error( err );
 
-  bool done = false;
+  bool projDone = false;
 
if ( !done )
 if ( !projDone )
   {
     // try to project from the same face with different location
-    done = projectPartner( tgtFace, srcFace, tgtWires, srcWires,
-                           shape2ShapeMap, _src2tgtNodes, is1DComputed );
+    projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires,
+                               shape2ShapeMap, _src2tgtNodes, is1DComputed );
   }
-  if ( !done )
+  if ( !projDone )
   {
     // projection in case if the faces are similar in 2D space
-    done = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
-                                  shape2ShapeMap, _src2tgtNodes, is1DComputed);
+    projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
+                                      shape2ShapeMap, _src2tgtNodes, is1DComputed);
   }
 
   SMESH_MesherHelper helper( theMesh );
   helper.SetSubShape( tgtFace );
 
-  if ( !done )
+  // it will remove mesh built on edges and vertices in failure case
+  MeshCleaner cleaner( tgtSubMesh );
+
+  if ( !projDone )
   {
     _src2tgtNodes.clear();
     // --------------------
@@ -1218,10 +1178,6 @@ 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");
 
-    // it will remove mesh built by pattern mapper on edges and vertices
-    // in failure case
-    MeshCleaner cleaner( tgtSubMesh );
-
     // -------------------------------------------------------------------------
     // mapper doesn't take care of nodes already existing on edges and vertices,
     // so we must merge nodes created by it with existing ones
@@ -1381,14 +1337,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() )
       return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces");
 
-
-    // ----------------------------------------------------------------
-    // The mapper can create distorted faces by placing nodes out of the FACE
-    // boundary -- fix bad faces by smoothing
-    // ----------------------------------------------------------------
-
-    fixDistortedFaces( helper, tgtWires );
-
     // ----------------------------------------------------------------
     // The mapper can't create quadratic elements, so convert if needed
     // ----------------------------------------------------------------
@@ -1407,11 +1355,18 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
       editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false);
     }
 
-    cleaner.Release(); // not to remove mesh
-
   } // end of projection using Pattern mapping
 
 
+  if ( !projDone || is1DComputed )
+    // ----------------------------------------------------------------
+    // The mapper can create distorted faces by placing nodes out of the FACE
+    // boundary, also bad face can be created if EDGEs already discretized
+    // --> fix bad faces by smoothing
+    // ----------------------------------------------------------------
+    if ( !fixDistortedFaces( helper, tgtWires ))
+      return error("Invalid mesh generated");
+
   // ---------------------------
   // Check elements orientation
   // ---------------------------
@@ -1457,6 +1412,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape&
     }
   }
 
+  cleaner.Release(); // not to remove mesh
+
   return true;
 }