diff --git a/src/IntPatch/IntPatch_ImpImpIntersection.hxx b/src/IntPatch/IntPatch_ImpImpIntersection.hxx index ece87d6db0..989cfa2922 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection.hxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection.hxx @@ -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; diff --git a/src/IntPatch/IntPatch_ImpImpIntersection.lxx b/src/IntPatch/IntPatch_ImpImpIntersection.lxx index 35d950efef..26cf77faee 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection.lxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection.lxx @@ -20,48 +20,54 @@ 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); } diff --git a/src/IntPatch/IntPatch_ImpImpIntersection_1.gxx b/src/IntPatch/IntPatch_ImpImpIntersection_1.gxx index e2f049e236..75d377de48 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection_1.gxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection_1.gxx @@ -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&, diff --git a/src/IntPatch/IntPatch_ImpImpIntersection_2.gxx b/src/IntPatch/IntPatch_ImpImpIntersection_2.gxx index 5972adfd17..27560c692b 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection_2.gxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection_2.gxx @@ -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; } //======================================================================= diff --git a/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx b/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx index f5aca30301..a5ac597dca 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx @@ -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; } //======================================================================= diff --git a/src/IntPatch/IntPatch_Intersection.cxx b/src/IntPatch/IntPatch_Intersection.cxx index 41d4dc01e0..754e89af44 100644 --- a/src/IntPatch/IntPatch_Intersection.cxx +++ b/src/IntPatch/IntPatch_Intersection.cxx @@ -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 index 0000000000..306b44c7ca --- /dev/null +++ b/tests/bugs/modalg_6/bug26894 @@ -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!" +}