0030913: Invalid result of Fusing slices
authoremv <emv@opencascade.com>
Mon, 19 Aug 2019 05:33:40 +0000 (08:33 +0300)
committerapn <apn@opencascade.com>
Thu, 29 Aug 2019 16:04:39 +0000 (19:04 +0300)
Refactoring of the Line-Line intersection method strengthening the parallel and coincidence criteria to allow almost parallel lines have an intersection point.

src/BRepCheck/BRepCheck_Wire.cxx
src/IntTools/IntTools_EdgeEdge.cxx
tests/bugs/modalg_7/bug30913_1 [new file with mode: 0644]
tests/bugs/modalg_7/bug30913_2 [new file with mode: 0644]

index 062a49d..da035c6 100644 (file)
@@ -1395,7 +1395,7 @@ BRepCheck_Status BRepCheck_Wire::SelfIntersect(const TopoDS_Face& F,
                if (aCT1==GeomAbs_Line && aCT2==GeomAbs_Line) {
                  // check for the two lines coincidence
                  Standard_Real aPAR_T, aT11, aT12, aT21, aT22, aT1m, aT2m;
-                 Standard_Real aD2, aTolE1, aTolE2,  aTol2, aDot;
+                 Standard_Real aD2, aTolE1, aTolE2,  aTol2;
                  gp_Lin2d aL1, aL2;
                  gp_Pnt2d aP1m;
                  //
@@ -1423,14 +1423,10 @@ BRepCheck_Status BRepCheck_Wire::SelfIntersect(const TopoDS_Face& F,
                    if (aT2m>aT21 && aT2m<aT22) {
                      const gp_Dir2d& aDir1=aL1.Direction();
                      const gp_Dir2d& aDir2=aL2.Direction();
-                     aDot=aDir1*aDir2;
-                     if (aDot<0.) {
-                       aDot=-aDot;
-                     }
-                     //
-                     if ((1.-aDot)<5.e-11){//0.00001 rad
-                       localok = Standard_False;
-                       break;// from for (k = 0; k < 2; ++k){...
+                     if (aDir1.IsParallel (aDir2, Precision::Angular()))
+                     {
+                       localok = Standard_False;
+                             break;// from for (k = 0; k < 2; ++k){...
                      }
                    }//if (aT2m>aT21 && aT2m<aT22) {
                  }//if (aD2<aTol2) {
index 1484349..63228f5 100644 (file)
@@ -837,141 +837,139 @@ void IntTools_EdgeEdge::FindBestSolution(const Standard_Real aT11,
 //=======================================================================
 void IntTools_EdgeEdge::ComputeLineLine()
 {
-  Standard_Boolean IsParallel, IsCoincide;
-  Standard_Real aSin, aCos, aAng, aTol;
-  Standard_Real aT1, aT2, aT11, aT12, aT21, aT22;
-  gp_Pnt aP11, aP12;
-  gp_Lin aL1, aL2;
-  gp_Dir aD1, aD2;
-  IntTools_CommonPrt aCommonPrt;
-  //
-  IsParallel = Standard_False;
-  IsCoincide = Standard_False;
-  aTol = myTol*myTol;
-  aL1 = myCurve1.Line();
-  aL2 = myCurve2.Line();
-  aD1 = aL1.Position().Direction();
-  aD2 = aL2.Position().Direction();
-  myRange1.Range(aT11, aT12);
-  myRange2.Range(aT21, aT22);
-  //
-  aCommonPrt.SetEdge1(myEdge1);
-  aCommonPrt.SetEdge2(myEdge2);
-  //
-  aCos = aD1.Dot(aD2);
-  aAng = (aCos >= 0.) ? 2.*(1. - aCos) : 2.*(1. + aCos);
-  //
-  if(aAng <= Precision::Angular()) {
-    IsParallel = Standard_True;
-    if(aL1.SquareDistance(aL2.Location()) <= aTol) {
-      IsCoincide = Standard_True;
-      aP11 = ElCLib::Value(aT11, aL1);
-      aP12 = ElCLib::Value(aT12, aL1);
-    }
+  Standard_Real aTol = myTol * myTol;
+
+  gp_Lin aL1 = myCurve1.Line();
+  gp_Lin aL2 = myCurve2.Line();
+
+  gp_Dir aD1 = aL1.Direction();
+  gp_Dir aD2 = aL2.Direction();
+
+  Standard_Real anAngle = aD1.Angle (aD2);
+  Standard_Boolean IsCoincide = anAngle < Precision::Angular();
+  if (IsCoincide)
+  {
+    if (aL1.SquareDistance (aL2.Location()) > aTol)
+      return;
   }
-  else {
-    aP11 = ElCLib::Value(aT11, aL1);
-    aP12 = ElCLib::Value(aT12, aL1);
-    if(aL2.SquareDistance(aP11) <= aTol && aL2.SquareDistance(aP12) <= aTol) {
-      IsCoincide = Standard_True;
-    }
+
+  Standard_Real aT11, aT12, aT21, aT22;
+  myRange1.Range (aT11, aT12);
+  myRange2.Range (aT21, aT22);
+
+  gp_Pnt aP11 = ElCLib::Value (aT11, aL1);
+  gp_Pnt aP12 = ElCLib::Value (aT12, aL1);
+
+  if (!IsCoincide)
+  {
+    gp_Pnt O2 (aL2.Location());
+    if (!Precision::IsInfinite (aT21) && !Precision::IsInfinite (aT22))
+      O2 = ElCLib::Value ((aT21 + aT22) / 2., aL2);
+
+    gp_Vec aVec1 = gp_Vec (O2, aP11).Crossed (aD2);
+    gp_Vec aVec2 = gp_Vec (O2, aP12).Crossed (aD2);
+
+    Standard_Real aSqDist1 = aVec1.SquareMagnitude();
+    Standard_Real aSqDist2 = aVec2.SquareMagnitude();
+
+    IsCoincide = (aSqDist1 <= aTol && aSqDist2 <= aTol);
+
+    if (!IsCoincide && aVec1.Dot (aVec2) > 0)
+      // the lines do not intersect
+      return;
   }
-  //
-  if (IsCoincide) {
-    Standard_Real t21, t22;
-    //
-    t21 = ElCLib::Parameter(aL2, aP11);
-    t22 = ElCLib::Parameter(aL2, aP12);
-    if((t21 > aT22 && t22 > aT22) || (t21 < aT21 && t22 < aT21)) {
+
+  IntTools_CommonPrt aCommonPrt;
+  aCommonPrt.SetEdge1 (myEdge1);
+  aCommonPrt.SetEdge2 (myEdge2);
+
+  if (IsCoincide)
+  {
+    Standard_Real t21 = ElCLib::Parameter (aL2, aP11);
+    Standard_Real t22 = ElCLib::Parameter (aL2, aP12);
+
+    if ((t21 > aT22 && t22 > aT22) || (t21 < aT21 && t22 < aT21))
+      // projections are out of range
       return;
-    }
-    //
-    Standard_Real temp;
-    if(t21 > t22) {
-      temp = t21;
-      t21 = t22;
-      t22 = temp;
-    }
-    //
-    if(t21 >= aT21) {
-      if(t22 <= aT22) {
-        aCommonPrt.SetRange1(aT11, aT12);
-        aCommonPrt.SetAllNullFlag(Standard_True);
-        aCommonPrt.AppendRange2(t21, t22);
+
+    if (t21 > t22)
+      std::swap (t21, t22);
+
+    if (t21 >= aT21)
+    {
+      if (t22 <= aT22)
+      {
+        aCommonPrt.SetRange1 (aT11, aT12);
+        aCommonPrt.SetAllNullFlag (Standard_True);
+        aCommonPrt.AppendRange2 (t21, t22);
       }
-      else {
-        aCommonPrt.SetRange1(aT11, aT12 - (t22 - aT22));
-        aCommonPrt.AppendRange2(t21, aT22);
+      else
+      {
+        aCommonPrt.SetRange1 (aT11, aT12 - (t22 - aT22));
+        aCommonPrt.AppendRange2 (t21, aT22);
       }
     }
-    else {
-      aCommonPrt.SetRange1(aT11 + (aT21 - t21), aT12);
-      aCommonPrt.AppendRange2(aT21, t22);
+    else
+    {
+      aCommonPrt.SetRange1 (aT11 + (aT21 - t21), aT12);
+      aCommonPrt.AppendRange2 (aT21, t22);
     }
-    aCommonPrt.SetType(TopAbs_EDGE);  
-    myCommonParts.Append(aCommonPrt);
+    aCommonPrt.SetType (TopAbs_EDGE);
+    myCommonParts.Append (aCommonPrt);
     return;
   }
-  //
-  if (IsParallel) {
+
+
+  gp_Vec O1O2 (aL1.Location(), aL2.Location());
+  gp_XYZ aCross = aD1.XYZ().Crossed (aD2.XYZ());
+  Standard_Real aDistLL = O1O2.Dot (gp_Vec (aCross.Normalized()));
+  if (Abs (aDistLL) > myTol)
     return;
-  }
-  //
+
   {
-    TopoDS_Iterator aIt1, aIt2;
-    aIt1.Initialize(myEdge1);
-    for (; aIt1.More(); aIt1.Next()) {
-      const TopoDS_Shape& aV1 = aIt1.Value();
-      aIt2.Initialize(myEdge2);
-      for (; aIt2.More(); aIt2.Next()) {
-        const TopoDS_Shape& aV2 = aIt2.Value();
-        if (aV2.IsSame(aV1)) {
+    // Fast check that no intersection needs to be added
+    for (TopoDS_Iterator it1 (myEdge1); it1.More(); it1.Next())
+    {
+      for (TopoDS_Iterator it2 (myEdge2); it2.More(); it2.Next())
+      {
+        if (it1.Value().IsSame (it2.Value()))
           return;
-        }
       }
     }
   }
-  //
-  aSin = 1. - aCos*aCos;
-  gp_Pnt O1 = aL1.Location();
-  gp_Pnt O2 = aL2.Location();
-  gp_Vec O1O2 (O1, O2);
-  //
-  aT2 = (aD1.XYZ()*(O1O2.Dot(aD1))-(O1O2.XYZ())).Dot(aD2.XYZ());
-  aT2 /= aSin;
-  //
-  if(aT2 < aT21 || aT2 > aT22) {
+
+  Standard_Real aSqSin = aCross.SquareModulus();
+  Standard_Real aT2 = (aD1.XYZ() * (O1O2.Dot (aD1)) - (O1O2.XYZ())).Dot (aD2.XYZ());
+  aT2 /= aSqSin;
+
+  if (aT2 < aT21 || aT2 > aT22)
+    // out of range
     return;
-  }
-  //
-  gp_Pnt aP2(ElCLib::Value(aT2, aL2));
-  aT1 = (gp_Vec(O1, aP2)).Dot(aD1);
-  //
-  if(aT1 < aT11 || aT1 > aT12) {
+
+  gp_Pnt aP2 = ElCLib::Value (aT2, aL2);
+  Standard_Real aT1 = gp_Vec (aL1.Location(), aP2).Dot (aD1);
+
+  if (aT1 < aT11 || aT1 > aT12)
+    // out of range
     return;
-  }
-  //
-  gp_Pnt aP1(ElCLib::Value(aT1, aL1));
-  Standard_Real aDist = aP1.SquareDistance(aP2);
-  //
-  if (aDist > aTol) {
+
+  gp_Pnt aP1 = ElCLib::Value (aT1, aL1);
+  Standard_Real aDist = aP1.SquareDistance (aP2);
+
+  if (aDist > aTol)
+    // no intersection
     return;
-  }
-  //
+
   // compute correct range on the edges
-  Standard_Real anAngle, aDt1, aDt2;
-  //
-  anAngle = aD1.Angle(aD2);
-  //
-  aDt1 = IntTools_Tools::ComputeIntRange(myTol1, myTol2, anAngle);
-  aDt2 = IntTools_Tools::ComputeIntRange(myTol2, myTol1, anAngle);
-  //
-  aCommonPrt.SetRange1(aT1 - aDt1, aT1 + aDt1);
-  aCommonPrt.AppendRange2(aT2 - aDt2, aT2 + aDt2);
-  aCommonPrt.SetType(TopAbs_VERTEX);
-  aCommonPrt.SetVertexParameter1(aT1);
-  aCommonPrt.SetVertexParameter2(aT2);
-  myCommonParts.Append(aCommonPrt);
+  Standard_Real aDt1 = IntTools_Tools::ComputeIntRange (myTol1, myTol2, anAngle);
+  Standard_Real aDt2 = IntTools_Tools::ComputeIntRange (myTol2, myTol1, anAngle);
+
+  aCommonPrt.SetRange1 (aT1 - aDt1, aT1 + aDt1);
+  aCommonPrt.AppendRange2 (aT2 - aDt2, aT2 + aDt2);
+  aCommonPrt.SetType (TopAbs_VERTEX);
+  aCommonPrt.SetVertexParameter1 (aT1);
+  aCommonPrt.SetVertexParameter2 (aT2);
+  myCommonParts.Append (aCommonPrt);
 }
 
 //=======================================================================
diff --git a/tests/bugs/modalg_7/bug30913_1 b/tests/bugs/modalg_7/bug30913_1
new file mode 100644 (file)
index 0000000..a3db016
--- /dev/null
@@ -0,0 +1,37 @@
+puts "========"
+puts "0030913: Invalid result of Fusing slices"
+puts "========"
+puts ""
+
+restore [locate_data_file bug30913_case1.brep] s
+
+bclearobjects
+bcleartools
+set exp [explode s]
+baddobjects s_1
+eval baddtools [lrange $exp 1 end]
+
+# Use gluing Shift option
+bglue 1
+# Avoid History filling
+setfillhistory 0
+
+bfillds
+bbop result 1
+
+checkshape result
+
+unifysamedom result result
+
+checkshape result
+
+checkprops result -s 3.81335e+06 -v 1.39597e+08
+checknbshapes result -vertex 12042 -edge 18169 -wire 6223 -face 6176 -shell 1 -solid 1 -t
+
+if {![regexp "This shape seems to be OK" [bopcheck result]]} {
+  puts "Error: result is a self-intersecting shape"
+}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
+
+boptions -default
\ No newline at end of file
diff --git a/tests/bugs/modalg_7/bug30913_2 b/tests/bugs/modalg_7/bug30913_2
new file mode 100644 (file)
index 0000000..8003c2f
--- /dev/null
@@ -0,0 +1,39 @@
+puts "========"
+puts "0030913: Invalid result of Fusing slices"
+puts "========"
+puts ""
+
+restore [locate_data_file bug30913_case2.brep] s
+
+bclearobjects
+bcleartools
+set exp [explode s]
+baddobjects s_1
+eval baddtools [lrange $exp 1 end]
+
+# Use gluing Shift option
+bglue 1
+# Avoid History filling
+setfillhistory 0
+
+bfillds
+bbop result 1
+
+checkshape result
+
+dchrono unify restart
+unifysamedom result result
+dchrono unify stop counter UNIFY_SD
+
+checkshape result
+
+checkprops result -s 3.89766e+06 -v 1.40733e+08
+checknbshapes result -vertex 46597 -edge 70375 -wire 24212 -face 23995 -shell 1 -solid 1 -t
+
+#if {![regexp "This shape seems to be OK" [bopcheck result]]} {
+#  puts "Error: result is a self-intersecting shape"
+#}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
+
+boptions -default