From 19e7092d1b0d871bbaed399e344a91c4916a80f4 Mon Sep 17 00:00:00 2001 From: msv Date: Tue, 14 Mar 2017 17:33:46 +0300 Subject: [PATCH] 0028553: Incorrect result of the ShapeUpgrade_ShapeDivideContinuity algorithm The cause of the bug was computation of incorrect UVBounds in the method ShapeAnalysis::GetFaceUVBounds. In this patch the computation of a box for a 2D curve in the method ShapeAnalysis_Curve::FillBndBox() has been improved taking into account intervals of C2 continuity. Also the fix makes little extension of bounds when making the new surface in ShapeUpgrade_FaceDivide::SplitSurface(), so that all p-curves were fully inside. Test case for issue CR28553 --- src/ShapeAnalysis/ShapeAnalysis_Curve.cxx | 75 ++++++++++++++------ src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx | 16 ++++- tests/bugs/heal/bug28553 | 24 +++++++ 3 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 tests/bugs/heal/bug28553 diff --git a/src/ShapeAnalysis/ShapeAnalysis_Curve.cxx b/src/ShapeAnalysis/ShapeAnalysis_Curve.cxx index 82d372c049..fc6f276894 100644 --- a/src/ShapeAnalysis/ShapeAnalysis_Curve.cxx +++ b/src/ShapeAnalysis/ShapeAnalysis_Curve.cxx @@ -637,7 +637,8 @@ static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d, gp_Pnt2d &res) { Standard_Real prevpar; - for ( Standard_Integer i=0; i <10; i++ ) { + Standard_Integer nbOut = 0; + for (Standard_Integer i = 0; i <10; i++) { prevpar = par; gp_Vec2d D1, D2; @@ -647,9 +648,19 @@ static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d, par -= ( D1 * dir ) / Det; if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True; - - if ( First - par >= Precision::PConfusion() || - par - Last >= Precision::PConfusion() ) return Standard_False; + + if (par < First) + { + if (nbOut++ > 2 || prevpar == First) + return Standard_False; + par = First; + } + if (par > Last) + { + if (nbOut++ > 2 || prevpar == Last) + return Standard_False; + par = Last; + } } return Standard_True; } @@ -661,24 +672,46 @@ void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d, const Standard_Boolean Exact, Bnd_Box2d &Box) const { - Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 ); - Standard_Real step = ( Last - First ) / nseg; - for ( Standard_Integer i=0; i <= nseg; i++ ) { - Standard_Real par = First + i * step; - gp_Pnt2d pnt = C2d->Value ( par ); - Box.Add ( pnt ); - if ( ! Exact ) continue; - - gp_Pnt2d pextr; - Standard_Real parextr = par; - if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step), - gp_Vec2d(1,0), parextr, pextr ) ) { - Box.Add ( pextr ); + if (!Exact) { + Standard_Integer nseg = (NPoints < 2 ? 1 : NPoints - 1); + Standard_Real step = (Last - First) / nseg; + for (Standard_Integer i = 0; i <= nseg; i++) { + Standard_Real par = First + i * step; + gp_Pnt2d pnt = C2d->Value(par); + Box.Add(pnt); } - parextr = par; - if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step), - gp_Vec2d(0,1), parextr, pextr ) ) { - Box.Add ( pextr ); + return; + } + + // We should solve the task on intervals of C2 continuity. + Geom2dAdaptor_Curve anAC(C2d, First, Last); + Standard_Integer nbInt = anAC.NbIntervals(GeomAbs_C2); + // If we have only 1 interval then use input NPoints parameter to get samples. + Standard_Integer nbSamples = (nbInt < 2 ? NPoints - 1 : nbInt); + TColStd_Array1OfReal aParams(1, nbSamples + 1); + if (nbSamples == nbInt) + anAC.Intervals(aParams, GeomAbs_C2); + else { + Standard_Real step = (Last - First) / nbSamples; + for (Standard_Integer i = 0; i <= nbSamples; i++) + aParams(i+1) = First + i * step; + } + for (Standard_Integer i = 1; i <= nbSamples + 1; i++) { + Standard_Real aPar1 = aParams(i); + gp_Pnt2d aPnt = C2d->Value(aPar1); + Box.Add(aPnt); + if (i <= nbSamples) { + Standard_Real aPar2 = aParams(i + 1); + Standard_Real par = (aPar1 + aPar2) * 0.5; + gp_Pnt2d pextr; + Standard_Real parextr = par; + if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(1, 0), parextr, pextr)) { + Box.Add(pextr); + } + parextr = par; + if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(0, 1), parextr, pextr)) { + Box.Add(pextr); + } } } } diff --git a/src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx b/src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx index baaf0e025b..9e6b94b939 100644 --- a/src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx +++ b/src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx @@ -132,7 +132,21 @@ Standard_Boolean ShapeUpgrade_FaceDivide::SplitSurface () if(Precision::IsInfinite(Uf) || Precision::IsInfinite(Ul) || Precision::IsInfinite(Vf) || Precision::IsInfinite(Vl)) return Standard_False; - + + // make little extension to ensure all pcurves fit inside new surface bounds + Standard_Real aSUf, aSUl, aSVf, aSVl; + surf->Bounds(aSUf, aSUl, aSVf, aSVl); + if (!surf->IsUPeriodic()) { + Standard_Real dU = (Ul - Uf) * 0.01; + if (Uf > aSUf) Uf -= Min(dU, Uf - aSUf); + if (Ul < aSUl) Ul += Min(dU, aSUl - Ul); + } + if (!surf->IsVPeriodic()) { + Standard_Real dV = (Vl - Vf) * 0.01; + if (Vf > aSVf) Vf -= Min(dV, Vf - aSVf); + if (Vl < aSVl) Vl += Min(dV, aSVl - Vl); + } + SplitSurf->Init ( surf, Uf, Ul, Vf, Vl ); SplitSurf->Perform(mySegmentMode); diff --git a/tests/bugs/heal/bug28553 b/tests/bugs/heal/bug28553 new file mode 100644 index 0000000000..f4a032423c --- /dev/null +++ b/tests/bugs/heal/bug28553 @@ -0,0 +1,24 @@ +puts "=======" +puts "OCC28553" +puts "=======" +puts "" +################################################## +# Incorrect result of the ShapeUpgrade_ShapeDivideContinuity algorithm +################################################## + +restore [locate_data_file bug28553_sh.brep] f + +#Split shape +DT_ShapeDivide r f + +explode r F +mksurface s2 r_1 +don r_1 s2 + +set fbnd [xbounds r_1] +set v2f [lindex $fbnd 3] +bounds s2 u1 u2 v1 v2 + +if {$v2f > [dval v2]} { + puts "Error: result face bounds are out of surface ($v2f > [dval v2])" +}