0029843: Modeling Algorithms - Boolean FUSE produces incorrect result
authoremv <emv@opencascade.com>
Fri, 20 Sep 2019 05:56:21 +0000 (08:56 +0300)
committerapn <apn@opencascade.com>
Tue, 22 Oct 2019 12:15:45 +0000 (15:15 +0300)
When splitting the shell/face with internal faces/edges use the 'internal' criteria of the face to choose the way to create loops.

Side effect changes:
- When performing Boolean operation - move the objects located far from Origin to the Origin to increase the accuracy of intersections.

17 files changed:
src/BOPAlgo/BOPAlgo_PaveFiller_3.cxx
src/BOPAlgo/BOPAlgo_PaveFiller_5.cxx
src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx
src/BOPAlgo/BOPAlgo_ShellSplitter.cxx
src/BOPAlgo/BOPAlgo_Tools.cxx
src/BOPAlgo/BOPAlgo_Tools.hxx
src/BOPAlgo/BOPAlgo_WireSplitter.lxx
src/BOPAlgo/BOPAlgo_WireSplitter_1.cxx
src/BOPTools/BOPTools_AlgoTools_1.cxx
src/IntTools/IntTools_EdgeEdge.cxx
src/IntTools/IntTools_EdgeFace.hxx
src/IntTools/IntTools_FaceFace.hxx
tests/bugs/modalg_7/bug26876 [new file with mode: 0644]
tests/bugs/modalg_7/bug26882
tests/bugs/modalg_7/bug26883_4
tests/bugs/modalg_7/bug29843_1 [new file with mode: 0644]
tests/bugs/modalg_7/bug29843_2 [new file with mode: 0644]

index 6994be6..1df7f3c 100644 (file)
@@ -89,28 +89,63 @@ class BOPAlgo_EdgeEdge :
   Handle(BOPDS_PaveBlock)& PaveBlock2() {
     return myPB2;
   }
-  // 
+  //
+  void SetBoxes (const Bnd_Box& theBox1,
+                 const Bnd_Box& theBox2)
+  {
+    myBox1 = theBox1;
+    myBox2 = theBox2;
+  }
+  //
   void SetFuzzyValue(const Standard_Real theFuzz) {
     IntTools_EdgeEdge::SetFuzzyValue(theFuzz);
   }
   //
   virtual void Perform() {
     BOPAlgo_Algo::UserBreak();
+    TopoDS_Edge anE1 = myEdge1, anE2 = myEdge2;
+    Standard_Boolean hasTrsf = false;
     try
     {
       OCC_CATCH_SIGNALS
 
+      gp_Trsf aTrsf;
+      if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
+      {
+        // Shapes are located far from origin, move the shapes to the origin,
+        // to increase the accuracy of intersection.
+        TopLoc_Location aLoc (aTrsf);
+        myEdge1.Move (aLoc);
+        myEdge2.Move (aLoc);
+        hasTrsf = Standard_True;
+      }
+
       IntTools_EdgeEdge::Perform();
     }
     catch (Standard_Failure const&)
     {
       AddError(new BOPAlgo_AlertIntersectionFailed);
     }
+
+    myEdge1 = anE1;
+    myEdge2 = anE2;
+    if (hasTrsf)
+    {
+      for (Standard_Integer i = 1; i <= myCommonParts.Length(); ++i)
+      {
+        IntTools_CommonPrt& aCPart = myCommonParts (i);
+        aCPart.SetEdge1 (myEdge1);
+        aCPart.SetEdge2 (myEdge2);
+      }
+    }
+
   }
   //
  protected:
   Handle(BOPDS_PaveBlock) myPB1;
   Handle(BOPDS_PaveBlock) myPB2;
+  Bnd_Box myBox1;
+  Bnd_Box myBox2;
 };
 //
 //=======================================================================
@@ -216,6 +251,7 @@ void BOPAlgo_PaveFiller::PerformEE()
         //
         anEdgeEdge.SetEdge1(aE1, aT11, aT12);
         anEdgeEdge.SetEdge2(aE2, aT21, aT22);
+        anEdgeEdge.SetBoxes (aBB1, aBB2);
         anEdgeEdge.SetFuzzyValue(myFuzzyValue);
         anEdgeEdge.SetProgressIndicator(myProgressIndicator);
       }//for (; aIt2.More(); aIt2.Next()) {
@@ -924,6 +960,8 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
   if (!aNbPB)
     return;
 
+  const Standard_Boolean bSICheckMode = (myArguments.Extent() == 1);
+
   // Prepare pave blocks with the same vertices for intersection.
   BOPAlgo_VectorOfEdgeEdge aVEdgeEdge;
 
@@ -940,10 +978,12 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
     const TopoDS_Vertex& aV1 = TopoDS::Vertex(myDS->Shape(nV1));
     const TopoDS_Vertex& aV2 = TopoDS::Vertex(myDS->Shape(nV2));
 
-    // Use the max tolerance of vertices as Fuzzy value for intersection
-    // of edges
-    Standard_Real aTolAdd = 2 * Max(BRep_Tool::Tolerance(aV1),
-                                    BRep_Tool::Tolerance(aV2));
+    // Use the max tolerance of vertices as Fuzzy value for intersection of edges.
+    // In the Self-Interference check mode we are interested in real
+    // intersections only, so use only the real tolerance of edges,
+    // no need to use the extended tolerance.
+    Standard_Real aTolAdd = (bSICheckMode ? myFuzzyValue :
+      2 * Max(BRep_Tool::Tolerance(aV1), BRep_Tool::Tolerance(aV2)));
 
     // All possible pairs combined from the list <aLPB> should be checked
     BOPDS_ListIteratorOfListOfPaveBlock aItLPB1(aLPB);
@@ -1022,6 +1062,7 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
         anEdgeEdge.SetPaveBlock2(aPB2);
         anEdgeEdge.SetEdge1(aE1, aT11, aT12);
         anEdgeEdge.SetEdge2(aE2, aT21, aT22);
+        anEdgeEdge.SetBoxes (myDS->ShapeInfo(nE1).Box(), myDS->ShapeInfo (nE2).Box());
         if (bUseAddTol)
           anEdgeEdge.SetFuzzyValue(myFuzzyValue + aTolAdd);
         else
index 7248bf9..933f3c7 100644 (file)
@@ -105,18 +105,50 @@ class BOPAlgo_EdgeFace :
     IntTools_EdgeFace::SetFuzzyValue(theFuzz);
   }
   //
+  void SetBoxes (const Bnd_Box& theBox1,
+                 const Bnd_Box& theBox2)
+  {
+    myBox1 = theBox1;
+    myBox2 = theBox2;
+  }
+  //
   virtual void Perform() {
     BOPAlgo_Algo::UserBreak();
+    TopoDS_Face aFace = myFace;
+    TopoDS_Edge anEdge = myEdge;
+    Standard_Boolean hasTrsf = false;
     try
     {
       OCC_CATCH_SIGNALS
 
+      gp_Trsf aTrsf;
+      if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
+      {
+        // Shapes are located far from origin, move the shapes to the origin,
+        // to increase the accuracy of intersection.
+        TopLoc_Location aLoc (aTrsf);
+        myEdge.Move (aLoc);
+        myFace.Move (aLoc);
+        hasTrsf = Standard_True;
+      }
+
       IntTools_EdgeFace::Perform();
     }
     catch (Standard_Failure const&)
     {
       AddError(new BOPAlgo_AlertIntersectionFailed);
     }
+    myFace = aFace;
+    myEdge = anEdge;
+
+    if (hasTrsf)
+    {
+      for (Standard_Integer i = 1; i <= mySeqOfCommonPrts.Length(); ++i)
+      {
+        IntTools_CommonPrt& aCPart = mySeqOfCommonPrts (i);
+        aCPart.SetEdge1 (myEdge);
+      }
+    }
   }
   //
  protected:
@@ -124,6 +156,8 @@ class BOPAlgo_EdgeFace :
   Standard_Integer myIF;
   IntTools_Range myNewSR;
   Handle(BOPDS_PaveBlock) myPB;
+  Bnd_Box myBox1;
+  Bnd_Box myBox2;
 };
 //
 //=======================================================================
@@ -231,6 +265,7 @@ void BOPAlgo_PaveFiller::PerformEF()
       //
       aEdgeFace.SetEdge (aE);
       aEdgeFace.SetFace (aF);
+      aEdgeFace.SetBoxes (myDS->ShapeInfo(nE).Box(), myDS->ShapeInfo (nF).Box());
       aEdgeFace.SetFuzzyValue(myFuzzyValue);
       aEdgeFace.UseQuickCoincidenceCheck(bExpressCompute);
       //
@@ -756,6 +791,8 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
   // Shake the tree
   aBBTree.Build();
 
+  const Standard_Boolean bSICheckMode = (myArguments.Extent() == 1);
+
   // Find pairs of Face/PaveBlock containing the same vertices
   // and prepare those pairs for intersection.
   BOPAlgo_VectorOfEdgeFace aVEdgeFace;
@@ -874,8 +911,12 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
       // tolerance as the criteria.
       const TopoDS_Vertex& aV1 = TopoDS::Vertex(myDS->Shape(nV1));
       const TopoDS_Vertex& aV2 = TopoDS::Vertex(myDS->Shape(nV2));
-      Standard_Real aTolCheck = 2 * Max(BRep_Tool::Tolerance(aV1),
-                                        BRep_Tool::Tolerance(aV2));
+
+      // In the Self-Interference check mode we are interested in real
+      // intersections only, so use only the real tolerance of edges,
+      // no need to use the extended tolerance.
+      Standard_Real aTolCheck = (bSICheckMode ? myFuzzyValue :
+        2 * Max(BRep_Tool::Tolerance(aV1), BRep_Tool::Tolerance(aV2)));
 
       if (aProjPS.LowerDistance() > aTolCheck + myFuzzyValue)
         continue;
@@ -940,6 +981,7 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
         aEdgeFace.SetPaveBlock(aPB);
         aEdgeFace.SetEdge(aE);
         aEdgeFace.SetFace(aF);
+        aEdgeFace.SetBoxes (myDS->ShapeInfo(nE).Box(), myDS->ShapeInfo (nF).Box());
         aEdgeFace.SetFuzzyValue(myFuzzyValue + aTolAdd);
         aEdgeFace.UseQuickCoincidenceCheck(Standard_True);
         aEdgeFace.SetRange(IntTools_Range(aPB->Pave1().Parameter(), aPB->Pave2().Parameter()));
index 9588e57..5dc2772 100644 (file)
@@ -122,6 +122,12 @@ class BOPAlgo_FaceFace :
     myF2=aF2;
   }
   //
+  void SetBoxes(const Bnd_Box& theBox1,
+                const Bnd_Box& theBox2) {
+    myBox1 = theBox1;
+    myBox2 = theBox2;
+  }
+  //
   const TopoDS_Face& Face1()const {
     return myF1;
   }
@@ -142,13 +148,37 @@ class BOPAlgo_FaceFace :
     IntTools_FaceFace::SetFuzzyValue(theFuzz);
   }
   //
+  const gp_Trsf& Trsf() const { return myTrsf; }
+  //
   virtual void Perform() {
     BOPAlgo_Algo::UserBreak();
     try
     {
       OCC_CATCH_SIGNALS
 
-      IntTools_FaceFace::Perform(myF1, myF2);
+      gp_Trsf aTrsf;
+      TopoDS_Face aF1 = myF1, aF2 = myF2;
+      if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
+      {
+        // Shapes are located far from origin, move the shapes to the origin,
+        // to increase the accuracy of intersection.
+        TopLoc_Location aLoc (aTrsf);
+        aF1.Move (aLoc);
+        aF2.Move (aLoc);
+
+        // The starting point is initialized only with the UV parameters
+        // on the faces - 3D point is not set (see GetEFPnts method),
+        // so no need to transform anything.
+        //for (IntSurf_ListOfPntOn2S::Iterator it (myListOfPnts); it.More(); it.Next())
+        //{
+        //  IntSurf_PntOn2S& aP2S = it.ChangeValue();
+        //  aP2S.SetValue (aP2S.Value().Transformed (aTrsf));
+        //}
+
+        myTrsf = aTrsf.Inverted();
+      }
+
+      IntTools_FaceFace::Perform (aF1, aF2);
     }
     catch (Standard_Failure const&)
     {
@@ -156,12 +186,39 @@ class BOPAlgo_FaceFace :
     }
   }
   //
+  void ApplyTrsf()
+  {
+    if (IsDone())
+    {
+      // Update curves
+      for (Standard_Integer i = 1; i <= mySeqOfCurve.Length(); ++i)
+      {
+        IntTools_Curve& aIC = mySeqOfCurve (i);
+        aIC.Curve()->Transform (myTrsf);
+      }
+      // Update points
+      for (Standard_Integer i = 1; i <= myPnts.Length(); ++i)
+      {
+        IntTools_PntOn2Faces& aP2F = myPnts (i);
+        IntTools_PntOnFace aPOnF1 = aP2F.P1(), aPOnF2 = aP2F.P2();
+        aPOnF1.SetPnt (aPOnF1.Pnt().Transformed (myTrsf));
+        aPOnF2.SetPnt (aPOnF2.Pnt().Transformed (myTrsf));
+        aP2F.SetP1 (aPOnF1);
+        aP2F.SetP2 (aPOnF2);
+      }
+    }
+  }
+
+  //
  protected:
   Standard_Integer myIF1;
   Standard_Integer myIF2;
   Standard_Real myTolFF;
   TopoDS_Face myF1;
   TopoDS_Face myF2;
+  Bnd_Box myBox1;
+  Bnd_Box myBox2;
+  gp_Trsf myTrsf;
 };
 //
 //=======================================================================
@@ -235,6 +292,7 @@ void BOPAlgo_PaveFiller::PerformFF()
       //
       aFaceFace.SetIndices(nF1, nF2);
       aFaceFace.SetFaces(aF1, aF2);
+      aFaceFace.SetBoxes (myDS->ShapeInfo (nF1).Box(), myDS->ShapeInfo (nF2).Box());
       // compute minimal tolerance for the curves
       Standard_Real aTolFF = ToleranceFF(aBAS1, aBAS2);
       aFaceFace.SetTolFF(aTolFF);
@@ -282,6 +340,8 @@ void BOPAlgo_PaveFiller::PerformFF()
     //
     aFaceFace.PrepareLines3D(bSplitCurve);
     //
+    aFaceFace.ApplyTrsf();
+    //
     const IntTools_SequenceOfCurves& aCvsX = aFaceFace.Lines();
     const IntTools_SequenceOfPntOn2Faces& aPntsX = aFaceFace.Points();
     //
@@ -1711,12 +1771,16 @@ void BOPAlgo_PaveFiller::PutBoundPaveOnCurve(const TopoDS_Face& aF1,
   getBoundPaves(myDS, aNC, aBndNV);
   //
   Standard_Real aTolVnew = Precision::Confusion();
+  Standard_Boolean isClosed = aP[1].IsEqual (aP[0], aTolVnew);
+  if (isClosed && (aBndNV[0] > 0 || aBndNV[1] > 0))
+    return;
+
   for (Standard_Integer j = 0; j<2; ++j)
   {
     if (aBndNV[j] < 0)
     {
       // no vertex on this end
-      if (j && aP[1].IsEqual(aP[0], aTolVnew)) {
+      if (j && isClosed) {
         //if curve is closed, process only one bound
         continue;
       }
index 631bb61..108d44f 100644 (file)
@@ -215,11 +215,15 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
   //
   // use only connected faces
   TopTools_ListOfShape aLFConnected;
+  // Boundary faces
+  TopTools_MapOfShape aBoundaryFaces;
   aItF.Initialize (myShapes);
   for (; aItF.More(); aItF.Next()) {
     const TopoDS_Shape& aF = aItF.Value();
     if (aMFaces.Contains(aF)) {
       aLFConnected.Append(aF);
+      if (!aBoundaryFaces.Add (aF))
+        aBoundaryFaces.Remove (aF);
     }
   }
   //
@@ -254,6 +258,7 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
       aItS.Initialize(aShell);
       for (; aItS.More(); aItS.Next()) {
         const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value()));
+        Standard_Boolean isBoundary = aBoundaryFaces.Contains (aF);
         //
         // loop on edges of aF; find a good neighbor face of aF by aE
         aExp.Init(aF, TopAbs_EDGE);
@@ -289,6 +294,8 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
           // take only not-processed faces as a candidates
           BOPTools_ListOfCoupleOfShape aLCSOff;
           //
+          Standard_Integer aNbWaysInside = 0;
+          TopoDS_Face aSelF;
           TopTools_ListIteratorOfListOfShape aItLF(aLF);
           for (; aItLF.More(); aItLF.Next()) {
             const TopoDS_Face& aFL = (*(TopoDS_Face*)(&aItLF.Value()));
@@ -301,6 +308,11 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
               continue;
             }
             //
+            if (isBoundary && !aBoundaryFaces.Contains (aFL))
+            {
+              ++aNbWaysInside;
+              aSelF = aFL;
+            }
             aCSOff.SetShape1(aEL);
             aCSOff.SetShape2(aFL);
             aLCSOff.Append(aCSOff);
@@ -313,12 +325,14 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
           //
           // among all the adjacent faces chose one with the minimal
           // angle to the current one
-          TopoDS_Face aSelF;
-          if (aNbOff == 1) {
-            aSelF = (*(TopoDS_Face*)(&aLCSOff.First().Shape2()));
-          }
-          else if (aNbOff > 1) {
-            BOPTools_AlgoTools::GetFaceOff(aE, aF, aLCSOff, aSelF, aContext);
+          if (!isBoundary || aNbWaysInside != 1)
+          {
+            if (aNbOff == 1) {
+              aSelF = (*(TopoDS_Face*)(&aLCSOff.First().Shape2()));
+            }
+            else if (aNbOff > 1) {
+              BOPTools_AlgoTools::GetFaceOff(aE, aF, aLCSOff, aSelF, aContext);
+            }
           }
           //
           if (!aSelF.IsNull() && AddedFacesMap.Add(aSelF)) {
index b5b7625..714708a 100644 (file)
@@ -1756,3 +1756,30 @@ void BOPAlgo_Tools::FillInternals(const TopTools_ListOfShape& theSolids,
     }
   }
 }
+
+//=======================================================================
+//function : TrsfToPoint
+//purpose  :
+//=======================================================================
+Standard_Boolean BOPAlgo_Tools::TrsfToPoint (const Bnd_Box& theBox1,
+                                             const Bnd_Box& theBox2,
+                                             gp_Trsf&       theTrsf,
+                                             const gp_Pnt&  thePoint,
+                                             const Standard_Real theCriteria)
+{
+  // Unify two boxes
+  Bnd_Box aBox = theBox1;
+  aBox.Add (theBox2);
+
+  gp_XYZ aBCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) / 2.;
+  Standard_Real aPBDist = (thePoint.XYZ() - aBCenter).Modulus();
+  if (aPBDist < theCriteria)
+    return Standard_False;
+  
+  Standard_Real aBSize = Sqrt (aBox.SquareExtent());
+  if ((aBSize / aPBDist) > (1. / theCriteria))
+    return Standard_False;
+
+  theTrsf.SetTranslation (gp_Vec (aBox.CornerMin(), thePoint));
+  return Standard_True;
+}
index 9d20dd3..1185394 100644 (file)
@@ -205,6 +205,20 @@ public:
                                             const TopTools_DataMapOfShapeListOfShape& theImages,
                                             const Handle(IntTools_Context)& theContext);
 
+  //! Computes the transformation needed to move the objects
+  //! to the given point to increase the quality of computations.
+  //! Returns true if the objects are located far from the given point
+  //! (relatively given criteria), false otherwise.
+  //! @param theBox1 the AABB of the first object
+  //! @param theBox2 the AABB of the second object
+  //! @param theTrsf the computed transformation
+  //! @param thePoint the Point to compute transformation to
+  //! @param theCriteria the Criteria to check whether thranformation is required
+  Standard_EXPORT static Standard_Boolean TrsfToPoint (const Bnd_Box& theBox1,
+                                                       const Bnd_Box& theBox2,
+                                                       gp_Trsf&       theTrsf,
+                                                       const gp_Pnt&  thePoint = gp_Pnt (0.0, 0.0, 0.0),
+                                                       const Standard_Real theCriteria = 1.e+5);
 };
 
 #endif // _BOPAlgo_Tools_HeaderFile
index 9f44253..e6510a4 100644 (file)
@@ -27,7 +27,9 @@ class BOPAlgo_EdgeInfo {
   BOPAlgo_EdgeInfo() : 
     myPassed(Standard_False),
     myInFlag(Standard_False),
-    myAngle (-1.) {
+    myIsInside (Standard_False),
+    myAngle (-1.)
+  {
   };
   //
   void SetEdge(const TopoDS_Edge& theE) {
@@ -62,10 +64,19 @@ class BOPAlgo_EdgeInfo {
     return myAngle;
   };
   //
+  Standard_Boolean IsInside() const {
+    return myIsInside;
+  };
+  //
+  void SetIsInside (const Standard_Boolean theIsInside) {
+    myIsInside = theIsInside;
+  };
+  //
  protected:
   TopoDS_Edge myEdge;
   Standard_Boolean myPassed;
   Standard_Boolean myInFlag;
+  Standard_Boolean myIsInside;
   Standard_Real myAngle;
 };
 
index 03adb27..fac4bbf 100644 (file)
@@ -166,6 +166,8 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
   MyDataMapOfShapeBoolean aVertMap;
   //
   const TopTools_ListOfShape& myEdges=aCB.Shapes();
+
+  TopTools_MapOfShape aMS;
   //
   // 1.Filling mySmartMap
   aIt.Initialize(myEdges);
@@ -177,6 +179,10 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
     //
     bIsClosed = BRep_Tool::Degenerated(aE) || 
                 BRep_Tool::IsClosed(aE, myFace);
+
+    if (!aMS.Add (aE) && !bIsClosed)
+      aMS.Remove (aE);
+
     //
     aItS.Initialize(aE);
     for(i = 0; aItS.More(); aItS.Next(), ++i) {
@@ -218,7 +224,7 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
   for (i=1; i<=aNb; i++) {
     aCntIn=0;
     aCntOut=0;
-    const BOPAlgo_ListOfEdgeInfo& aLEInfo= mySmartMap(i);
+    const BOPAlgo_ListOfEdgeInfo& aLEInfo = mySmartMap(i);
     BOPAlgo_ListIteratorOfListOfEdgeInfo anIt(aLEInfo);
     for (; anIt.More(); anIt.Next()) {
       const BOPAlgo_EdgeInfo& aEI=anIt.Value();
@@ -304,6 +310,7 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
     for (; aItLEI.More(); aItLEI.Next()) {
       BOPAlgo_EdgeInfo& aEI=aItLEI.ChangeValue();
       const TopoDS_Edge& aE=aEI.Edge();
+      aEI.SetIsInside (!aMS.Contains (aE));
       //
       aVV = aV;
       bIsIN = aEI.IsIn();
@@ -366,7 +373,7 @@ void Path (const GeomAdaptor_Surface& aGAS,
   Standard_Integer i, j, aNb, aNbj;
   Standard_Real anAngleIn, anAngleOut, anAngle, aMinAngle;
   Standard_Real aTol2D, aTol2D2, aD2, aTwoPI;
-  Standard_Boolean anIsSameV2d, anIsSameV, anIsFound, anIsOut, anIsNotPassed;
+  Standard_Boolean anIsSameV2d, anIsSameV, anIsOut, anIsNotPassed;
   Standard_Boolean bIsClosed;
   TopoDS_Vertex aVa, aVb;
   TopoDS_Edge aEOuta;
@@ -501,8 +508,12 @@ void Path (const GeomAdaptor_Surface& aGAS,
     //
     anAngleIn = AngleIn(aEOuta, aLEInfo);
     aMinAngle = 100.;
-    anIsFound = Standard_False;
     Standard_Integer iCnt = NbWaysOut(aLEInfo);
+
+    Standard_Boolean isBoundary = !anEdgeInfo->IsInside();
+    Standard_Integer aNbWaysInside = 0;
+    BOPAlgo_EdgeInfo *pOnlyWayIn = NULL;
+
     Standard_Integer aCurIndexE = 0;
     anIt.Initialize(aLEInfo);
     for (; anIt.More(); anIt.Next()) {
@@ -525,7 +536,6 @@ void Path (const GeomAdaptor_Surface& aGAS,
         if (iCnt==1) {
           // the one and only way to go out .
           pEdgeInfo=&anEI;
-          anIsFound=Standard_True;
           break;
         }
         //
@@ -548,15 +558,25 @@ void Path (const GeomAdaptor_Surface& aGAS,
           anAngleOut=anEI.Angle();
           anAngle=ClockWiseAngle(anAngleIn, anAngleOut);
         }
+
+        if (isBoundary && anEI.IsInside())
+        {
+          ++aNbWaysInside;
+          pOnlyWayIn = &anEI;
+        }
+
         if (anAngle < aMinAngle - eps) {
           aMinAngle=anAngle;
           pEdgeInfo=&anEI;
-          anIsFound=Standard_True;
         }
       }
     } // for (; anIt.More(); anIt.Next()) 
+    if (aNbWaysInside == 1)
+    {
+      pEdgeInfo = pOnlyWayIn;
+    }
     //
-    if (!anIsFound) {
+    if (!pEdgeInfo) {
       // no way to go . (Error)
       return;
     }
index 5832bfa..803f8ba 100644 (file)
@@ -525,6 +525,7 @@ namespace {
   struct EdgeData {
     const TopoDS_Edge* Edge; // Edge
     Standard_Real VParameter; // Parameter of the vertex on the edge
+    Standard_Boolean IsClosed; // Closed flag of the edge
     Geom2dAdaptor_Curve GAdaptor; // 2D adaptor for PCurve of the edge on the face
     Standard_Real First; // First parameter in the range
     Standard_Real Last; // Last parameter in the rage
@@ -610,9 +611,9 @@ static
       continue;
     }
     //
-    if (Abs(aTint1 - aT1) > aHalfR1 ||
-        Abs(aTint2 - aT2) > aHalfR2) {
-      // intersection on the other end of the closed edge
+    if ((!theEData1.IsClosed && Abs (aTint1 - aT1) > aHalfR1) ||
+        (!theEData2.IsClosed && Abs (aTint2 - aT2) > aHalfR2)) {
+      // intersection is on the other end of the edge
       continue;
     }
     //
@@ -634,7 +635,7 @@ void CorrectWires(const TopoDS_Face& aFx,
                   const TopTools_IndexedMapOfShape& aMapToAvoid)
 {
   Standard_Integer i, aNbV;
-  Standard_Real aTol, aTol2, aD2, aD2max, aT1, aT2, aT;
+  Standard_Real aTol, aTol2, aD2, aD2max, aT1, aT2;
   gp_Pnt aP, aPV;
   gp_Pnt2d aP2D;
   TopoDS_Face aF;
@@ -644,11 +645,9 @@ void CorrectWires(const TopoDS_Face& aFx,
   aF=aFx;
   aF.Orientation(TopAbs_FORWARD);
   const Handle(Geom_Surface)& aS=BRep_Tool::Surface(aFx);
-  //
-  TopExp::MapShapesAndAncestors(aF, 
-                                TopAbs_VERTEX, 
-                                TopAbs_EDGE, 
-                                aMVE);
+
+  TopExp::MapShapesAndUniqueAncestors (aF, TopAbs_VERTEX, TopAbs_EDGE, aMVE, Standard_True);
+
   NCollection_DataMap<TopoDS_Shape, Standard_Real> aMapEdgeLen;
   aNbV=aMVE.Extent();
   for (i=1; i<=aNbV; ++i) {
@@ -666,7 +665,13 @@ void CorrectWires(const TopoDS_Face& aFx,
       const TopoDS_Edge& aE=*(TopoDS_Edge*)(&aIt.Value());
       const Handle(Geom2d_Curve)& aC2D=
         BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2);
-      aT=BRep_Tool::Parameter(aV, aE);
+      Standard_Real aT = BRep_Tool::Parameter (aV, aE);
+      Standard_Boolean isClosed = Standard_False;
+      {
+        TopoDS_Vertex aV1, aV2;
+        TopExp::Vertices (aE, aV1, aV2);
+        isClosed = aV1.IsSame (aV2);
+      }
       //
       aC2D->D0(aT, aP2D);
       aS->D0(aP2D.X(), aP2D.Y(), aP);
@@ -674,7 +679,7 @@ void CorrectWires(const TopoDS_Face& aFx,
       if (aD2>aD2max) {
         aD2max=aD2;
       }
-      EdgeData anEData = {&aE, aT, Geom2dAdaptor_Curve(aC2D), aT1, aT2};
+      EdgeData anEData = {&aE, aT, isClosed, Geom2dAdaptor_Curve(aC2D), aT1, aT2};
       aLEPars.Append(anEData);
     }
     //
index 63228f5..91fadaf 100644 (file)
@@ -682,10 +682,14 @@ void IntTools_EdgeEdge::MergeSolutions(const IntTools_SequenceOfRanges& theRange
       aRj2.Range(aTj21, aTj22);
       //
       bCond = (fabs(aTi12 - aTj11) < dTR1) ||
+        (aTj11 > aTi11 && aTj11 < aTi12) ||
+        (aTi11 > aTj11 && aTi11 < aTj12) ||
         (bSplit2 && (fabs(aTj12 - aTi11) < dTR1));
       if (bCond && bSplit2) {
         bCond = (fabs((Max(aTi22, aTj22) - Min(aTi21, aTj21)) - 
-                      ((aTi22 - aTi21) + (aTj22 - aTj21))) < dTR2);
+                      ((aTi22 - aTi21) + (aTj22 - aTj21))) < dTR2) ||
+                        (aTj21 > aTi21 && aTj21 < aTi22) ||
+                          (aTi21 > aTj21 && aTi21 < aTj22);
       }
       //
       if (bCond) {
index 33af356..12c2592 100644 (file)
@@ -196,7 +196,7 @@ protected: //! @name Protected methods performing the intersection
   //! Checks if the edge is in the face really.
   Standard_EXPORT Standard_Boolean IsCoincident();
 
-private:
+protected:
 
   TopoDS_Edge myEdge;
   TopoDS_Face myFace;
index 04ad9d8..8e9d550 100644 (file)
@@ -120,7 +120,7 @@ protected:
   //! and surfaces is computed.
   Standard_EXPORT void ComputeTolReached3d();
 
-private:
+protected:
 
   Standard_Boolean myIsDone;
   IntPatch_Intersection myIntersector;
diff --git a/tests/bugs/modalg_7/bug26876 b/tests/bugs/modalg_7/bug26876
new file mode 100644 (file)
index 0000000..217174e
--- /dev/null
@@ -0,0 +1,40 @@
+puts "============================================================================"
+puts "0026876: Modeling Algorithms - Boolean algorithm fails or produce faulty shape"
+puts "============================================================================"
+puts ""
+
+restore [locate_data_file bug26883_object.brep] o
+restore [locate_data_file bug26883_fuse_tool1.brep] ft1
+restore [locate_data_file bug26883_fuse_tool2.brep] ft2
+restore [locate_data_file bug26876_cut_tool1.brep] ct1
+restore [locate_data_file bug26876_cut_tool2.brep] ct2
+
+bclearobjects
+bcleartools
+baddobjects o
+baddtools ft1 ft2
+bfillds
+bbop result_fuse 1
+
+checkshape result_fuse
+if {![regexp "OK" [bopcheck result_fuse]]} {
+  puts "Error: the result of FUSE operation is a self-interfering shape"
+}
+checkprops result_fuse -s 2117 -v 607.602
+checknbshapes result_fuse -wire 52 -face 44 -shell 3 -solid 1 -t
+
+bclearobjects
+bcleartools
+baddobjects result_fuse
+baddtools ct1 ct2
+bfillds
+bbop result 2
+
+checkshape result
+if {![regexp "OK" [bopcheck result]]} {
+  puts "Error: the result of CUT operation is a self-interfering shape"
+}
+checkprops result -s 2112.67 -v 607.132
+checknbshapes result -wire 50 -face 42 -shell 2 -solid 1 -t
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
index 58a0a52..66f181b 100644 (file)
@@ -1,6 +1,3 @@
-puts "TODO OCC26882 ALL: Error :  is WRONG because number of VERTEX entities in shape"
-puts "TODO OCC26882 ALL: Error :  is WRONG because number of EDGE entities in shape"
-
 puts "========"
 puts "OCC26882"
 puts "========"
index 0365023..201df4f 100644 (file)
@@ -15,10 +15,37 @@ baddobjects b1
 baddtools b2
 bfillds
  
-bbop result 1
+bbop r_0 0
+bbop r_1 1
+bbop r_2 2
+bbop r_3 3
+bbop r_4 4
+bbuild r_5
 
-checkshape result
-checkprops result -s 2116.44 -v 607.276
-checknbshapes result -wire 39 -face 32 -shell 3 -solid 1
+foreach i { 0 1 2 3 4 5} {
+  checkshape r_$i
+  if {![regexp "OK" [bopcheck r_$i]]} {
+    puts "Error: r_$i is self-intersecting shape"
+  }
+}
 
-checkview -display result -2d -path ${imagedir}/${test_image}.png
+checkprops r_0 -s 9.84822 -v 0.639566
+checknbshapes r_0 -wire 7 -face 5 -shell 1 -solid 1 -t
+
+checkprops r_1 -s 2116.61 -v 607.386
+checknbshapes r_1 -wire 40 -face 34 -shell 3 -solid 1 -t
+
+checkprops r_2 -s 2110.46 -v 606.532
+checknbshapes r_2 -wire 36 -face 30 -shell 3 -solid 2 -t
+
+checkprops r_3 -s 15.9958 -v 0.215358
+checknbshapes r_3 -wire 11 -face 9 -shell 2 -solid 2 -t
+
+checkprops r_4 -l 24.818
+checksection r_4 -r 0
+
+checkprops r_5 -s 2146.15 -v 608.026
+checknbshapes r_5 -wire 47 -face 39 -shell 6 -solid 5 -t
+
+
+checkview -display r_1 -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug29843_1 b/tests/bugs/modalg_7/bug29843_1
new file mode 100644 (file)
index 0000000..24e35fe
--- /dev/null
@@ -0,0 +1,48 @@
+puts "========"
+puts "0029843: Modeling Algorithms - Boolean FUSE produces incorrect result"
+puts "========"
+puts ""
+
+restore [locate_data_file bug29843.brep] s
+
+explode s
+bclearobjects
+bcleartools
+baddobjects s_1
+baddtools s_2
+bfillds
+
+bbop r_0 0
+bbop r_1 1
+bbop r_2 2
+bbop r_3 3
+bbop r_4 4
+bbuild r_5
+
+foreach i { 0 1 2 3 4 5} {
+  checkshape r_$i
+  if {![regexp "OK" [bopcheck r_$i]]} {
+    puts "Error: r_$i is self-intersecting shape"
+  }
+}
+
+checkprops r_0 -s 9.84429 -v 0.639311
+checknbshapes r_0 -wire 7 -face 5 -shell 1 -solid 1 -t
+
+checkprops r_1 -s 2121.39 -v 612.41
+checknbshapes r_1 -wire 38 -face 32 -shell 2 -solid 1 -t
+
+checkprops r_2 -s 2113.85 -v 611.569
+checknbshapes r_2 -wire 32 -face 26 -shell 2 -solid 1 -t
+
+checkprops r_3 -s 15.9893 -v 0.215264
+checknbshapes r_3 -wire 11 -face 9 -shell 2 -solid 2 -t
+
+checkprops r_4 -l 24.9725
+checksection r_4 -r 2
+
+checkprops r_5 -s 2139.68 -v 612.402
+checknbshapes r_5 -wire 44 -face 36 -shell 5 -solid 4 -t
+
+checkview -display r_0 -2d -path ${imagedir}/${test_image}.png
+
diff --git a/tests/bugs/modalg_7/bug29843_2 b/tests/bugs/modalg_7/bug29843_2
new file mode 100644 (file)
index 0000000..da78486
--- /dev/null
@@ -0,0 +1,51 @@
+puts "========"
+puts "0029843: Modeling Algorithms - Boolean FUSE produces incorrect result"
+puts "========"
+puts ""
+
+puts "Boolean operation fails on the objects located far from origin (1.e+8)"
+
+restore [locate_data_file bug29843_loc.brep] s
+
+explode s
+bclearobjects
+bcleartools
+baddobjects s_1
+baddtools s_2
+bfillds
+
+bbop r_0 0
+bbop r_1 1
+bbop r_2 2
+bbop r_3 3
+bbop r_4 4
+bbuild r_5
+
+foreach i { 0 1 2 3 4 5} {
+  checkshape r_$i
+  if {![regexp "OK" [bopcheck r_$i]]} {
+    puts "Error: r_$i is self-intersecting shape"
+  }
+}
+
+checkprops r_0 -s 62185.2 -v 1.1761e+06
+checknbshapes r_0 -vertex 6 -edge 9 -wire 5 -face 5 -shell 1 -solid 1 -t
+
+checkprops r_1 -s 1.85327e+06 -v 5.92874e+07
+checknbshapes r_1 -vertex 15 -edge 24 -wire 11 -face 11 -shell 1 -solid 1 -t
+
+checkprops r_2 -s 1.85376e+06 -v 5.78639e+07
+checknbshapes r_2 -vertex 14 -edge 21 -wire 9 -face 9 -shell 1 -solid 1 -t
+
+checkprops r_3 -s 37189.7 -v 247431
+checknbshapes r_3 -vertex 6 -edge 9 -wire 5 -face 5 -shell 1 -solid 1 -t
+
+checkprops r_4 -l 952.189
+checksection r_4 -r 2
+checknbshapes r_4 -vertex 6 -edge 7 -t
+
+checkprops r_5 -s 2.01533e+06 -v 6.04635e+07
+checknbshapes r_5 -vertex 15 -edge 26 -wire 15 -face 15 -shell 3 -solid 3 -t
+
+checkview -display r_2 -2d -path ${imagedir}/${test_image}.png
+