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)
committerbugmaster <bugmaster@opencascade.com>
Fri, 3 Jul 2020 08:03:08 +0000 (11:03 +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 de3239f..76efbc9 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>
@@ -130,6 +131,7 @@ static
 static 
   void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild, 
                              const TopTools_MapOfShape& theModifiedEdges,
+                             const BRepOffset_Analyse* theAnalyse,
                              TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                              TopTools_DataMapOfShapeListOfShape& theDMFNewHoles,
                              TopTools_DataMapOfShapeListOfShape& theEdgesOrigins,
@@ -172,6 +174,17 @@ static
                         TopTools_MapOfShape& theEdgesInvalidByVertex,
                         TopTools_MapOfShape& theEdgesValidByVertex);
 
+static
+  void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset,
+                         const TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
+                         const TopTools_DataMapOfShapeShape& theFacesOrigins,
+                         const BRepOffset_Analyse* theAnalyse,
+                         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,
@@ -324,6 +337,7 @@ static
                     const TopTools_MapOfShape& theFSelfRebAvoid,
                     const TopoDS_Shape& theSolids,
                     const TopTools_DataMapOfShapeListOfShape& theSSInterfs,
+                    const BRepOffset_Analyse* theAnalyse,
                     TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                     TopTools_DataMapOfShapeListOfShape& theDMFNewHoles,
                     TopTools_DataMapOfShapeListOfShape& theEdgesOrigins,
@@ -734,7 +748,7 @@ void BRepOffset_MakeOffset::BuildSplitsOfExtendedFaces(const TopTools_ListOfShap
     if (aFToRebuild.Extent()) {
       // vertices to avoid
       TopTools_MapOfShape aVAEmpty;
-      RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, aFImages, aDMFNewHoles,
+      RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, &theAnalyse, aFImages, aDMFNewHoles,
                    theEdgesOrigins, theFacesOrigins, anOEImages, anOEOrigins, aLastInvEdges,
                    anEdgesToAvoid, anInvEdges, aValidEdges, anInvertedEdges, anAlreadyInvFaces,
                    anInvFaces, anArtInvFaces, aVAEmpty, theETrimEInf, theAsDes);
@@ -755,6 +769,7 @@ void BRepOffset_MakeOffset::BuildSplitsOfExtendedFaces(const TopTools_ListOfShap
 //=======================================================================
 void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild, 
                            const TopTools_MapOfShape& theModifiedEdges,
+                           const BRepOffset_Analyse* theAnalyse,
                            TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                            TopTools_DataMapOfShapeListOfShape& theDMFNewHoles,
                            TopTools_DataMapOfShapeListOfShape& theEdgesOrigins,
@@ -794,7 +809,7 @@ void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theF
   //
   TopoDS_Shape aSolids;
   //
-  BuildSplitsOfFaces(aLF, theModifiedEdges, theEdgesOrigins, NULL, theAsDes, theFacesOrigins, 
+  BuildSplitsOfFaces(aLF, theModifiedEdges, theEdgesOrigins, theAnalyse, theAsDes, theFacesOrigins, 
                      theOEImages, theOEOrigins, theLastInvEdges, theEdgesToAvoid, anInvEdges, theValidEdges, 
                      anInvertedEdges, theAlreadyInvFaces, anInvFaces, anArtInvFaces, theFImages,
                      theDMFNewHoles, aSolids, aSSInterfs);
@@ -805,7 +820,7 @@ void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theF
     FindFacesToRebuild(theFImages, anInvEdges, anInvFaces, aSSInterfs, aFToRebuild, aFSelfRebAvoid);
     //
     if (aFToRebuild.Extent()) {
-      RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, theFImages, theDMFNewHoles,
+      RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, theAnalyse, theFImages, theDMFNewHoles,
                    theEdgesOrigins, theFacesOrigins, theOEImages, theOEOrigins, theLastInvEdges,
                    theEdgesToAvoid, anInvEdges, theValidEdges, anInvertedEdges, theAlreadyInvFaces,
                    anInvFaces, anArtInvFaces, theVertsToAvoid, theETrimEInf, theAsDes);
@@ -999,7 +1014,12 @@ 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, theFacesOrigins, theAnalyse,
+                    theInvEdges, theValidEdges, aDMFMIE, aDMFMVE, aDMFMNE);
+
 #ifdef OFFSET_DEBUG
   // show invalid edges
   TopoDS_Compound aCEInv1;
@@ -1960,6 +1980,196 @@ 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_DataMapOfShapeShape& theFacesOrigins,
+                       const BRepOffset_Analyse* theAnalyse,
+                       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;
+
+  // Avoid artificial faces
+  TopTools_MapOfShape aNewFaces;
+  if (theAnalyse)
+  {
+    TopTools_MapOfShape aMapNewTmp;
+    for (TopTools_ListOfShape::Iterator it (theAnalyse->NewFaces()); it.More(); it.Next())
+      aMapNewTmp.Add (it.Value());
+
+    for (TopTools_ListOfShape::Iterator it (theLFOffset); it.More(); it.Next())
+    {
+      const TopoDS_Shape& aFOffset = it.Value();
+      const TopoDS_Shape& aFOrigin = theFacesOrigins.Find (aFOffset);
+      if (aMapNewTmp.Contains (aFOrigin))
+        aNewFaces.Add (aFOffset);
+    }
+  }
+
+  TopTools_IndexedDataMapOfShapeListOfShape anEFMap;
+  for (TopTools_ListOfShape::Iterator itLFO (theLFOffset); itLFO.More(); itLFO.Next())
+  {
+    const TopoDS_Shape& aF = itLFO.Value();
+    if (aNewFaces.Contains (aF))
+      continue;
+
+    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, NULL, 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, NULL, 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
@@ -4256,6 +4466,7 @@ void RebuildFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild
                   const TopTools_MapOfShape& theFSelfRebAvoid,
                   const TopoDS_Shape& theSolids,
                   const TopTools_DataMapOfShapeListOfShape& theSSInterfs,
+                  const BRepOffset_Analyse* theAnalyse,
                   TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                   TopTools_DataMapOfShapeListOfShape& theDMFNewHoles,
                   TopTools_DataMapOfShapeListOfShape& theEdgesOrigins,
@@ -4282,7 +4493,7 @@ void RebuildFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild
                  theInvFaces, theArtInvFaces, theVertsToAvoid, theETrimEInf, aModifiedEdges, theAsDes);
   //
   // 2. Repeat steps to build the correct faces
-  BuildSplitsOfInvFaces(theFToRebuild, aModifiedEdges, theFImages, theDMFNewHoles, theEdgesOrigins,
+  BuildSplitsOfInvFaces(theFToRebuild, aModifiedEdges, theAnalyse, theFImages, theDMFNewHoles, theEdgesOrigins,
                         theFacesOrigins, theOEImages, theOEOrigins, theLastInvEdges,
                         theEdgesToAvoid, theVertsToAvoid, theAlreadyInvFaces, theValidEdges, 
                         theETrimEInf, theAsDes);
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