0026894: Intersection algorithm between two infinite cylinders is hanging
authornbv <nbv@opencascade.com>
Thu, 6 Oct 2016 09:57:25 +0000 (12:57 +0300)
committerapn <apn@opencascade.com>
Fri, 7 Oct 2016 10:37:33 +0000 (13:37 +0300)
1. VRange of intersection curve has been limited. As result, too oblong intersection curve(s) will be never returned.
2. Now, purger algorithm is not called for lines obtained by Geom-Geom intersection method.
3. New statuses are entered in IntPatch_ImpImpIntersection class. It makes intersection algorithm more informative and flexible for using.
4. Method IntPatch_ImpImpIntersection::GetStatus() has been created.

Tuning of test case bugs modalg_6/bug26894

src/IntPatch/IntPatch_ImpImpIntersection.hxx
src/IntPatch/IntPatch_ImpImpIntersection.lxx
src/IntPatch/IntPatch_ImpImpIntersection_1.gxx
src/IntPatch/IntPatch_ImpImpIntersection_2.gxx
src/IntPatch/IntPatch_ImpImpIntersection_4.gxx
src/IntPatch/IntPatch_Intersection.cxx
tests/bugs/modalg_6/bug26894 [new file with mode: 0644]

index ece87d6..989cfa2 100644 (file)
@@ -45,10 +45,25 @@ public:
 
   DEFINE_STANDARD_ALLOC
 
-  
+  enum IntStatus
+  {
+    //! OK. Good intersection result.
+    IntStatus_OK,
+
+    //! Intersection curve is too long (e.g. as in the bug #26894).
+    //! We cannot provide precise computation of value and
+    //! derivatives of this curve having used floating-point model
+    //! determined by IEEE 754 standard. As result, OCCT algorithms
+    //! cannot work with that curve correctly.
+    IntStatus_InfiniteSectionCurve,
+
+    //! Algorithm cannot finish correctly.
+    IntStatus_Fail   
+  };
+
   Standard_EXPORT IntPatch_ImpImpIntersection();
   
-  //! Flag theIsReqToKeepRLine has been enterred only for
+  //! Flag theIsReqToKeepRLine has been entered only for
   //! compatibility with TopOpeBRep package. It shall be deleted
   //! after deleting TopOpeBRep.
   //! When intersection result returns IntPatch_RLine and another
@@ -56,7 +71,7 @@ public:
   //! will always keep both lines even if they are coincided.
   Standard_EXPORT IntPatch_ImpImpIntersection(const Handle(Adaptor3d_HSurface)& S1, const Handle(Adaptor3d_TopolTool)& D1, const Handle(Adaptor3d_HSurface)& S2, const Handle(Adaptor3d_TopolTool)& D2, const Standard_Real TolArc, const Standard_Real TolTang, const Standard_Boolean theIsReqToKeepRLine = Standard_False);
   
-  //! Flag theIsReqToKeepRLine has been enterred only for
+  //! Flag theIsReqToKeepRLine has been entered only for
   //! compatibility with TopOpeBRep package. It shall be deleted
   //! after deleting TopOpeBRep.
   //! When intersection result returns IntPatch_RLine and another
@@ -71,8 +86,11 @@ public:
                                 const Standard_Boolean theIsReqToKeepRLine =
                                                                   Standard_False);
   
-  //! Returns True if the calculus was succesfull.
-    Standard_Boolean IsDone() const;
+  //! Returns True if the calculus was successful.
+  Standard_Boolean IsDone() const;
+
+  //! Returns status
+  IntStatus GetStatus() const;
   
   //! Returns true if the is no intersection.
     Standard_Boolean IsEmpty() const;
@@ -116,7 +134,7 @@ private:
 
 
 
-  Standard_Boolean done;
+  IntStatus myDone;
   Standard_Boolean empt;
   Standard_Boolean tgte;
   Standard_Boolean oppo;
index 35d950e..26cf77f 100644 (file)
 
 inline Standard_Boolean IntPatch_ImpImpIntersection::IsDone () const
 {
-  return done;
+  return (GetStatus() != IntStatus_Fail);
+}
+
+inline IntPatch_ImpImpIntersection::IntStatus 
+                      IntPatch_ImpImpIntersection::GetStatus() const
+{
+  return myDone;
 }
 
 inline Standard_Boolean IntPatch_ImpImpIntersection::IsEmpty () const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return empt;
 }
 
 inline Standard_Boolean IntPatch_ImpImpIntersection::TangentFaces () const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return tgte;
 }
 
 inline Standard_Boolean IntPatch_ImpImpIntersection::OppositeFaces () const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   if (!tgte) {Standard_DomainError::Raise();}
   return oppo;
 }
 
 inline Standard_Integer IntPatch_ImpImpIntersection::NbPnts () const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return spnt.Length();
 }
 
 inline const IntPatch_Point& IntPatch_ImpImpIntersection::Point (const Standard_Integer Index) const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return spnt(Index);
 }
 
 inline Standard_Integer IntPatch_ImpImpIntersection::NbLines () const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return slin.Length();
 }
 
 inline const Handle(IntPatch_Line)& IntPatch_ImpImpIntersection::Line (const Standard_Integer Index) const
 {
-  if (!done) {StdFail_NotDone::Raise();}
+  if (!IsDone ()) { StdFail_NotDone::Raise(); }
   return slin(Index);
 }
index e2f049e..75d377d 100644 (file)
@@ -70,19 +70,19 @@ static void ProcessBounds(const Handle(IntPatch_ALine)&,
                          const Standard_Real);
 
 
-static Standard_Boolean IntCyCy(const IntSurf_Quadric& theQuad1,
-                                    const IntSurf_Quadric& theQuad2,
-                                    const Standard_Real theTol3D,
-                                    const Standard_Real theTol2D,
-                                    const Bnd_Box2d& theUVSurf1,
-                                    const Bnd_Box2d& theUVSurf2,
-                                    const Standard_Boolean isTheReverse,
-                                    Standard_Boolean& isTheEmpty,
-                                    Standard_Boolean& isTheSameSurface,
-                                    Standard_Boolean& isTheMultiplePoint,
-                                    IntPatch_SequenceOfLine& theSlin,
-                                    IntPatch_SequenceOfPoint& theSPnt);
-
+static 
+  IntPatch_ImpImpIntersection::IntStatus IntCyCy(const IntSurf_Quadric& theQuad1,
+                                                 const IntSurf_Quadric& theQuad2,
+                                                 const Standard_Real theTol3D,
+                                                 const Standard_Real theTol2D,
+                                                 const Bnd_Box2d& theUVSurf1,
+                                                 const Bnd_Box2d& theUVSurf2,
+                                                 const Standard_Boolean isTheReverse,
+                                                 Standard_Boolean& isTheEmpty,
+                                                 Standard_Boolean& isTheSameSurface,
+                                                 Standard_Boolean& isTheMultiplePoint,
+                                                 IntPatch_SequenceOfLine& theSlin,
+                                                 IntPatch_SequenceOfPoint& theSPnt);
 
 static Standard_Boolean IntCySp(const IntSurf_Quadric&,
                                const IntSurf_Quadric&,
index 5972adf..27560c6 100644 (file)
@@ -26,7 +26,7 @@ static
 //purpose  : 
 //=======================================================================
 IntPatch_ImpImpIntersection::IntPatch_ImpImpIntersection ():
-        done(Standard_False)
+myDone(IntStatus_Fail)
 {
 }
 //=======================================================================
@@ -56,7 +56,7 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
                                           const Standard_Real TolTang,
                                           const Standard_Boolean theIsReqToKeepRLine)
 {
-  done = Standard_False;
+  myDone = IntStatus_Fail;
   spnt.Clear();
   slin.Clear();
 
@@ -151,7 +151,6 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
     //
     case 22:
       { // Cylinder/Cylinder
-        Standard_Boolean isDONE = Standard_False;
         Bnd_Box2d aBox1, aBox2;
 
         const Standard_Real aU1f = S1->FirstUParameter();
@@ -192,16 +191,16 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
 
         if(isReversed)
         {
-          isDONE = IntCyCy(quad2, quad1, TolTang, a2DTol, aBox2, aBox1,
+          myDone = IntCyCy(quad2, quad1, TolTang, a2DTol, aBox2, aBox1,
                                     Standard_True, empt, SameSurf, multpoint, slin, spnt);
         }
         else
         {
-          isDONE = IntCyCy(quad1, quad2, TolTang, a2DTol, aBox1, aBox2,
+          myDone = IntCyCy(quad1, quad2, TolTang, a2DTol, aBox1, aBox2,
                                     Standard_False, empt, SameSurf, multpoint, slin, spnt);
         }
 
-        if (!isDONE)
+        if (myDone == IntPatch_ImpImpIntersection::IntStatus_Fail)
         {
           return;
         }
@@ -305,7 +304,9 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
   }
   //
   if (bEmpty) {
-    done = Standard_True;
+    if (myDone == IntStatus_Fail)
+      myDone = IntStatus_OK;
+
     return;
   }
   //
@@ -408,7 +409,7 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
       }
       //
       oppo = quad1.Normale(Ptreference).Dot(quad2.Normale(Ptreference)) < 0.0;
-      done = Standard_True;
+      myDone = IntStatus_OK;
       return;
     }// if (SameSurf || (all1 && all2)) {
 
@@ -547,7 +548,7 @@ void IntPatch_ImpImpIntersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
       }
     }
   }
-  done = Standard_True;
+  myDone = IntStatus_OK;
 }
 
 //=======================================================================
index f5aca30..a5ac597 100644 (file)
@@ -2487,18 +2487,18 @@ void WorkWithBoundaries::BoundaryEstimation(const gp_Cylinder& theCy1,
 //function : IntCyCy
 //purpose  : 
 //=======================================================================
-Standard_Boolean IntCyCy( const IntSurf_Quadric& theQuad1,
-                          const IntSurf_Quadric& theQuad2,
-                          const Standard_Real theTol3D,
-                          const Standard_Real theTol2D,
-                          const Bnd_Box2d& theUVSurf1,
-                          const Bnd_Box2d& theUVSurf2,
-                          const Standard_Boolean isTheReverse,
-                          Standard_Boolean& isTheEmpty,
-                          Standard_Boolean& isTheSameSurface,
-                          Standard_Boolean& isTheMultiplePoint,
-                          IntPatch_SequenceOfLine& theSlin,
-                          IntPatch_SequenceOfPoint& theSPnt)
+IntPatch_ImpImpIntersection::IntStatus IntCyCy(const IntSurf_Quadric& theQuad1,
+                                               const IntSurf_Quadric& theQuad2,
+                                               const Standard_Real theTol3D,
+                                               const Standard_Real theTol2D,
+                                               const Bnd_Box2d& theUVSurf1,
+                                               const Bnd_Box2d& theUVSurf2,
+                                               const Standard_Boolean isTheReverse,
+                                               Standard_Boolean& isTheEmpty,
+                                               Standard_Boolean& isTheSameSurface,
+                                               Standard_Boolean& isTheMultiplePoint,
+                                               IntPatch_SequenceOfLine& theSlin,
+                                               IntPatch_SequenceOfPoint& theSPnt)
 {
   isTheEmpty = Standard_True;
   isTheSameSurface = Standard_False;
@@ -2513,15 +2513,18 @@ Standard_Boolean IntCyCy( const IntSurf_Quadric& theQuad1,
 
   if (!anInter.IsDone())
   {
-    return Standard_False;
+    return IntPatch_ImpImpIntersection::IntStatus_Fail;
   }
 
   if(anInter.TypeInter() != IntAna_NoGeometricSolution)
   {
-    return CyCyAnalyticalIntersect( theQuad1, theQuad2, anInter,
-                                    theTol3D, isTheReverse, isTheEmpty,
-                                    isTheSameSurface, isTheMultiplePoint,
-                                    theSlin, theSPnt);
+    if (CyCyAnalyticalIntersect(theQuad1, theQuad2, anInter,
+                                theTol3D, isTheReverse, isTheEmpty,
+                                isTheSameSurface, isTheMultiplePoint,
+                                theSlin, theSPnt))
+    {
+      return IntPatch_ImpImpIntersection::IntStatus_OK;
+    }
   }
   
   Standard_Real aUSurf1f = 0.0, //const
@@ -2557,7 +2560,20 @@ Standard_Boolean IntCyCy( const IntSurf_Quadric& theQuad1,
   Bnd_Range aRangeS1, aRangeS2;
   aBoundWork.BoundaryEstimation(aCyl1, aCyl2, aRangeS1, aRangeS2);
   if (aRangeS1.IsVoid() || aRangeS2.IsVoid())
-    return Standard_True;
+    return IntPatch_ImpImpIntersection::IntStatus_OK;
+
+  {
+  //Quotation of the message from issue #26894 (author MSV):
+  //"We should return fail status from intersector if the result should be an
+  //infinite curve of non-analytical type... I propose to define the limit for the
+  //extent as the radius divided by 1e+2 and multiplied by 1e+7.
+  //Thus, taking into account the number of valuable digits (15), we provide reliable
+  //computations with an error not exceeding R/100."
+    const Standard_Real aF = 1.0e+5;
+    const Standard_Real aMaxV1Range = aF*aCyl1.Radius(), aMaxV2Range = aF*aCyl2.Radius();
+    if ((aRangeS1.Delta() > aMaxV1Range) || (aRangeS2.Delta() > aMaxV2Range))
+      return IntPatch_ImpImpIntersection::IntStatus_InfiniteSectionCurve;
+  }
 
   //Boundaries
   const Standard_Integer aNbOfBoundaries = 2;
@@ -2565,7 +2581,7 @@ Standard_Boolean IntCyCy( const IntSurf_Quadric& theQuad1,
   Standard_Real aU1l[aNbOfBoundaries] = {Precision::Infinite(), Precision::Infinite()};
 
   if(!aBoundWork.BoundariesComputing(aU1f, aU1l))
-    return Standard_True;
+    return IntPatch_ImpImpIntersection::IntStatus_OK;
 
   for(Standard_Integer i = 0; i < aNbOfBoundaries; i++)
   {
@@ -3317,7 +3333,7 @@ Standard_Boolean IntCyCy( const IntSurf_Quadric& theQuad1,
     }
   }
   
-  return Standard_True;
+  return IntPatch_ImpImpIntersection::IntStatus_OK;
 }
 
 //=======================================================================
index 41d4dc0..754e89a 100644 (file)
@@ -954,6 +954,9 @@ void IntPatch_Intersection::Perform(const Handle(Adaptor3d_HSurface)&  theS1,
     if(aWL.IsNull())
       continue;
 
+    if (!aWL->IsPurgingAllowed())
+      continue;
+
     Handle(IntPatch_WLine) aRW =
       IntPatch_WLineTool::ComputePurgedWLine(aWL, theS1, theS2, theD1, theD2, RestrictLine);
 
@@ -1329,10 +1332,9 @@ void IntPatch_Intersection::GeomGeomPerfom(const Handle(Adaptor3d_HSurface)& the
 {
   IntPatch_ImpImpIntersection interii(theS1,theD1,theS2,theD2,
                                       myTolArc,myTolTang, theIsReqToKeepRLine);
-  const Standard_Boolean anIS = interii.IsDone();
-  if (anIS)
+  if (interii.IsDone())
   {
-    done = anIS;
+    done = (interii.GetStatus() == IntPatch_ImpImpIntersection::IntStatus_OK);
     empt = interii.IsEmpty();
     if (!empt)
     {
@@ -1650,6 +1652,9 @@ void IntPatch_Intersection::Perform(const Handle(Adaptor3d_HSurface)&  S1,
     if(aWL.IsNull())
       continue;
 
+    if (!aWL->IsPurgingAllowed())
+      continue;
+
     Handle(IntPatch_WLine) aRW =
       IntPatch_WLineTool::ComputePurgedWLine(aWL, S1, S2, D1, D2, Standard_True);
 
diff --git a/tests/bugs/modalg_6/bug26894 b/tests/bugs/modalg_6/bug26894
new file mode 100644 (file)
index 0000000..306b44c
--- /dev/null
@@ -0,0 +1,67 @@
+puts "================"
+puts "OCC26894"
+puts "================"
+puts ""
+#######################################################################
+# Intersection algorithm between two infinite cylinders is hanging
+#######################################################################
+
+# Attention!!!
+# The test on performance meter.
+# On the MASTER it takes:
+# Elapsed time: 0 Hours 0 Minutes 6.3723911111 Seconds
+# CPU user time: 6.15625 seconds
+# CPU system time: 0.0625 seconds
+
+# The intersection curve is almost infinite.
+# Therefore, we must have failed to return
+# any section curve (see comments to the issue #26894).
+set GoodNbCurv 0
+
+restore [locate_data_file bug26884-f1.brep] f1
+restore [locate_data_file bug26884-f2.brep] f2
+
+mksurface ss1 f1
+mksurface ss2 f2
+
+if { ![ catch {intersect result ss1 ss2 } ] } {
+  puts "Error: intersection algorithm must return fail status. But it is not."
+}
+
+set che [whatis result]
+set ind [string first "3d curve" $che]
+if {${ind} >= 0} {
+  #Only variable "result" exists
+  renamevar result result_1
+}
+
+set ic 1
+set AllowRepeate 1
+while { $AllowRepeate != 0 } {
+  set che [whatis result_$ic]
+  set ind [string first "3d curve" $che]
+  if {${ind} < 0} {
+    set AllowRepeate 0
+  } else {
+    display result_$ic
+    
+    bounds result_$ic U1 U2
+    
+    dump U1 U2
+    
+    if {[dval U2-U1] < 1.0e-9} {
+      puts "Error: Wrong curve's range!"
+    }
+    
+    xdistcs result_$ic ss1 U1 U2 10 1.0e-7
+    xdistcs result_$ic ss2 U1 U2 10 1.0e-7
+    
+    incr ic
+  }
+}
+
+if {[expr {$ic - 1}] == $GoodNbCurv} {
+  puts "OK: Number of curves is good!"
+} else {
+  puts "Error: $GoodNbCurv is expected but [expr {$ic - 1}] is found!"
+}