Salome HOME
23404: EDF 14011 - Problem with Quadrangle (Medial Axis projection) algorithm
authoreap <eap@opencascade.com>
Thu, 12 Jan 2017 12:13:47 +0000 (15:13 +0300)
committereap <eap@opencascade.com>
Thu, 12 Jan 2017 12:13:47 +0000 (15:13 +0300)
  (SMESH_MAT2d.cxx)

+ IPAL53878: Quadrangle: Medial Axis Projection algorithm fails
   (StdMeshers_QuadFromMedialAxis_1D2D.cxx)

resources/CMakeLists.txt
resources/mesh_tree_hypo_quadratic.png [new file with mode: 0644]
src/SMESHUtils/SMESH_MAT2d.cxx
src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx
src/StdMeshersGUI/StdMeshers_images.ts

index 9975b95..b720853 100755 (executable)
@@ -192,6 +192,7 @@ SET(SMESH_RESOURCES_FILES
   mesh_tree_hypo_source_3d_shape.png
   mesh_tree_hypo_projection_3d.png
   mesh_tree_hypo_projection_2d.png
+  mesh_tree_hypo_quadratic.png
   mesh_build_compound.png
   copy_mesh.png
   mesh_node_to_point.png
diff --git a/resources/mesh_tree_hypo_quadratic.png b/resources/mesh_tree_hypo_quadratic.png
new file mode 100644 (file)
index 0000000..6516bf8
Binary files /dev/null and b/resources/mesh_tree_hypo_quadratic.png differ
index 2c20eb8..aad6899 100644 (file)
@@ -340,7 +340,7 @@ namespace
       return ( _inSeg->getGeomEdge( _edge->twin()->cell() ) != theNoEdgeID );
     }
 
-    // check a next segment in CW order
+    // check a next segment in CCW order
     bool isSameBranch( const BndSeg& seg2 )
     {
       if ( !_edge || !seg2._edge )
@@ -1011,6 +1011,8 @@ namespace
     int branchID = 1; // we code orientation as branchID sign
     branchEdges.resize( branchID );
 
+    vector< std::pair< int, const TVDVertex* > > branchesToCheckEnd;
+
     for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE )
     {
       vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ];
@@ -1039,7 +1041,13 @@ namespace
         {
           branchEdges.resize(( branchID = branchEdges.size()) + 1 );
           if ( bndSegs[i]._edge && bndSegs[i]._prev )
+          {
             endType.insert( make_pair( bndSegs[i]._edge->vertex1(), SMESH_MAT2d::BE_BRANCH_POINT ));
+            if ( bndSegs[i]._prev->_branchID < 0 )
+              // 0023404: a branch-point is inside a branch
+              branchesToCheckEnd.push_back( make_pair( bndSegs[i]._prev->branchID(),
+                                                       bndSegs[i]._edge->vertex1() ));
+          }
         }
         else if ( bndSegs[i]._prev->_branchID )
         {
@@ -1063,6 +1071,37 @@ namespace
       }
     }
 
+    if ( !ignoreCorners && !branchesToCheckEnd.empty() )
+    {
+      // split branches having branch-point inside
+      // (a branch-point was not detected since another branch is joined at the opposite side)
+      for ( size_t i = 0; i < branchesToCheckEnd.size(); ++i )
+      {
+        vector<const TVDEdge*> & branch = branchEdges[ branchesToCheckEnd[i].first ];
+        const TVDVertex*    branchPoint = branchesToCheckEnd[i].second;
+        if ( branch.front()->vertex1() == branchPoint ||
+             branch.back ()->vertex0() == branchPoint )
+          continue; // OK - branchPoint is at a branch end
+
+        // find a MA edge where another branch begins
+        size_t iE;
+        for ( iE = 0; iE < branch.size(); ++iE )
+          if ( branch[iE]->vertex1() == branchPoint )
+            break;
+        if ( iE < branch.size() )
+        {
+          // split the branch
+          branchEdges.resize(( branchID = branchEdges.size()) + 1 );
+          vector<const TVDEdge*> & branch2 = branchEdges[ branchID ];
+          branch2.assign( branch.begin()+iE, branch.end() );
+          branch.resize( iE );
+          for ( iE = 0; iE < branch2.size(); ++iE )
+            if ( BndSeg* bs = BndSeg::getBndSegOfEdge( branch2[iE], bndSegsPerEdge ))
+              bs->setBranch( branchID, bndSegsPerEdge );
+        }
+      }
+    }
+
     // join the 1st and the last branch edges if it is the same branch
     // if ( bndSegs.back().branchID() != bndSegs.front().branchID() &&
     //      bndSegs.back().isSameBranch( bndSegs.front() ))
@@ -1073,10 +1112,14 @@ namespace
     //   br2.clear();
     // }
 
-    // remove branches ending at BE_ON_VERTEX
+    // remove branches ending at BE_ON_VERTEX and BE_END
 
     vector<bool> isBranchRemoved( branchEdges.size(), false );
 
+    std::set< SMESH_MAT2d::BranchEndType > endTypeToRm;
+    endTypeToRm.insert( SMESH_MAT2d::BE_ON_VERTEX );
+    endTypeToRm.insert( SMESH_MAT2d::BE_END );
+
     if ( ignoreCorners && branchEdges.size() > 2 && !branchEdges[2].empty() )
     {
       // find branches to remove
@@ -1088,10 +1131,10 @@ namespace
         const TVDVertex* v0 = branchEdges[iB][0]->vertex1();
         const TVDVertex* v1 = branchEdges[iB].back()->vertex0();
         v2et = endType.find( v0 );
-        if ( v2et != endType.end() && v2et->second == SMESH_MAT2d::BE_ON_VERTEX )
+        if ( v2et != endType.end() && endTypeToRm.count( v2et->second ))
           isBranchRemoved[ iB ] = true;
         v2et = endType.find( v1 );
-        if ( v2et != endType.end() && v2et->second == SMESH_MAT2d::BE_ON_VERTEX )
+        if ( v2et != endType.end() && endTypeToRm.count( v2et->second ))
           isBranchRemoved[ iB ] = true;
       }
       // try to join not removed branches into one
index 76f3a31..c7df8a3 100644 (file)
@@ -1072,7 +1072,7 @@ namespace
       if ( ! ( theDivPoints[0]._iEdge     == 0 &&
                theDivPoints[0]._edgeParam == 0. )) // recursive call
       {
-        SMESH_MAT2d::BranchPoint brp( &branch, 0, 0 );
+        SMESH_MAT2d::BranchPoint brp( &branch, 0, 0. );
         vector< SMESH_MAT2d::BranchPoint > divPoint( 1, brp );
         vector< std::size_t > edgeIDs1(2), edgeIDs2(2);
         edgeIDs1[0] = theEdgeIDs1.back();
@@ -1084,9 +1084,10 @@ namespace
       }
     }
 
-    // project theDivPoints
+    // project theDivPoints and keep projections to merge
 
     TMAPar2NPoints::iterator u2NP;
+    vector< TMAPar2NPoints::iterator > projToMerge;
     for ( size_t i = 0; i < theDivPoints.size(); ++i )
     {
       if ( !branch.getParameter( theDivPoints[i], uMA ))
@@ -1129,9 +1130,18 @@ namespace
       if ( isVertex[0] && isVertex[1] )
         continue;
 
-      bool isOppComputed = theIsEdgeComputed[ np[ iNode ]._edgeInd ];
-      if ( !isOppComputed )
-        continue;
+      // bool isOppComputed = theIsEdgeComputed[ np[ iNode ]._edgeInd ];
+      // if ( isOppComputed )
+        projToMerge.push_back( u2NP );
+    }
+
+    // merge projections
+
+    for ( size_t i = 0; i < projToMerge.size(); ++i )
+    {
+      u2NP = projToMerge[i];
+      const size_t iVert = get( u2NP->second, 0 )._node ? 0 : 1; // side with a VERTEX
+      const size_t iNode = 1 - iVert;                            // opposite (meshed?) side
 
       // a VERTEX is projected on a meshed EDGE; there are two options:
       // 1) a projected point is joined with a closet node if a strip between this and neighbor
@@ -1145,10 +1155,6 @@ namespace
       bool isShortPrev[2], isShortNext[2], isPrevCloser[2];
       TMAPar2NPoints::iterator u2NPPrev = u2NP, u2NPNext = u2NP;
       --u2NPPrev; ++u2NPNext;
-      // bool hasPrev = ( u2NP     != thePointsOnE.begin() );
-      // bool hasNext = ( u2NPNext != thePointsOnE.end() );
-      // if ( !hasPrev ) u2NPPrev = u2NP0;
-      // if ( !hasNext ) u2NPNext = u2NP1;
       for ( int iS = 0; iS < 2; ++iS ) // side with Vertex and side with Nodes
       {
         NodePoint np     = get( u2NP->second,     iS );
@@ -1161,11 +1167,9 @@ namespace
         double  distNext = p.Distance( pNext );
         double         r = distPrev / ( distPrev + distNext );
         isShortPrev [iS] = ( r < rShort );
-        isShortNext [iS] = (( 1 - r ) > ( 1 - rShort ));
-        isPrevCloser[iS] = (( r < 0.5 ) && ( u2NPPrev->first > 0 ));
+        isShortNext [iS] = (( 1 - r ) < rShort );
+        isPrevCloser[iS] = (( r < 0.5 ) && ( theSinuFace.IsRing() || u2NPPrev->first > 0 ));
       }
-      // if ( !hasPrev ) isShortPrev[0] = isShortPrev[1] = false;
-      // if ( !hasNext ) isShortNext[0] = isShortNext[1] = false;
 
       TMAPar2NPoints::iterator u2NPClose;
 
@@ -1174,17 +1178,18 @@ namespace
       {
         u2NPClose = isPrevCloser[0] ? u2NPPrev : u2NPNext;
         NodePoint& npProj  = get( u2NP->second,      iNode ); // NP of VERTEX projection
+        NodePoint& npVert  = get( u2NP->second,      iVert ); // NP of VERTEX
         NodePoint npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj
-        NodePoint npCloseV = get( u2NPClose->second, iVert ); // NP close to VERTEX
-        if ( !npCloseV._node )
+        NodePoint npCloseV = get( u2NPClose->second, iVert ); // NP close to npVert
+        if ( !npCloseV._node || npCloseV._node == npVert._node )
         {
           npProj = npCloseN;
-          thePointsOnE.erase( isPrevCloser[0] ? u2NPPrev : u2NPNext );
+          thePointsOnE.erase( u2NPClose );
           continue;
         }
         else
         {
-          // can't remove the neighbor projection as it is also from VERTEX, -> option 1)
+          // can't remove the neighbor projection as it is also from VERTEX -> option 1)
         }
       }
       // else: option 1) - wide enough -> "duplicate" existing node
index 4bfcece..fc618a7 100644 (file)
         </message>
         <message>
             <source>ICON_SMESH_TREE_HYPO_QuadraticMesh</source>
-            <translation>mesh_tree_hypo_length.png</translation>
+            <translation>mesh_tree_hypo_quadratic.png</translation>
         </message>
         <message>
             <source>ICON_SMESH_TREE_HYPO_SegmentLengthAroundVertex</source>