From ff89fc39f57b9d96b5e341cab135891d874aec61 Mon Sep 17 00:00:00 2001 From: emv Date: Thu, 26 Sep 2019 14:50:10 +0300 Subject: [PATCH] 0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface When collecting the points to build plane use the points on the curve instead of poles (in case of BSpline and Bezier curves). Side effect changes: Changes in Geom2dHatch_Elements are to increase the chance of correct 2d classification (by the means of Geom2dHatch_Classifier) by taking more than just one point on the edge to construct the classification ray and by checking if this ray is not tangent to the edge itself. --- src/BRepLib/BRepLib_FindSurface.cxx | 286 +++++++++----------- src/Geom2dHatch/Geom2dHatch_Elements.cxx | 102 +++++-- src/Geom2dHatch/Geom2dHatch_Elements.hxx | 2 +- tests/bugs/modalg_6/bug6768 | 2 +- tests/mkface/mkplane/bug30878_1 | 22 ++ tests/mkface/mkplane/bug30878_2 | 11 + tests/offset/wire_unclosed_outside_0_005/C1 | 14 +- tests/offset/wire_unclosed_outside_0_025/B2 | 4 +- 8 files changed, 244 insertions(+), 199 deletions(-) create mode 100644 tests/mkface/mkplane/bug30878_1 create mode 100644 tests/mkface/mkplane/bug30878_2 diff --git a/src/BRepLib/BRepLib_FindSurface.cxx b/src/BRepLib/BRepLib_FindSurface.cxx index ae942259b8..41dc6a5648 100644 --- a/src/BRepLib/BRepLib_FindSurface.cxx +++ b/src/BRepLib/BRepLib_FindSurface.cxx @@ -55,6 +55,7 @@ #include #include #include +#include //======================================================================= //function : Controle @@ -174,6 +175,70 @@ BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape& S, { Init(S,Tol,OnlyPlane,OnlyClosed); } + +namespace +{ +static void fillParams (const TColStd_Array1OfReal& theKnots, + Standard_Integer theDegree, + Standard_Real theParMin, + Standard_Real theParMax, + NCollection_Vector& theParams) +{ + Standard_Real aPrevPar = theParMin; + theParams.Append (aPrevPar); + + Standard_Integer aNbP = Max (theDegree, 1); + + for (Standard_Integer i = 1; + (i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i) + { + if (theKnots (i + 1) < theParMin + Precision::PConfusion()) + continue; + + Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP; + for (Standard_Integer k = 1; k <= aNbP ; ++k) + { + Standard_Real aPar = theKnots (i) + k * aStep; + if (aPar > theParMax - Precision::PConfusion()) + break; + + if (aPar > aPrevPar + Precision::PConfusion()) + { + theParams.Append (aPar); + aPrevPar = aPar; + } + } + } + theParams.Append (theParMax); +} + +static void fillPoints (const BRepAdaptor_Curve& theCurve, + const NCollection_Vector theParams, + TColgp_SequenceOfPnt& thePoints, + TColStd_SequenceOfReal& theWeights) +{ + Standard_Real aDistPrev = 0., aDistNext; + gp_Pnt aPPrev (theCurve.Value (theParams (0))), aPNext; + + for (Standard_Integer iP = 1; iP <= theParams.Length(); ++iP) + { + if (iP < theParams.Length()) + { + Standard_Real aParam = theParams (iP); + aPNext = theCurve.Value (aParam); + aDistNext = aPPrev.Distance (aPNext); + } + else + aDistNext = 0.0; + + thePoints.Append (aPPrev); + theWeights.Append (aDistPrev + aDistNext); + aDistPrev = aDistNext; + aPPrev = aPNext; + } +} + +} //======================================================================= //function : Init //purpose : @@ -282,117 +347,56 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape& S, } Standard_Integer iNbPoints=0; - // Add the points with weights to the sequences + // Fill the parameters of the sampling points + NCollection_Vector aParams; switch (c.GetType()) { - case GeomAbs_BezierCurve: + case GeomAbs_BezierCurve: { - // Put all poles for bezier Handle(Geom_BezierCurve) GC = c.Bezier(); - Standard_Integer iNbPol = GC->NbPoles(); - Standard_Real tf = GC->FirstParameter(); - Standard_Real tl = GC->LastParameter(); - Standard_Real r = (dfUl - dfUf) / (tl - tf); - r *= iNbPol; - if ( iNbPol < 2 || r < 1.) - // Degenerate - continue; - else - { - Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol); - GC->Poles(aPoles->ChangeArray1()); - gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext; - Standard_Real dfDistPrev = 0., dfDistNext; - for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++) - { - if (iPolValue(iPol+1); - dfDistNext = aPolePrev.Distance(aPoleNext); - } - else - dfDistNext = 0.; - aPoints.Append (aPolePrev); - aWeight.Append (dfDistPrev+dfDistNext); - dfDistPrev = dfDistNext; - aPolePrev = aPoleNext; - } - } + TColStd_Array1OfReal aKnots (1, 2); + aKnots.SetValue (1, GC->FirstParameter()); + aKnots.SetValue (2, GC->LastParameter()); + + fillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams); + break; } - break; - case GeomAbs_BSplineCurve: + case GeomAbs_BSplineCurve: { - // Put all poles for bspline Handle(Geom_BSplineCurve) GC = c.BSpline(); - Standard_Integer iNbPol = GC->NbPoles(); - Standard_Real tf = GC->FirstParameter(); - Standard_Real tl = GC->LastParameter(); - Standard_Real r = (dfUl - dfUf) / (tl - tf); - r *= iNbPol; - if ( iNbPol < 2 || r < 1.) - // Degenerate - continue; - else - { - Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol); - GC->Poles(aPoles->ChangeArray1()); - gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext; - Standard_Real dfDistPrev = 0., dfDistNext; - for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++) - { - if (iPolValue(iPol+1); - dfDistNext = aPolePrev.Distance(aPoleNext); - } - else - dfDistNext = 0.; - aPoints.Append (aPolePrev); - aWeight.Append (dfDistPrev+dfDistNext); - dfDistPrev = dfDistNext; - aPolePrev = aPoleNext; - } - } + fillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams); } - break; - - case GeomAbs_Line: - case GeomAbs_Circle: - case GeomAbs_Ellipse: - case GeomAbs_Hyperbola: - case GeomAbs_Parabola: - // Two points on straight segment, Four points on otheranalitical curves - iNbPoints = (c.GetType() == GeomAbs_Line ? 2 : 4); - Standard_FALLTHROUGH - default: + case GeomAbs_Line: + { + // Two points on a straight segment + aParams.Append (dfUf); + aParams.Append (dfUl); + break; + } + case GeomAbs_Circle: + case GeomAbs_Ellipse: + case GeomAbs_Hyperbola: + case GeomAbs_Parabola: + // Four points on other analytical curves + iNbPoints = 4; + Standard_FALLTHROUGH + default: { // Put some points on other curves - if (iNbPoints==0) - iNbPoints = 15 + c.NbIntervals(GeomAbs_C3); - Standard_Real dfDelta = (dfUl-dfUf)/(iNbPoints-1); - Standard_Integer iPoint; - Standard_Real dfU; - gp_Pnt aPointPrev = c.Value(dfUf), aPointNext; - Standard_Real dfDistPrev = 0., dfDistNext; - for (iPoint=1, dfU=dfUf+dfDelta; - iPoint<=iNbPoints; - iPoint++, dfU+=dfDelta) - { - if (iPoint dfSide*myTolerance) { - Handle(Geom_Plane) aPlane2 = new Geom_Plane(aBaryCenter, aCross); - Standard_Real dfDist2 = Controle (aPoints, aPlane2); - if (dfDist2 < myTolerance) { - myTolReached = dfDist2; - mySurface = aPlane2; - return; - } - if (dfDist2 < dfDist) { - dfDist = dfDist2; - aPlane = aPlane2; - } - } - } - } - } - // - //XXf - //static Standard_Real weakness = 5.0; - Standard_Real weakness = 5.0; - //XXf - if(dfDist <= myTolerance || (dfDist < myTolerance*weakness && Tol<0)) { - //XXf - //myTolReached = dfDist; - //XXt + gp_Vec aN (aVec (1), aVec (2), aVec (3)); + Handle(Geom_Plane) aPlane = new Geom_Plane (aBaryCenter, aN); + myTolReached = Controle (aPoints, aPlane); + const Standard_Real aWeakness = 5.0; + if (myTolReached <= myTolerance || (Tol < 0 && myTolReached < myTolerance * aWeakness)) + { mySurface = aPlane; //If S is wire, try to orient surface according to orientation of wire. - if(S.ShapeType() == TopAbs_WIRE && S.Closed()) + if (S.ShapeType() == TopAbs_WIRE && S.Closed()) { - // - TopoDS_Wire aW = TopoDS::Wire(S); - TopoDS_Face aTmpFace = BRepLib_MakeFace(mySurface, Precision::Confusion()); + TopoDS_Wire aW = TopoDS::Wire (S); + TopoDS_Face aTmpFace = BRepLib_MakeFace (mySurface, Precision::Confusion()); BRep_Builder BB; - BB.Add(aTmpFace, aW); - BRepTopAdaptor_FClass2d FClass(aTmpFace, 0.); - if ( FClass.PerformInfinitePoint() == TopAbs_IN ) + BB.Add (aTmpFace, aW); + BRepTopAdaptor_FClass2d FClass (aTmpFace, 0.); + if (FClass.PerformInfinitePoint() == TopAbs_IN) { - gp_Dir aN = aPlane->Position().Direction(); - aN.Reverse(); - mySurface = new Geom_Plane(aPlane->Position().Location(), aN); + gp_Dir aNorm = aPlane->Position().Direction(); + aNorm.Reverse(); + mySurface = new Geom_Plane (aPlane->Position().Location(), aNorm); } - } } - //XXf - myTolReached = dfDist; - //XXt } //======================================================================= //function : Found diff --git a/src/Geom2dHatch/Geom2dHatch_Elements.cxx b/src/Geom2dHatch/Geom2dHatch_Elements.cxx index acd872b2aa..5db9310177 100644 --- a/src/Geom2dHatch/Geom2dHatch_Elements.cxx +++ b/src/Geom2dHatch/Geom2dHatch_Elements.cxx @@ -28,6 +28,11 @@ #include #include #include +#include + +static const Standard_Real Probing_Start = 0.123; +static const Standard_Real Probing_End = 0.8; +static const Standard_Real Probing_Step = 0.2111; Geom2dHatch_Elements::Geom2dHatch_Elements(const Geom2dHatch_Elements& ) { @@ -41,6 +46,7 @@ Geom2dHatch_Elements::Geom2dHatch_Elements() NumWire = 0; NumEdge = 0; myCurEdge = 1; + myCurEdgePar = Probing_Start; } void Geom2dHatch_Elements::Clear() @@ -102,7 +108,7 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P, Standard_Real& Par) { myCurEdge = 1; - + myCurEdgePar = Probing_Start; return OtherSegment(P, L, Par); } @@ -111,43 +117,91 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P, //purpose : //======================================================================= -Standard_Boolean Geom2dHatch_Elements::OtherSegment(const gp_Pnt2d& P, - gp_Lin2d& L, - Standard_Real& Par) +Standard_Boolean Geom2dHatch_Elements::OtherSegment (const gp_Pnt2d& P, + gp_Lin2d& L, + Standard_Real& Par) { Geom2dHatch_DataMapIteratorOfMapOfElements Itertemp; Standard_Integer i; - for( Itertemp.Initialize(myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++) { + for (Itertemp.Initialize (myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++) + { if (i < myCurEdge) continue; void *ptrmyMap = (void *)(&myMap); - Geom2dHatch_Element& Item=((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind(Itertemp.Key()); + Geom2dHatch_Element& Item = ((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind (Itertemp.Key()); Geom2dAdaptor_Curve& E = Item.ChangeCurve(); - TopAbs_Orientation Or= Item.Orientation(); - gp_Pnt2d P2 = E.Value - ((E.FirstParameter() + E.LastParameter()) *0.5); - if ((Or == TopAbs_FORWARD) || - (Or == TopAbs_REVERSED)) { - gp_Vec2d V(P,P2); - Par = V.Magnitude(); - if (Par >= gp::Resolution()) { - L = gp_Lin2d(P,V); - myCurEdge++; - return Standard_True; + TopAbs_Orientation Or = Item.Orientation(); + if (Or == TopAbs_FORWARD || Or == TopAbs_REVERSED) + { + Standard_Real aFPar = E.FirstParameter(), aLPar = E.LastParameter(); + if (Precision::IsNegativeInfinite (aFPar)) + { + if (Precision::IsPositiveInfinite (aLPar)) + { + aFPar = -1.; + aLPar = 1.; + } + else + aFPar = aLPar - 1.; + } + else if (Precision::IsPositiveInfinite (aLPar)) + aLPar = aFPar + 1.; + + for (; myCurEdgePar < Probing_End; myCurEdgePar += Probing_Step) + { + Standard_Real aParam = myCurEdgePar * aFPar + (1. - myCurEdgePar) * aLPar; + gp_Vec2d aTanVec; + gp_Pnt2d aPOnC; + E.D1 (aParam, aPOnC, aTanVec); + gp_Vec2d aLinVec (P, aPOnC); + Par = aLinVec.SquareMagnitude(); + if (Par > Precision::SquarePConfusion()) + { + gp_Dir2d aLinDir (aLinVec); + Standard_Real aTanMod = aTanVec.SquareMagnitude(); + if (aTanMod < Precision::SquarePConfusion()) + continue; + + aTanVec /= Sqrt (aTanMod); + Standard_Real aSinA = aTanVec.Crossed (aLinDir); + if (Abs (aSinA) < 0.001) + { + // too small angle - line and edge may be considered + // as tangent which is bad for classifier + if (myCurEdgePar + Probing_Step < Probing_End) + continue; + } + + L = gp_Lin2d (P, aLinDir); + + aPOnC = E.Value (aFPar); + if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion()) + { + aPOnC = E.Value (aLPar); + if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion()) + { + myCurEdgePar += Probing_Step; + if (myCurEdgePar >= Probing_End) + { + myCurEdge++; + myCurEdgePar = Probing_Start; + } + Par = Sqrt (Par); + return Standard_True; + } + } + } } } - } - - if (i == myCurEdge + 1) { - Par = RealLast(); - L = gp_Lin2d(P,gp_Dir2d(1,0)); myCurEdge++; - - return Standard_True; + myCurEdgePar = Probing_Start; } + Par = RealLast(); + L = gp_Lin2d (P, gp_Dir2d (1, 0)); + return Standard_False; } diff --git a/src/Geom2dHatch/Geom2dHatch_Elements.hxx b/src/Geom2dHatch/Geom2dHatch_Elements.hxx index 5ef0623894..3b7f486ecb 100644 --- a/src/Geom2dHatch/Geom2dHatch_Elements.hxx +++ b/src/Geom2dHatch/Geom2dHatch_Elements.hxx @@ -114,7 +114,7 @@ private: Standard_Integer NumWire; Standard_Integer NumEdge; Standard_Integer myCurEdge; - + Standard_Real myCurEdgePar; }; diff --git a/tests/bugs/modalg_6/bug6768 b/tests/bugs/modalg_6/bug6768 index 75d7712669..963a985d3d 100644 --- a/tests/bugs/modalg_6/bug6768 +++ b/tests/bugs/modalg_6/bug6768 @@ -29,7 +29,7 @@ if { ${s} eq "co_1" } { checknbshapes r${s}_1 -vertex 80 } elseif { ${s} eq "co_3" } { checkprops r${s}_1 -l 550.648 - checknbshapes r${s}_1 -vertex 111 + checknbshapes r${s}_1 -vertex 113 } else { checkprops r${s}_1 -l 545.219 checknbshapes r${s}_1 -vertex 290 diff --git a/tests/mkface/mkplane/bug30878_1 b/tests/mkface/mkplane/bug30878_1 new file mode 100644 index 0000000000..c966de4c35 --- /dev/null +++ b/tests/mkface/mkplane/bug30878_1 @@ -0,0 +1,22 @@ +puts "=============" +puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface" +puts "=============" + +brestore [locate_data_file bug30878_wire.brep] w + +# build the face on the original wire +mkplane result w 1 + +checkprops result -s 69458.1 + +# reduce the tolerance +settolerance w 0.7 + +# build face again +mkplane result w 1 + +checkprops result -s 69458.1 + +set MaxFTol 0.7 +set MaxETol 0.7 +set MaxVTol 0.7 diff --git a/tests/mkface/mkplane/bug30878_2 b/tests/mkface/mkplane/bug30878_2 new file mode 100644 index 0000000000..4429354d9b --- /dev/null +++ b/tests/mkface/mkplane/bug30878_2 @@ -0,0 +1,11 @@ +puts "REQUIRED ALL: Error. mkplane has been finished with \"Not Planar\" status." +puts "REQUIRED ALL: Error : The mkface can not be built." + +puts "=============" +puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface" +puts "=============" + +brestore [locate_data_file bug30878_wire2.brep] w + +mkplane result w 1 + diff --git a/tests/offset/wire_unclosed_outside_0_005/C1 b/tests/offset/wire_unclosed_outside_0_005/C1 index aa39a97ccf..e4e5596648 100644 --- a/tests/offset/wire_unclosed_outside_0_005/C1 +++ b/tests/offset/wire_unclosed_outside_0_005/C1 @@ -1,15 +1,15 @@ -#puts "TODO OCC23068 ALL: Error : big tolerance of shape result" -#puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2" +puts "TODO OCC23068 ALL: Error : big tolerance of shape result" +puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2" #puts "TODO OCC24255 ALL: An exception was caught" -puts "TODO OCC24255 ALL: Error: Offset is not done." -puts "TODO OCC24255 ALL: Error: The command cannot be built" -puts "TODO OCC24255 ALL: Error : The offset cannot be built." +#puts "TODO OCC24255 ALL: Error: Offset is not done." +#puts "TODO OCC24255 ALL: Error: The command cannot be built" +#puts "TODO OCC24255 ALL: Error : The offset cannot be built." restore [locate_data_file offset_wire_072.brep] s set length 116267 -set nbsh_v 301 -set nbsh_e 301 +set nbsh_v 321 +set nbsh_e 321 set nbsh_w 1 diff --git a/tests/offset/wire_unclosed_outside_0_025/B2 b/tests/offset/wire_unclosed_outside_0_025/B2 index f6a4e3af86..056953482d 100644 --- a/tests/offset/wire_unclosed_outside_0_025/B2 +++ b/tests/offset/wire_unclosed_outside_0_025/B2 @@ -1,7 +1,7 @@ restore [locate_data_file offset_wire_033.brep] s set length 68.7414 -set nbsh_v 61 -set nbsh_e 61 +set nbsh_v 62 +set nbsh_e 62 set nbsh_w 1 -- 2.39.5