From: nbv Date: Wed, 17 Feb 2016 07:31:18 +0000 (+0300) Subject: 0027035: General fuse algorithm loses face X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2FCR27035_680;p=occt-copy.git 0027035: General fuse algorithm loses face Porting the fix for issue #27035 to OCCT 6.8.0. (cherry picked from commit f6f844dc652a256f1aa73c92fea2cf2756bea348) (cherry picked from commit 6dd894d85532a447fd54f59c4504ddd76a99b658) Addition correction in order to avoid compiler warnings/errors. --- diff --git a/src/BOPAlgo/BOPAlgo_Builder_2.cxx b/src/BOPAlgo/BOPAlgo_Builder_2.cxx index eb24e6b96d..e5dc03295c 100644 --- a/src/BOPAlgo/BOPAlgo_Builder_2.cxx +++ b/src/BOPAlgo/BOPAlgo_Builder_2.cxx @@ -59,6 +59,7 @@ #include #include #include +#include static @@ -284,6 +285,9 @@ void BOPAlgo_Builder::BuildSplitFaces() } // const TopoDS_Face& aF=(*(TopoDS_Face*)(&aSI.Shape())); + Standard_Boolean isUClosed = Standard_False, + isVClosed = Standard_False, + isChecked = Standard_False; // bHasFaceInfo=myDS->HasFaceInfo(i); if(!bHasFaceInfo) { @@ -321,8 +325,6 @@ void BOPAlgo_Builder::BuildSplitFaces() for (; aExp.More(); aExp.Next()) { const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current())); anOriE=aE.Orientation(); - bIsDegenerated=BRep_Tool::Degenerated(aE); - bIsClosed=BRep_Tool::IsClosed(aE, aF); // if (!myImages.IsBound(aE)) { if (anOriE==TopAbs_INTERNAL) { @@ -335,8 +337,32 @@ void BOPAlgo_Builder::BuildSplitFaces() else { aLE.Append(aE); } + + continue; + } + + if(!isChecked) + { + const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aF); + GeomLib::IsClosed(aSurf, BRep_Tool::Tolerance(aE), + isUClosed, isVClosed); + + isChecked = Standard_True; + } + + bIsClosed = Standard_False; + + if((isUClosed || isVClosed) && BRep_Tool::IsClosed(aE, aF)) + { + + Standard_Boolean isUIso = Standard_False, isVIso = Standard_False; + BOPTools_AlgoTools2D::IsEdgeIsoline(aE, aF, isUIso, isVIso); + + bIsClosed = ((isUClosed && isUIso) || (isVClosed && isVIso)); } - else {//else 1 + + bIsDegenerated=BRep_Tool::Degenerated(aE); + const BOPCol_ListOfShape& aLIE=myImages.Find(aE); aIt.Initialize(aLIE); for (; aIt.More(); aIt.Next()) { @@ -376,7 +402,6 @@ void BOPAlgo_Builder::BuildSplitFaces() } aLE.Append(aSp); }// for (; aIt.More(); aIt.Next()) { - }// else 1 }// for (; aExp.More(); aExp.Next()) { // // diff --git a/src/BOPTools/BOPTools_AlgoTools2D.cdl b/src/BOPTools/BOPTools_AlgoTools2D.cdl index e62abb1a50..f4aafceaae 100644 --- a/src/BOPTools/BOPTools_AlgoTools2D.cdl +++ b/src/BOPTools/BOPTools_AlgoTools2D.cdl @@ -196,5 +196,13 @@ is ---Purpose: --- Make empty P-Curve of relevant to type --- + + IsEdgeIsoline(myclass; + theE: Edge from TopoDS; + theF: Face from TopoDS; + isTheUIso, isTheVIso: in out Boolean from Standard); + --- Purpose: Checks if CurveOnSurface of theE on theF matches with + -- isoline of theF surface. Sets corresponding values for + -- isTheUIso and isTheVIso variables. end AlgoTools2D; diff --git a/src/BOPTools/BOPTools_AlgoTools2D.cxx b/src/BOPTools/BOPTools_AlgoTools2D.cxx index 712caa7eab..4bbb43c900 100644 --- a/src/BOPTools/BOPTools_AlgoTools2D.cxx +++ b/src/BOPTools/BOPTools_AlgoTools2D.cxx @@ -833,3 +833,39 @@ Standard_Real MaxToleranceEdge (const TopoDS_Face& aF) } return aTolMax; } + +//======================================================================= +//function : IsEdgeIsoline +//purpose : +//======================================================================= +void BOPTools_AlgoTools2D::IsEdgeIsoline( const TopoDS_Edge& theE, + const TopoDS_Face& theF, + Standard_Boolean& isTheUIso, + Standard_Boolean& isTheVIso) +{ + isTheUIso = isTheVIso = Standard_False; + + gp_Vec2d aT; + gp_Pnt2d aP; + Standard_Real aFirst = 0.0, aLast = 0.0; + const Handle(Geom2d_Curve) aPC = BRep_Tool::CurveOnSurface(theE, theF, aFirst, aLast); + + aPC->D1(0.5*(aFirst+aLast), aP, aT); + + const Standard_Real aSqMagn = aT.SquareMagnitude(); + if(aSqMagn <= gp::Resolution()) + return; + + //Normalyze aT + aT /= sqrt(aSqMagn); + + //sin(da) ~ da, when da->0. + const Standard_Real aTol = Precision::Angular(); + const gp_Vec2d aRefVDir(0.0, 1.0), aRefUDir(1.0, 0.0); + + const Standard_Real aDPv = aT.CrossMagnitude(aRefVDir), + aDPu = aT.CrossMagnitude(aRefUDir); + + isTheUIso = (aDPv <= aTol); + isTheVIso = (aDPu <= aTol); +} diff --git a/src/GeomLib/GeomLib.cdl b/src/GeomLib/GeomLib.cdl index cc19f58dd9..2dd259652c 100644 --- a/src/GeomLib/GeomLib.cdl +++ b/src/GeomLib/GeomLib.cdl @@ -287,6 +287,35 @@ is -- 1 for quasysingular (ex.: sphere pole) -- 2 for conical singular point -- 3 if computation impossible (for ex. DU||DV - tangent isolines) + + IsClosed(S: Surface from Geom ; Tol: Real from Standard; + isUClosed, isVClosed: in out Boolean from Standard); + --- Purpose: This method defines if opposite boundaries of surface + -- coincide with given tolerance + + IsBSplUClosed(S: BSplineSurface from Geom; U1, U2, Tol: Real from Standard) + returns Boolean from Standard; + --- Purpose: Returns true if the poles of U1-isoline and the poles of + -- U2-isoline of surface are identical according to tolerance criterion. + -- For rational surfaces Weights(i)*Poles(i) are checked. + + IsBSplVClosed(S: BSplineSurface from Geom; V1, V2, Tol: Real from Standard) + returns Boolean from Standard; + --- Purpose: Returns true if the poles of V1-isoline and the poles of + -- V2-isoline of surface are identical according to tolerance criterion. + -- For rational surfaces Weights(i)*Poles(i) are checked. + + IsBzUClosed(S: BezierSurface from Geom; U1, U2, Tol: Real from Standard) + returns Boolean from Standard; + --- Purpose: Returns true if the poles of U1-isoline and the poles of + -- U2-isoline of surface are identical according to tolerance criterion. + + IsBzVClosed(S: BezierSurface from Geom; V1, V2, Tol: Real from Standard) + returns Boolean from Standard; + --- Purpose: Returns true if the poles of V1-isoline and the poles of + -- V2-isoline of surface are identical according to tolerance criterion. + + end GeomLib; diff --git a/src/GeomLib/GeomLib.cxx b/src/GeomLib/GeomLib.cxx index 90fff06966..bcab45cfd7 100644 --- a/src/GeomLib/GeomLib.cxx +++ b/src/GeomLib/GeomLib.cxx @@ -138,6 +138,12 @@ #include +static Standard_Boolean CompareWeightPoles(const TColgp_Array1OfPnt& thePoles1, + const TColStd_Array1OfReal* const theW1, + const TColgp_Array1OfPnt& thePoles2, + const TColStd_Array1OfReal* const theW2, + const Standard_Real theTol); + //======================================================================= //function : ComputeLambda //purpose : Calcul le facteur lambda qui minimise la variation de vittesse @@ -2439,4 +2445,358 @@ Standard_Integer GeomLib::NormEstim(const Handle(Geom_Surface)& S, return 3; } +//======================================================================= +//function : IsClosed +//purpose : +//======================================================================= +void GeomLib::IsClosed (const Handle(Geom_Surface)& S, + const Standard_Real Tol, + Standard_Boolean& isUClosed, Standard_Boolean& isVClosed) +{ + isUClosed = Standard_False; + isVClosed = Standard_False; + // + GeomAdaptor_Surface aGAS(S); + GeomAbs_SurfaceType aSType = aGAS.GetType(); + // + Standard_Real Tol2 = Tol * Tol; + switch (aSType) + { + case GeomAbs_Plane: + { + return; + } + case GeomAbs_Cylinder: + case GeomAbs_SurfaceOfExtrusion: + { + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(); + if(Precision::IsInfinite(v1)) + v1 = 0.; + gp_Pnt p1 = aGAS.Value(u1, v1); + gp_Pnt p2 = aGAS.Value(u2, v1); + isUClosed = p1.SquareDistance(p2) <= Tol2; + return; + } + case GeomAbs_Cone: + { + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + //find v with maximal distance from axis + if(!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2))) + { + gp_Cone aCone = aGAS.Cone(); + gp_Pnt anApex = aCone.Apex(); + gp_Pnt P1 = aGAS.Value(u1, v1); + gp_Pnt P2 = aGAS.Value(u1, v2); + if(P2.SquareDistance(anApex) > P1.SquareDistance(anApex)) + { + v1 = v2; + } + } + else + { + v1 = 0.; + } + gp_Pnt p1 = aGAS.Value(u1, v1); + gp_Pnt p2 = aGAS.Value(u2, v1); + isUClosed = p1.SquareDistance(p2) <= Tol2; + return; + } + case GeomAbs_Sphere: + { + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + //find v with maximal distance from axis + if(v1*v2 <= 0.) + { + v1 = 0.; + } + else + { + if(v1 < 0.) + { + v1 = v2; + } + } + gp_Pnt p1 = aGAS.Value(u1, v1); + gp_Pnt p2 = aGAS.Value(u2, v1); + isUClosed = p1.SquareDistance(p2) <= Tol2; + return; + } + case GeomAbs_Torus: + { + Standard_Real ures = aGAS.UResolution(Tol); + Standard_Real vres = aGAS.VResolution(Tol); + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + // + isUClosed = (u2 - u1) >= aGAS.UPeriod() - ures; + isVClosed = (v2 - v1) >= aGAS.VPeriod() - vres; + return; + } + case GeomAbs_BSplineSurface: + { + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + Handle(Geom_BSplineSurface) aBSpl = aGAS.BSpline(); + isUClosed = GeomLib::IsBSplUClosed(aBSpl, u1, u2, Tol); + isVClosed = GeomLib::IsBSplVClosed(aBSpl, v1, v2, Tol); + return; + } + case GeomAbs_BezierSurface: + { + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + Handle(Geom_BezierSurface) aBz = aGAS.Bezier(); + isUClosed = GeomLib::IsBzUClosed(aBz, u1, u2, Tol); + isVClosed = GeomLib::IsBzVClosed(aBz, v1, v2, Tol); + return; + } + case GeomAbs_SurfaceOfRevolution: + case GeomAbs_OffsetSurface: + case GeomAbs_OtherSurface: + { + Standard_Integer nbp = 23; + Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter(); + Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter(); + if(Precision::IsInfinite(v1)) + { + v1 = Sign(1., v1); + } + if(Precision::IsInfinite(v2)) + { + v2 = Sign(1., v2); + } + // + if(aSType == GeomAbs_OffsetSurface || + aSType == GeomAbs_OtherSurface) + { + if(Precision::IsInfinite(u1)) + { + u1 = Sign(1., u1); + } + if(Precision::IsInfinite(u2)) + { + u2 = Sign(1., u2); + } + } + isUClosed = Standard_True; + Standard_Real dt = (v2 - v1) / (nbp - 1); + Standard_Real res = Max(aGAS.UResolution(Tol), Precision::PConfusion()); + if(dt <= res) + { + nbp = RealToInt((v2 - v1) /(2.*res)) + 1; + nbp = Max(nbp, 2); + dt = (v2 - v1) / (nbp - 1); + } + Standard_Real t; + Standard_Integer i; + for(i = 0; i < nbp; ++i) + { + t = (i == nbp-1 ? v2 : v1 + i * dt); + gp_Pnt p1 = aGAS.Value(u1, t); + gp_Pnt p2 = aGAS.Value(u2, t); + if(p1.SquareDistance(p2) > Tol2) + { + isUClosed = Standard_False; + break; + } + } + // + nbp = 23; + isVClosed = Standard_True; + dt = (u2 - u1) / (nbp - 1); + res = Max(aGAS.VResolution(Tol), Precision::PConfusion()); + if(dt <= res) + { + nbp = RealToInt((u2 - u1) /(2.*res)) + 1; + nbp = Max(nbp, 2); + dt = (u2 - u1) / (nbp - 1); + } + for(i = 0; i < nbp; ++i) + { + t = (i == nbp-1 ? u2 : u1 + i * dt); + gp_Pnt p1 = aGAS.Value(t, v1); + gp_Pnt p2 = aGAS.Value(t, v2); + if(p1.SquareDistance(p2) > Tol2) + { + isVClosed = Standard_False; + break; + } + } + return; + } + default: + { + return; + } + } +} + +//======================================================================= +//function : IsBSplUClosed +//purpose : +//======================================================================= +Standard_Boolean GeomLib::IsBSplUClosed (const Handle(Geom_BSplineSurface)& S, + const Standard_Real U1, + const Standard_Real U2, + const Standard_Real Tol) +{ + Handle(Geom_Curve) aCUF = S->UIso( U1 ); + Handle(Geom_Curve) aCUL = S->UIso( U2 ); + if(aCUF.IsNull() || aCUL.IsNull()) + return Standard_False; + Standard_Real Tol2 = 2.*Tol; + Handle(Geom_BSplineCurve) aBsF = Handle(Geom_BSplineCurve)::DownCast(aCUF); + Handle(Geom_BSplineCurve) aBsL = Handle(Geom_BSplineCurve)::DownCast(aCUL); + + TColgp_Array1OfPnt aPF(1, aBsF->NbPoles()), aPL(1, aBsL->NbPoles()); + aBsF->Poles(aPF); + aBsL->Poles(aPL); + + TColStd_Array1OfReal *aWF = 0, *aWL = 0; + if(aBsF->IsRational()) + { + aWF = new TColStd_Array1OfReal(aPF.Lower(), aPF.Upper()); + aBsF->Weights(*aWF); + } + + if(aBsL->IsRational()) + { + aWL = new TColStd_Array1OfReal(aPL.Lower(), aPL.Upper()); + aBsL->Weights(*aWL); + } + + const Standard_Boolean aRetVal = CompareWeightPoles(aPF, aWF, aPL, aWL, Tol2); + + if(aWF) + delete aWF; + + if(aWL) + delete aWL; + + return aRetVal; +} + +//======================================================================= +//function : IsBSplVClosed +//purpose : +//======================================================================= +Standard_Boolean GeomLib::IsBSplVClosed (const Handle(Geom_BSplineSurface)& S, + const Standard_Real V1, + const Standard_Real V2, + const Standard_Real Tol) +{ + Handle(Geom_Curve) aCVF = S->VIso( V1 ); + Handle(Geom_Curve) aCVL = S->VIso( V2 ); + if(aCVF.IsNull() || aCVL.IsNull()) + return Standard_False; + Standard_Real Tol2 = 2.*Tol; + Handle(Geom_BSplineCurve) aBsF = Handle(Geom_BSplineCurve)::DownCast(aCVF); + Handle(Geom_BSplineCurve) aBsL = Handle(Geom_BSplineCurve)::DownCast(aCVL); + TColgp_Array1OfPnt aPF(1, aBsF->NbPoles()), aPL(1, aBsL->NbPoles()); + aBsF->Poles(aPF); + aBsL->Poles(aPL); + + TColStd_Array1OfReal *aWF = 0, *aWL = 0; + if(aBsF->IsRational()) + { + aWF = new TColStd_Array1OfReal(aPF.Lower(), aPF.Upper()); + aBsF->Weights(*aWF); + } + + if(aBsL->IsRational()) + { + aWL = new TColStd_Array1OfReal(aPL.Lower(), aPL.Upper()); + aBsL->Weights(*aWL); + } + const Standard_Boolean aRetVal = CompareWeightPoles(aPF, aWF, aPL, aWL, Tol2); + + if(aWF) + delete aWF; + + if(aWL) + delete aWL; + + return aRetVal; +} +//======================================================================= +//function : IsBzUClosed +//purpose : +//======================================================================= +Standard_Boolean GeomLib::IsBzUClosed (const Handle(Geom_BezierSurface)& S, + const Standard_Real U1, + const Standard_Real U2, + const Standard_Real Tol) +{ + Handle(Geom_Curve) aCUF = S->UIso( U1 ); + Handle(Geom_Curve) aCUL = S->UIso( U2 ); + if(aCUF.IsNull() || aCUL.IsNull()) + return Standard_False; + Standard_Real Tol2 = 2.*Tol; + Handle(Geom_BezierCurve) aBzF = Handle(Geom_BezierCurve)::DownCast(aCUF); + Handle(Geom_BezierCurve) aBzL = Handle(Geom_BezierCurve)::DownCast(aCUL); + TColgp_Array1OfPnt aPF(1, aBzF->NbPoles()), aPL(1, aBzL->NbPoles()); + aBzF->Poles(aPF); + aBzL->Poles(aPL); + // + return CompareWeightPoles(aPF, 0, aPL, 0, Tol2); +} + +//======================================================================= +//function : IsBzVClosed +//purpose : +//======================================================================= +Standard_Boolean GeomLib::IsBzVClosed (const Handle(Geom_BezierSurface)& S, + const Standard_Real V1, + const Standard_Real V2, + const Standard_Real Tol) +{ + Handle(Geom_Curve) aCVF = S->VIso( V1 ); + Handle(Geom_Curve) aCVL = S->VIso( V2 ); + if(aCVF.IsNull() || aCVL.IsNull()) + return Standard_False; + Standard_Real Tol2 = 2.*Tol; + Handle(Geom_BezierCurve) aBzF = Handle(Geom_BezierCurve)::DownCast(aCVF); + Handle(Geom_BezierCurve) aBzL = Handle(Geom_BezierCurve)::DownCast(aCVL); + TColgp_Array1OfPnt aPF(1, aBzF->NbPoles()), aPL(1, aBzL->NbPoles()); + aBzF->Poles(aPF); + aBzL->Poles(aPL); + // + return CompareWeightPoles(aPF, 0, aPL, 0, Tol2); +} + +//======================================================================= +//function : CompareWeightPoles +//purpose : Checks if thePoles1(i)*theW1(i) is equal to thePoles2(i)*theW2(i) +// with tolerance theTol. +// It is necessary for not rational B-splines and Bezier curves +// to set theW1 and theW2 adresses to zero. +//======================================================================= +static Standard_Boolean CompareWeightPoles(const TColgp_Array1OfPnt& thePoles1, + const TColStd_Array1OfReal* const theW1, + const TColgp_Array1OfPnt& thePoles2, + const TColStd_Array1OfReal* const theW2, + const Standard_Real theTol) +{ + if(thePoles1.Length() != thePoles2.Length()) + { + return Standard_False; + } + // + Standard_Integer i = 1; + for( i = 1 ; i <= thePoles1.Length(); i++ ) + { + const Standard_Real aW1 = (theW1 == 0) ? 1.0 : theW1->Value(i); + const Standard_Real aW2 = (theW2 == 0) ? 1.0 : theW2->Value(i); + + gp_XYZ aPole1 = thePoles1.Value(i).XYZ() * aW1; + gp_XYZ aPole2 = thePoles2.Value(i).XYZ() * aW2; + if(!aPole1.IsEqual(aPole2, theTol)) + return Standard_False; + } + // + return Standard_True; +} diff --git a/tests/bugs/modalg_2/bug472_3 b/tests/bugs/modalg_2/bug472_3 index 1e67122a87..d09bbdd479 100755 --- a/tests/bugs/modalg_2/bug472_3 +++ b/tests/bugs/modalg_2/bug472_3 @@ -1,7 +1,6 @@ -#puts "TODO OCC12345 ALL: Faulty shapes in variables faulty_1 to faulty_" -#puts "TODO OCC12345 ALL: Error : The square of result shape is" -puts "TODO OCC12345 ALL: Error : The command is not valid" -puts "TODO OCC12345 ALL: Error : Result shape is WRONG because it must contains" +puts "TODO OCC25917 ALL: Faulty shapes in variables faulty_1 to faulty_" +puts "TODO OCC25917 ALL: Error : The square of result shape" +puts "TODO OCC25917 ALL: Error : Result shape is WRONG" puts "========================" puts " OCC472 " @@ -22,6 +21,6 @@ bfuse result b1 b2 set nb_v_good 5 set nb_e_edge 7 -set square 0 +set square 229.516 set 2dviewer 0 diff --git a/tests/bugs/modalg_5/bug27035 b/tests/bugs/modalg_5/bug27035 new file mode 100644 index 0000000000..1f2255f7c8 --- /dev/null +++ b/tests/bugs/modalg_5/bug27035 @@ -0,0 +1,27 @@ +puts "========" +puts "OCC27035" +puts "========" +puts "" +########################################################################### +# General fuse algorithm loses face +########################################################################### + +restore [locate_data_file bug27035_cmpd.brep] a + +explode a + +bclearobjects +bcleartools + +baddobjects a_1 a_2 + +bfillds +bbuild result + +set nb_w_good 2 +set nb_f_good 2 + +donly result +fit + +set 2dviewer 1