]> OCCT Git - occt-copy.git/commitdiff
0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes
authoremv <emv@opencascade.com>
Fri, 26 Jun 2020 11:20:52 +0000 (14:20 +0300)
committeremv <emv@opencascade.com>
Tue, 30 Jun 2020 11:43:41 +0000 (14:43 +0300)
Check if unclassified edge may be added as neutral (invalid in one split, valid in other) by checking the SD faces in which the edge was classified.

src/BRepOffset/BRepOffset_MakeOffset_1.cxx
tests/offset/shape_type_i_c/XX1 [new file with mode: 0644]
tests/offset/shape_type_i_c/XX2 [new file with mode: 0644]
tests/offset/shape_type_i_c/XX3 [new file with mode: 0644]

index 1f549670ce89b7306a137e5b300687d383aeb6a3..9d26ee1c898ef226e4b6520321205d39aaa3ce59 100644 (file)
@@ -60,6 +60,7 @@
 #include <BOPTools_AlgoTools3D.hxx>
 #include <BOPTools_AlgoTools.hxx>
 #include <BOPTools_AlgoTools2D.hxx>
+#include <BOPTools_Set.hxx>
 
 #include <IntTools_Context.hxx>
 #include <IntTools_ShrunkRange.hxx>
@@ -170,6 +171,15 @@ static
                         TopTools_MapOfShape& theEdgesInvalidByVertex,
                         TopTools_MapOfShape& theEdgesValidByVertex);
 
+static
+  void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset,
+                         const TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
+                         const TopTools_IndexedMapOfShape& theInvEdges,
+                         const TopTools_IndexedMapOfShape& theValidEdges,
+                         BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
+                         BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges,
+                         BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges);
+
 static
   void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
                         const TopTools_IndexedMapOfShape& theInvEdges,
@@ -994,7 +1004,11 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
   if (theInvEdges.IsEmpty() && theArtInvFaces.IsEmpty() && aDMFMIE.IsEmpty()) {
     return;
   }
-  //
+
+  // Additional step to find invalid edges by checking unclassified edges
+  // in the splits of SD faces
+  FindInvalidEdges (aLFDone, theFImages, theInvEdges, theValidEdges, aDMFMIE, aDMFMVE, aDMFMNE);
+
 #ifdef OFFSET_DEBUG
   // show invalid edges
   TopoDS_Compound aCEInv1;
@@ -1918,6 +1932,175 @@ void FindInvalidEdges(const TopoDS_Face& theF,
   }
 }
 
+
+namespace 
+{
+  static void addAsNeutral (const TopoDS_Shape& theE,
+                            const TopoDS_Shape& theFInv,
+                            const TopoDS_Shape& theFVal,
+                            BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
+                            BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges)
+  {
+    TopTools_IndexedMapOfShape* pMEInv = theLocInvEdges.ChangeSeek (theFInv);
+    if (!pMEInv)
+      pMEInv = theLocInvEdges.Bound (theFInv, TopTools_IndexedMapOfShape());
+    pMEInv->Add (theE);
+
+    TopTools_MapOfShape* pMEVal = theLocValidEdges.ChangeSeek (theFVal);
+    if (!pMEVal)
+      pMEVal = theLocValidEdges.Bound (theFVal, TopTools_MapOfShape());
+    pMEVal->Add (theE);
+  }
+
+}
+//=======================================================================
+//function : FindInvalidEdges
+//purpose  : Additional method to look for invalid faces
+//=======================================================================
+void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset,
+                       const TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
+                       const TopTools_IndexedMapOfShape& theInvEdges,
+                       const TopTools_IndexedMapOfShape& theValidEdges,
+                       BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
+                       BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges,
+                       BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges)
+{
+  // 1. Find edges unclassified in faces
+  // 2. Find SD faces in which the same edge is classified
+  // 3. Check if the edge is neutral in face in which it wasn't classified
+
+  NCollection_IndexedDataMap<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> aMEUnclassified;
+  TopTools_DataMapOfShapeShape aFSplitFOffset;
+
+  TopTools_IndexedDataMapOfShapeListOfShape anEFMap;
+  for (TopTools_ListOfShape::Iterator itLFO (theLFOffset); itLFO.More(); itLFO.Next())
+  {
+    const TopoDS_Shape& aF = itLFO.Value();
+    const TopTools_ListOfShape& aLFImages = theFImages.FindFromKey (aF);
+    for (TopTools_ListOfShape::Iterator itLF (aLFImages); itLF.More(); itLF.Next())
+    {
+      const TopoDS_Shape& aFIm = itLF.Value();
+
+      TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, anEFMap);
+
+      const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFIm);
+      const TopTools_MapOfShape* pMEValid = theLocValidEdges.Seek (aFIm);
+
+      for (TopExp_Explorer expE (aFIm, TopAbs_EDGE); expE.More(); expE.Next())
+      {
+        const TopoDS_Shape& aE = expE.Current();
+        if (theInvEdges.Contains (aE) != theValidEdges.Contains (aE))
+        {
+          // edge is classified in some face
+
+          if ((!pMEInvalid || !pMEInvalid->Contains (aE)) && 
+              (!pMEValid   || !pMEValid->Contains (aE)))
+          {
+            // but not in the current one
+            TopTools_MapOfShape *pMap = aMEUnclassified.ChangeSeek (aE);
+            if (!pMap)
+              pMap = &aMEUnclassified (aMEUnclassified.Add (aE, TopTools_MapOfShape()));
+            pMap->Add (aFIm);
+
+            aFSplitFOffset.Bind (aFIm, aF);
+          }
+        }
+      }
+    }
+  }
+
+  if (aMEUnclassified.IsEmpty())
+    return;
+
+  // Analyze unclassified edges
+  const Standard_Integer aNbE = aMEUnclassified.Extent();
+  for (Standard_Integer iE = 1; iE <= aNbE; ++iE)
+  {
+    const TopoDS_Shape& aE = aMEUnclassified.FindKey (iE);
+    const TopTools_MapOfShape& aMFUnclassified = aMEUnclassified (iE);
+
+    const TopTools_ListOfShape& aLF = anEFMap.FindFromKey (aE);
+
+    for (TopTools_ListOfShape::Iterator itLF (aLF); itLF.More(); itLF.Next())
+    {
+      const TopoDS_Shape& aFClassified = itLF.Value();
+      if (aMFUnclassified.Contains (aFClassified))
+        continue;
+
+      BOPTools_Set anEdgeSetClass;
+      anEdgeSetClass.Add (aFClassified, TopAbs_EDGE);
+
+      TopoDS_Shape aEClassified;
+      FindShape (aE, aFClassified, aEClassified);
+      TopAbs_Orientation anOriClass = aEClassified.Orientation();
+
+      gp_Dir aDNClass;
+      BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aEClassified), TopoDS::Face (aFClassified), aDNClass);
+
+      const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFClassified);
+      Standard_Boolean isInvalid = pMEInvalid && pMEInvalid->Contains (aE);
+
+      for (TopTools_MapOfShape::Iterator itM (aMFUnclassified); itM.More(); itM.Next())
+      {
+        const TopoDS_Shape& aFUnclassified = itM.Value();
+
+        BOPTools_Set anEdgeSetUnclass;
+        anEdgeSetUnclass.Add (aFUnclassified, TopAbs_EDGE);
+
+        if (anEdgeSetClass.IsEqual (anEdgeSetUnclass))
+        {
+          gp_Dir aDNUnclass;
+          BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aE), TopoDS::Face (aFUnclassified), aDNUnclass);
+
+          Standard_Boolean isSameOri = aDNClass.IsEqual (aDNUnclass, Precision::Angular());
+
+          // Among other splits of the same face find those where the edge is contained with different
+          // orientation
+          const TopoDS_Shape& aFOffset = aFSplitFOffset.Find (aFUnclassified);
+          const TopTools_ListOfShape& aLFSplits = theFImages.FindFromKey (aFOffset);
+          TopTools_ListOfShape::Iterator itLFSp (aLFSplits);
+          for (; itLFSp.More(); itLFSp.Next())
+          {
+            const TopoDS_Shape& aFSp = itLFSp.Value();
+
+            if (!aFSp.IsSame (aFUnclassified) && aMFUnclassified.Contains (aFSp))
+            {
+              TopoDS_Shape aEUnclassified;
+              FindShape (aE, aFSp, aEUnclassified);
+
+              TopAbs_Orientation anOriUnclass = aEUnclassified.Orientation();
+              if (!isSameOri)
+                anOriUnclass = TopAbs::Reverse (anOriUnclass);
+
+              if (anOriClass != anOriUnclass)
+              {
+                // make the edge neutral for the face
+                TopTools_MapOfShape* pMENeutral = theNeutralEdges.ChangeSeek (aFOffset);
+                if (!pMENeutral)
+                  pMENeutral = theNeutralEdges.Bound (aFOffset, TopTools_MapOfShape());
+                pMENeutral->Add (aE);
+
+                if (isInvalid && isSameOri)
+                {
+                  // make edge invalid in aFUnclassified and valid in aFSp
+                  addAsNeutral (aE, aFClassified, aFSp, theLocInvEdges, theLocValidEdges);
+                }
+                else
+                {
+                  // make edge invalid in aFSp and valid in aFUnclassified
+                  addAsNeutral (aE, aFSp, aFClassified, theLocInvEdges, theLocValidEdges);
+                }
+              }
+            }
+          }
+          if (itLFSp.More())
+            break;
+        }
+      }
+    }
+  }
+}
+
 //=======================================================================
 //function : FindInvalidFaces
 //purpose  : Looking for the invalid faces by analyzing their invalid edges
@@ -2014,7 +2197,7 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
       //
       bValidLoc = pMVE && pMVE->Contains(aEIm);
       bInverted = theMEInverted.Contains(aEIm);
-      if (!bInvalid && bTreatInvertedAsInvalid) {
+      if (!bInvalid && !bInvalidLoc && bTreatInvertedAsInvalid) {
         bInvalid = bInverted;
       }
       //
@@ -2023,7 +2206,7 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
       }
       //
       bAllValid &= bValidLoc;
-      bAllInvalid &= bInvalid;
+      bAllInvalid &= (bInvalid || bInvalidLoc);
       bAllInvNeutral &= (bAllInvalid && bNeutral);
       bIsInvalidByInverted &= (bInvalidLoc || bInverted);
     }
diff --git a/tests/offset/shape_type_i_c/XX1 b/tests/offset/shape_type_i_c/XX1
new file mode 100644 (file)
index 0000000..d5a63b9
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes"
+puts "========"
+puts ""
+
+restore [locate_data_file bug31639_input.brep] s
+offsetparameter 1e-7 c i r
+offsetload s 7
+offsetperform result
+
+checkprops result -s 2.11103e+07 -v 1.43353e+09
+
+unifysamedom result_unif result
+checknbshapes result_unif -wire 45 -face 41 -shell 1 -solid 1
+
+checkview -display result_unif -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/offset/shape_type_i_c/XX2 b/tests/offset/shape_type_i_c/XX2
new file mode 100644 (file)
index 0000000..62e75d1
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes"
+puts "========"
+puts ""
+
+restore [locate_data_file bug31639_input_trim.brep] s
+offsetparameter 1e-7 c i r
+offsetload s 7
+offsetperform result
+
+checkprops result -s 7.22731e+06 -v 2.57323e+08
+
+unifysamedom result_unif result
+checknbshapes result_unif -wire 18 -face 17 -shell 1 -solid 1
+
+checkview -display result_unif -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/offset/shape_type_i_c/XX3 b/tests/offset/shape_type_i_c/XX3
new file mode 100644 (file)
index 0000000..f00bc69
--- /dev/null
@@ -0,0 +1,23 @@
+puts "========"
+puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes"
+puts "========"
+puts ""
+
+restore [locate_data_file bug31639_input.brep] s
+offsetparameter 1e-7 c i r
+offsetload s 0
+foreach f [explode s f] {
+  mksurface surf $f
+  regexp {Axis   :([-0-9.+eE]*), ([-0-9.+eE]*), ([-0-9.+eE]*)} [dump surf] full x y z
+  if {abs($x) > 1.e-7 || abs($y) > 1.e-7} {
+    offsetonface $f 7
+  }
+}
+offsetperform result
+
+checkprops result -s 2.10662e+07 -v 1.42886e+09
+
+unifysamedom result_unif result
+checknbshapes result_unif -wire 45 -face 41 -shell 1 -solid 1
+
+checkview -display result_unif -2d -path ${imagedir}/${test_image}.png