]> OCCT Git - occt.git/commitdiff
0030559: BOP Fuse: result is inconsistent
authoremv <emv@opencascade.com>
Wed, 16 Sep 2020 12:05:50 +0000 (15:05 +0300)
committerbugmaster <bugmaster@opencascade.com>
Sun, 27 Sep 2020 09:00:04 +0000 (12:00 +0300)
Implement alternative approach for making the edge seam (closed) on the face. This approach is useful for non-periodic surfaces (e.g. tore-like surface of revolution is periodic in U direction only).
Avoid internal faces in the affected solids of the result of BOP Fuse.

src/BOPAlgo/BOPAlgo.msg
src/BOPAlgo/BOPAlgo_Alerts.hxx
src/BOPAlgo/BOPAlgo_BOP.cxx
src/BOPAlgo/BOPAlgo_BOPAlgo_msg.pxx
src/BOPAlgo/BOPAlgo_Builder_2.cxx
src/BOPTools/BOPTools_AlgoTools3D.cxx
src/BOPTools/BOPTools_AlgoTools3D.hxx
tests/bugs/modalg_2/bug22109_2
tests/bugs/modalg_7/bug30559 [new file with mode: 0644]

index 72170794926029003417181973cc3048c5a73c4f..9843277bc1a790bb81049181669a89a8beff842d 100644 (file)
@@ -124,3 +124,6 @@ Unable to glue the shapes
 
 .BOPAlgo_AlertShapeIsNotPeriodic
 The shape is not periodic
+
+.BOPAlgo_AlertUnableToMakeClosedEdgeOnFace
+Unable to make closed edge on face.
index 39fe78975160c4b6d4e22ad8caf588f717651d7a..3871c58fcd60f921490aa73cb00085e5315ea6a2 100644 (file)
@@ -138,4 +138,7 @@ DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertUnableToGlue)
 //! The shape is not periodic
 DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertShapeIsNotPeriodic)
 
+//! Unable to make closed edge on face (to make a seam)
+DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertUnableToMakeClosedEdgeOnFace)
+
 #endif // _BOPAlgo_Alerts_HeaderFile
index 5069c2132dcb274b351ea10cf5ed8e166adeda8b..b516015c4900ecb9b58d17eef9b495ffadb93079 100644 (file)
@@ -60,8 +60,7 @@ static
 //
 static
   void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
-                             TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
-                             TopTools_IndexedMapOfShape& theMFI);
+                             TopTools_IndexedDataMapOfShapeListOfShape& theMFS);
 
 //=======================================================================
 //function : 
@@ -1002,8 +1001,6 @@ void BOPAlgo_BOP::BuildSolid()
   TopTools_IndexedMapOfShape aMUSols;
   // Use map to chose the most outer faces to build result solids
   aMFS.Clear();
-  // Internal faces
-  TopTools_IndexedMapOfShape aMFI;
   //
   TopoDS_Iterator aIt(myRC);
   for (; aIt.More(); aIt.Next()) {
@@ -1015,7 +1012,7 @@ void BOPAlgo_BOP::BuildSolid()
       }
     }
     //
-    MapFacesToBuildSolids(aSx, aMFS, aMFI);
+    MapFacesToBuildSolids(aSx, aMFS);
   } // for (; aIt.More(); aIt.Next()) {
   //
   // Process possibly untouched solids.
@@ -1035,7 +1032,7 @@ void BOPAlgo_BOP::BuildSolid()
     }
     //
     if (aExp.More()) {
-      MapFacesToBuildSolids(aSx, aMFS, aMFI);
+      MapFacesToBuildSolids(aSx, aMFS);
     }
     else {
       BOPTools_Set aST;
@@ -1058,13 +1055,6 @@ void BOPAlgo_BOP::BuildSolid()
       aSFS.Append(aFx);
     }
   }
-  // Internal faces
-  aNb = aMFI.Extent();
-  for (i = 1; i <= aNb; ++i) {
-    TopoDS_Shape aFx = aMFI.FindKey(i);
-    aSFS.Append(aFx.Oriented(TopAbs_FORWARD));
-    aSFS.Append(aFx.Oriented(TopAbs_REVERSED));
-  }
   //
   TopoDS_Shape aRC;
   BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
@@ -1073,6 +1063,7 @@ void BOPAlgo_BOP::BuildSolid()
     BOPAlgo_BuilderSolid aBS;
     aBS.SetContext(myContext);
     aBS.SetShapes(aSFS);
+    aBS.SetAvoidInternalShapes (Standard_True);
     aBS.Perform();
     if (aBS.HasErrors()) {
       AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
@@ -1518,19 +1509,16 @@ Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
 //=======================================================================
 //function : MapFacesToBuildSolids
 //purpose  : Stores the faces of the given solid into outgoing maps:
-//           <theMFS> - not internal faces with reference to solid;
-//           <theMFI> - internal faces.
+//           <theMFS> - not internal faces with reference to solid.
 //=======================================================================
 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
-                           TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
-                           TopTools_IndexedMapOfShape& theMFI)
+                           TopTools_IndexedDataMapOfShapeListOfShape& theMFS)
 {
   TopExp_Explorer aExp(theSol, TopAbs_FACE);
   for (; aExp.More(); aExp.Next()) {
     const TopoDS_Shape& aF = aExp.Current();
     //
     if (aF.Orientation() == TopAbs_INTERNAL) {
-      theMFI.Add(aF);
       continue;
     }
     //
index d8fd52feae440297bd1713e155344b33772468b1..6c971d1d4f39027fc94fcc74dd69d0fd0e984c26 100644 (file)
@@ -126,4 +126,7 @@ static const char BOPAlgo_BOPAlgo_msg[] =
   "Unable to glue the shapes\n"
   "\n"
   ".BOPAlgo_AlertShapeIsNotPeriodic\n"
-  "The shape is not periodic\n";
+  "The shape is not periodic\n"
+  "\n"
+  ".BOPAlgo_AlertUnableToMakeClosedEdgeOnFace\n"
+  "Unable to make closed edge on face.\n";
index 17c29ada6ab4ffa3c2a875db2243a2593b69e9c7..09a57fa46a109c355c4520eb515521fbd79108d2 100644 (file)
@@ -17,6 +17,7 @@
 
 
 #include <BOPAlgo_Builder.hxx>
+#include <BOPAlgo_Alerts.hxx>
 #include <BOPAlgo_BuilderFace.hxx>
 #include <BOPAlgo_PaveFiller.hxx>
 #include <BOPAlgo_Tools.hxx>
@@ -383,7 +384,18 @@ void BOPAlgo_Builder::BuildSplitFaces()
         if (bIsClosed) {
           if (aMFence.Add(aSp)) {
             if (!BRep_Tool::IsClosed(aSp, aF)){
-              BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF);
+              if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF))
+              {
+                // try different approach
+                if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aE, aSp, aF))
+                {
+                  TopoDS_Compound aWS;
+                  BRep_Builder().MakeCompound (aWS);
+                  BRep_Builder().Add (aWS, aF);
+                  BRep_Builder().Add (aWS, aSp);
+                  AddWarning (new BOPAlgo_AlertUnableToMakeClosedEdgeOnFace (aWS));
+                }
+              }
             }
             //
             aSp.Orientation(TopAbs_FORWARD);
index 06653d1605f84f005ac66d7b9bc6c3da44fc5c03..4de235a3919d0c5fca4ed0a6eb930ed10b782bb0 100644 (file)
@@ -39,6 +39,7 @@
 #include <Geom_RectangularTrimmedSurface.hxx>
 #include <Geom_Surface.hxx>
 #include <GeomAdaptor_Surface.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
 #include <gp_Cylinder.hxx>
 #include <gp_Dir.hxx>
 #include <gp_Dir2d.hxx>
@@ -72,8 +73,8 @@ static
 //function : DoSplitSEAMOnFace
 //purpose  : 
 //=======================================================================
-void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
-                                              const TopoDS_Face& aF)
+Standard_Boolean BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
+                                                          const TopoDS_Face& aF)
 {
   Standard_Boolean bIsUPeriodic, bIsVPeriodic, bIsLeft;
   Standard_Real aTol, a, b, anUPeriod, anVPeriod, aT, anU, dU, anU1;
@@ -131,7 +132,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
       bIsVPeriodic=aSB->IsVPeriodic();
       //
       if (!(bIsUPeriodic || bIsVPeriodic)) {
-        return;
+        return Standard_False;
       }
       anUPeriod = bIsUPeriodic ? aSB->UPeriod() : 0.;
       anVPeriod = bIsVPeriodic ? aSB->VPeriod() : 0.;
@@ -139,7 +140,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
     //
     if (aRTS.IsNull()) {
       if (!bIsUClosed && !bIsVClosed) {
-        return;
+        return Standard_False;
       }
       //
       if (bIsUClosed) {
@@ -191,7 +192,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
   }
   //
   if (anU1==anU && anV1==anV) {
-    return;
+    return Standard_False;
   }
   //
   aScPr = (anU1==anU) ? aDir2D1*aDOX : aDir2D1*aDOY;
@@ -222,7 +223,96 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
       BB.UpdateEdge(aSp, aC2, aC1, aF, aTol);
     }
   }
+  return Standard_True;
 }
+
+//=======================================================================
+//function : DoSplitSEAMOnFace
+//purpose  : 
+//=======================================================================
+Standard_Boolean BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& theEOrigin,
+                                                          const TopoDS_Edge& theESplit,
+                                                          const TopoDS_Face& theFace)
+{
+  if (!BRep_Tool::IsClosed (theEOrigin, theFace))
+    return Standard_False;
+
+  if (BRep_Tool::IsClosed (theESplit, theFace))
+    return Standard_True;
+
+  TopoDS_Edge aESplit = theESplit;
+  aESplit.Orientation (TopAbs_FORWARD);
+
+  TopoDS_Face aFace = theFace;
+  aFace.Orientation (TopAbs_FORWARD);
+
+  Standard_Real aTS1, aTS2;
+  Handle(Geom2d_Curve) aC2DSplit = BRep_Tool::CurveOnSurface (aESplit, aFace, aTS1, aTS2);
+  if (aC2DSplit.IsNull())
+    return Standard_False;
+
+  Standard_Real aT1, aT2;
+  Handle(Geom2d_Curve) aC2D1 = BRep_Tool::CurveOnSurface (
+    TopoDS::Edge (theEOrigin.Oriented (TopAbs_FORWARD)), aFace, aT1, aT2);
+  Handle(Geom2d_Curve) aC2D2 = BRep_Tool::CurveOnSurface (
+    TopoDS::Edge (theEOrigin.Oriented (TopAbs_REVERSED)), aFace, aT1, aT2);
+
+  Standard_Real aT = BOPTools_AlgoTools2D::IntermediatePoint (aTS1, aTS2);
+  gp_Pnt2d aPMid;
+  gp_Vec2d aVTgt;
+  aC2DSplit->D1 (aT, aPMid, aVTgt);
+
+  // project on original 2d curves
+  Geom2dAPI_ProjectPointOnCurve aProjPC1, aProjPC2;
+  aProjPC1.Init (aPMid, aC2D1, aT1, aT2);
+  aProjPC2.Init (aPMid, aC2D2, aT1, aT2);
+
+  if (!aProjPC1.NbPoints() && !aProjPC2.NbPoints())
+    return Standard_False;
+
+  Standard_Real aDist1 = aProjPC1.NbPoints() ? aProjPC1.LowerDistance() : RealLast();
+  Standard_Real aDist2 = aProjPC2.NbPoints() ? aProjPC2.LowerDistance() : RealLast();
+
+  if (aDist1 > Precision::PConfusion() && aDist2 > Precision::PConfusion())
+    return Standard_False;
+
+  // choose the closest and take corresponding point from the opposite
+  gp_Pnt2d aNewPnt = aDist1 < aDist2 ? aC2D2->Value (aProjPC1.LowerDistanceParameter()) :
+    aC2D1->Value (aProjPC2.LowerDistanceParameter());
+
+  Handle (Geom2d_Curve) aTmpC1 = Handle (Geom2d_Curve)::DownCast (aC2DSplit->Copy());
+  Handle (Geom2d_Curve) aTmpC2 = Handle (Geom2d_Curve)::DownCast (aC2DSplit->Copy());
+
+  Handle (Geom2d_TrimmedCurve) aC1 = new Geom2d_TrimmedCurve (aTmpC1, aTS1, aTS2);
+  Handle (Geom2d_TrimmedCurve) aC2 = new Geom2d_TrimmedCurve (aTmpC2, aTS1, aTS2);
+
+  gp_Vec2d aTrVec (aPMid, aNewPnt);
+  aC2->Translate (aTrVec);
+
+  gp_Pnt2d aPProj;
+  gp_Vec2d aVTgtOrigin;
+  if (aDist1 < aDist2)
+  {
+    aC2D1->D1 (aProjPC1.LowerDistanceParameter(), aPProj, aVTgtOrigin);
+  }
+  else
+  {
+    aC2D2->D1 (aProjPC2.LowerDistanceParameter(), aPProj, aVTgtOrigin);
+  }
+
+  Standard_Real aDot = aVTgt.Dot (aVTgtOrigin);
+
+  if ((aDist1 < aDist2) == (aDot > 0))
+  {
+    BRep_Builder().UpdateEdge (aESplit, aC1, aC2, aFace, BRep_Tool::Tolerance (aESplit));
+  }
+  else
+  {
+    BRep_Builder().UpdateEdge (aESplit, aC2, aC1, aFace, BRep_Tool::Tolerance (aESplit));
+  }
+  return Standard_True;
+}
+
 //=======================================================================
 //function : GetNormalToFaceOnEdge
 //purpose  : 
index 9a3d5de623d951890a7fd469c96cb9001a5f8fbf..10457b91e9802260f48c7b94a16d4aada68c0ca7 100644 (file)
@@ -43,11 +43,15 @@ public:
 
   DEFINE_STANDARD_ALLOC
 
-  
+  //! Makes the edge <theESplit> seam edge for the face <theFace> basing on the surface properties (U and V periods)
+  Standard_EXPORT static Standard_Boolean DoSplitSEAMOnFace (const TopoDS_Edge& theESplit,
+                                                             const TopoDS_Face& theFace);
 
-  //! Make the edge <aSp> seam edge for the face <aF>
-  Standard_EXPORT static void DoSplitSEAMOnFace (const TopoDS_Edge& aSp,
-                                                 const TopoDS_Face& aF);
+  //! Makes the split edge <theESplit> seam edge for the face <theFace> basing on the positions
+  //! of 2d curves of the original edge <theEOrigin>.
+  Standard_EXPORT static Standard_Boolean DoSplitSEAMOnFace (const TopoDS_Edge& theEOrigin,
+                                                             const TopoDS_Edge& theESplit,
+                                                             const TopoDS_Face& theFace);
 
   //! Computes normal to the face <aF> for the point on the edge <aE>
   //! at parameter <aT>.<br>
index d53991b41da3fe2c8b58ceba7ce534d7858f57cc..b3ef5cb57118cf5c94bc9de6e4e6134fee0d06dc 100755 (executable)
@@ -24,6 +24,6 @@ puts "Finish boolean operation ..."
 checkprops result -s 87449.7 
 checkshape result
 
-checknbshapes result -vertex 17 -edge 25 -wire 14 -face 10 -shell 2 -solid 1 -compsolid 0 -compound 1 -shape 70
+checknbshapes result -vertex 17 -edge 24 -wire 13 -face 9 -shell 1 -solid 1
 
 checkview -display result -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug30559 b/tests/bugs/modalg_7/bug30559
new file mode 100644 (file)
index 0000000..b099291
--- /dev/null
@@ -0,0 +1,25 @@
+puts "TODO CR29596 ALL: Warning: Intersection of pair of shapes has failed"
+
+puts "============================================================================================="
+puts "0030559: BOP Fuse: result is inconsistent"
+puts "============================================================================================="
+puts ""
+
+restore [locate_data_file bug30559_VALVE_1_of_BRANCH_6028_B3.brep] a
+set exp [explode a So]
+bclearobjects
+bcleartools
+baddobjects a_1
+eval baddtools [lrange $exp 1 end]
+bfillds
+bbop result 1
+
+checkshape result
+checknbshapes result -wire 26 -face 20 -shell 1 -solid 1
+checkprops result -s 456495 -v 1.2165e+07
+
+if {![regexp "This shape seems to be OK" [bopcheck result]]} {
+  puts "Error: result is self-interfered shape"
+}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png