From 6fd9bdf2cc6eabbdd31b433eab5bd2ebd7bdbe83 Mon Sep 17 00:00:00 2001 From: azv Date: Sat, 13 Apr 2019 14:57:39 +0300 Subject: [PATCH] 0030645: Modeling Algorithms - B-spline segmentation produces wrong parametrization Method Segment() of B-spline curve and surface has been extended by parameter theTolerance (theUTolerance and theVTolerance for surface), which defines the proximity between knots of a NURBS and boundaries of cutting segment. The default value of the tolerance is Precision::PConfusion(). Test cases have been added to check segmenting of B-spline surface and curves both 2D and 3D. --- src/BndLib/BndLib_Add3dCurve.cxx | 5 +- src/Geom/Geom_BSplineCurve.cxx | 5 +- src/Geom/Geom_BSplineCurve.hxx | 8 +- src/Geom/Geom_BSplineSurface.cxx | 476 ++++++------------ src/Geom/Geom_BSplineSurface.hxx | 27 +- src/Geom2d/Geom2d_BSplineCurve.cxx | 5 +- src/Geom2d/Geom2d_BSplineCurve.hxx | 8 +- .../GeomliteTest_CurveCommands.cxx | 12 +- .../GeomliteTest_SurfaceCommands.cxx | 14 +- tests/bugs/modalg_7/bug30645_1 | 32 ++ tests/bugs/modalg_7/bug30645_2 | 42 ++ tests/bugs/modalg_7/bug30645_3 | 44 ++ 12 files changed, 335 insertions(+), 343 deletions(-) create mode 100644 tests/bugs/modalg_7/bug30645_1 create mode 100644 tests/bugs/modalg_7/bug30645_2 create mode 100644 tests/bugs/modalg_7/bug30645_3 diff --git a/src/BndLib/BndLib_Add3dCurve.cxx b/src/BndLib/BndLib_Add3dCurve.cxx index 3d9a697b9a..c7226d9d50 100644 --- a/src/BndLib/BndLib_Add3dCurve.cxx +++ b/src/BndLib/BndLib_Add3dCurve.cxx @@ -226,7 +226,10 @@ void BndLib_Add3dCurve::Add( const Adaptor3d_Curve& C, if(Bsaux->LastParameter() < U2 ) u2 = Bsaux->LastParameter(); // modified by NIZHNY-EAP Fri Dec 3 14:29:18 1999 ___END___ } - Bsaux->Segment(u1, u2); + Standard_Real aSegmentTol = Precision::PConfusion(); + if (Abs(u2 - u1) < aSegmentTol) + aSegmentTol = Abs(u2 - u1) * 0.01; + Bsaux->Segment(u1, u2, aSegmentTol); Bs = Bsaux; } //OCC566(apo)-> diff --git a/src/Geom/Geom_BSplineCurve.cxx b/src/Geom/Geom_BSplineCurve.cxx index 7792defa11..807eacd0a7 100644 --- a/src/Geom/Geom_BSplineCurve.cxx +++ b/src/Geom/Geom_BSplineCurve.cxx @@ -491,7 +491,8 @@ Standard_Real Geom_BSplineCurve::ReversedParameter //======================================================================= void Geom_BSplineCurve::Segment(const Standard_Real U1, - const Standard_Real U2) + const Standard_Real U2, + const Standard_Real theTolerance) { if (U2 < U1) throw Standard_DomainError("Geom_BSplineCurve::Segment"); @@ -539,7 +540,7 @@ void Geom_BSplineCurve::Segment(const Standard_Real U1, AbsUMax = Max(AbsUMax, Max(Abs(FirstParameter()),Abs(LastParameter()))); // Modified by Sergey KHROMOV - Fri Apr 11 12:15:40 2003 End - Standard_Real Eps = 100. * Epsilon(AbsUMax); + Standard_Real Eps = Max(Epsilon(AbsUMax), theTolerance); InsertKnots( Knots, Mults, Eps); diff --git a/src/Geom/Geom_BSplineCurve.hxx b/src/Geom/Geom_BSplineCurve.hxx index dc28c43f1b..ae036654ea 100644 --- a/src/Geom/Geom_BSplineCurve.hxx +++ b/src/Geom/Geom_BSplineCurve.hxx @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -290,6 +291,10 @@ public: //! All data structure tables of this BSpline curve are //! modified, but the knots located between U1 and U2 //! are retained. The degree of the curve is not modified. + //! + //! Parameter theTolerance defines the possible proximity of the segment + //! boundaries and B-spline knots to treat them as equal. + //! //! Warnings : //! Even if is not closed it can become closed after the //! segmentation for example if U1 or U2 are out of the bounds @@ -298,7 +303,8 @@ public: //! raises if U2 < U1. //! Standard_DomainError if U2 - U1 exceeds the period for periodic curves. //! i.e. ((U2 - U1) - Period) > Precision::PConfusion(). - Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2); + Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2, + const Standard_Real theTolerance = Precision::PConfusion()); //! Modifies this BSpline curve by assigning the value K //! to the knot of index Index in the knots table. This is a diff --git a/src/Geom/Geom_BSplineSurface.cxx b/src/Geom/Geom_BSplineSurface.cxx index 8bbd8cb76e..f538442cf1 100644 --- a/src/Geom/Geom_BSplineSurface.cxx +++ b/src/Geom/Geom_BSplineSurface.cxx @@ -529,20 +529,20 @@ void Geom_BSplineSurface::IncreaseVMultiplicity } //======================================================================= -//function : Segment +//function : segment //purpose : //======================================================================= -void Geom_BSplineSurface::Segment(const Standard_Real U1, - const Standard_Real U2, - const Standard_Real V1, - const Standard_Real V2) +void Geom_BSplineSurface::segment(const Standard_Real U1, + const Standard_Real U2, + const Standard_Real V1, + const Standard_Real V2, + const Standard_Real EpsU, + const Standard_Real EpsV, + const Standard_Boolean SegmentInU, + const Standard_Boolean SegmentInV) { - if ((U2 < U1) || (V2 < V1)) - throw Standard_DomainError("Geom_BSplineSurface::Segment"); - Standard_Real deltaU = Max(Abs(U2),Abs(U1)); - Standard_Real EpsU = Epsilon(deltaU); - deltaU = U2 - U1; + Standard_Real deltaU = U2 - U1; if (uperiodic) { Standard_Real aUPeriod = uknots->Last() - uknots->First(); if (deltaU - aUPeriod > Precision::PConfusion()) @@ -550,10 +550,8 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, if (deltaU > aUPeriod) deltaU = aUPeriod; } - - Standard_Real deltaV = Max(Abs(V2),Abs(V1)); - Standard_Real EpsV = Epsilon(deltaV); - deltaV = V2 - V1; + + Standard_Real deltaV = V2 - V1; if (vperiodic) { Standard_Real aVPeriod = vknots->Last() - vknots->First(); if (deltaV - aVPeriod > Precision::PConfusion()) @@ -563,50 +561,53 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, } Standard_Real NewU1, NewU2, NewV1, NewV2; - Standard_Real U,V; + Standard_Real U, V; Standard_Integer indexU, indexV; - // inserting the UKnots - TColStd_Array1OfReal UKnots(1,2); - TColStd_Array1OfInteger UMults(1,2); - indexU = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U1,uperiodic,uknots->Lower(),uknots->Upper(), - indexU,NewU1); + BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), + U1, uperiodic, uknots->Lower(), uknots->Upper(), + indexU, NewU1); indexU = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U2,uperiodic,uknots->Lower(),uknots->Upper(), - indexU,NewU2); - UKnots( 1) = Min( NewU1, NewU2); - UKnots( 2) = Max( NewU1, NewU2); - UMults( 1) = UMults( 2) = udeg; - InsertUKnots( UKnots, UMults, EpsU); - - // Inserting the VKnots - TColStd_Array1OfReal VKnots(1,2); - TColStd_Array1OfInteger VMults(1,2); + BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), + U2, uperiodic, uknots->Lower(), uknots->Upper(), + indexU, NewU2); + if (SegmentInU) { + // inserting the UKnots + TColStd_Array1OfReal UKnots(1, 2); + TColStd_Array1OfInteger UMults(1, 2); + UKnots(1) = Min(NewU1, NewU2); + UKnots(2) = Max(NewU1, NewU2); + UMults(1) = UMults(2) = udeg; + + InsertUKnots(UKnots, UMults, EpsU); + } indexV = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V1,vperiodic,vknots->Lower(),vknots->Upper(), - indexV,NewV1); + BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), + V1, vperiodic, vknots->Lower(), vknots->Upper(), + indexV, NewV1); indexV = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V2,vperiodic,vknots->Lower(),vknots->Upper(), - indexV,NewV2); - VKnots( 1) = Min( NewV1, NewV2); - VKnots( 2) = Max( NewV1, NewV2); - VMults( 1) = VMults( 2) = vdeg; - InsertVKnots( VKnots, VMults, EpsV); + BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), + V2, vperiodic, vknots->Lower(), vknots->Upper(), + indexV, NewV2); + if (SegmentInV) { + // Inserting the VKnots + TColStd_Array1OfReal VKnots(1, 2); + TColStd_Array1OfInteger VMults(1, 2); + VKnots(1) = Min(NewV1, NewV2); + VKnots(2) = Max(NewV1, NewV2); + VMults(1) = VMults(2) = vdeg; + InsertVKnots(VKnots, VMults, EpsV); + } - if (uperiodic) { // set the origine at NewU1 + if (uperiodic && SegmentInU) { // set the origine at NewU1 Standard_Integer index = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U1,uperiodic,uknots->Lower(),uknots->Upper(), - index,U); - if ( Abs(uknots->Value(index+1)-U) <= EpsU) + BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), + U1, uperiodic, uknots->Lower(), uknots->Upper(), + index, U); + if (Abs(uknots->Value(index + 1) - U) <= EpsU) index++; SetUOrigin(index); SetUNotPeriodic(); @@ -615,37 +616,38 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, // compute index1 and index2 to set the new knots and mults Standard_Integer index1U = 0, index2U = 0; Standard_Integer FromU1 = uknots->Lower(); - Standard_Integer ToU2 = uknots->Upper(); - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - NewU1,uperiodic,FromU1,ToU2,index1U,U); - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - NewU1 + deltaU,uperiodic,FromU1,ToU2,index2U,U); - if ( Abs(uknots->Value(index2U+1)-U) <= EpsU) + Standard_Integer ToU2 = uknots->Upper(); + BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), + NewU1, uperiodic, FromU1, ToU2, index1U, U); + BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), + NewU1 + deltaU, uperiodic, FromU1, ToU2, index2U, U); + if (Abs(uknots->Value(index2U + 1) - U) <= EpsU) index2U++; - + Standard_Integer nbuknots = index2U - index1U + 1; - Handle(TColStd_HArray1OfReal) - nuknots = new TColStd_HArray1OfReal(1,nbuknots); - Handle(TColStd_HArray1OfInteger) - numults = new TColStd_HArray1OfInteger(1,nbuknots); + Handle(TColStd_HArray1OfReal) + nuknots = new TColStd_HArray1OfReal(1, nbuknots); + Handle(TColStd_HArray1OfInteger) + numults = new TColStd_HArray1OfInteger(1, nbuknots); - Standard_Integer i , k = 1; - for ( i = index1U; i<= index2U; i++) { + Standard_Integer i, k = 1; + for (i = index1U; i <= index2U; i++) { nuknots->SetValue(k, uknots->Value(i)); numults->SetValue(k, umults->Value(i)); k++; } - numults->SetValue( 1, udeg + 1); - numults->SetValue(nbuknots, udeg + 1); - + if (SegmentInU) { + numults->SetValue(1, udeg + 1); + numults->SetValue(nbuknots, udeg + 1); + } - if (vperiodic) { // set the origine at NewV1 + if (vperiodic&& SegmentInV) { // set the origine at NewV1 Standard_Integer index = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V1,vperiodic,vknots->Lower(),vknots->Upper(), - index,V); - if ( Abs(vknots->Value(index+1)-V) <= EpsV) + BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), + V1, vperiodic, vknots->Lower(), vknots->Upper(), + index, V); + if (Abs(vknots->Value(index + 1) - V) <= EpsV) index++; SetVOrigin(index); SetVNotPeriodic(); @@ -654,79 +656,80 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, // compute index1 and index2 to set the new knots and mults Standard_Integer index1V = 0, index2V = 0; Standard_Integer FromV1 = vknots->Lower(); - Standard_Integer ToV2 = vknots->Upper(); - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - NewV1,vperiodic,FromV1,ToV2,index1V,V); - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - NewV1 + deltaV,vperiodic,FromV1,ToV2,index2V,V); - if ( Abs(vknots->Value(index2V+1)-V) <= EpsV) + Standard_Integer ToV2 = vknots->Upper(); + BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), + NewV1, vperiodic, FromV1, ToV2, index1V, V); + BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), + NewV1 + deltaV, vperiodic, FromV1, ToV2, index2V, V); + if (Abs(vknots->Value(index2V + 1) - V) <= EpsV) index2V++; - + Standard_Integer nbvknots = index2V - index1V + 1; - Handle(TColStd_HArray1OfReal) - nvknots = new TColStd_HArray1OfReal(1,nbvknots); - Handle(TColStd_HArray1OfInteger) - nvmults = new TColStd_HArray1OfInteger(1,nbvknots); + Handle(TColStd_HArray1OfReal) + nvknots = new TColStd_HArray1OfReal(1, nbvknots); + Handle(TColStd_HArray1OfInteger) + nvmults = new TColStd_HArray1OfInteger(1, nbvknots); k = 1; - for ( i = index1V; i<= index2V; i++) { + for (i = index1V; i <= index2V; i++) { nvknots->SetValue(k, vknots->Value(i)); nvmults->SetValue(k, vmults->Value(i)); k++; } - nvmults->SetValue( 1, vdeg + 1); - nvmults->SetValue(nbvknots, vdeg + 1); + if (SegmentInV) { + nvmults->SetValue(1, vdeg + 1); + nvmults->SetValue(nbvknots, vdeg + 1); + } // compute index1 and index2 to set the new poles and weights - Standard_Integer pindex1U - = BSplCLib::PoleIndex(udeg,index1U,uperiodic,umults->Array1()); - Standard_Integer pindex2U - = BSplCLib::PoleIndex(udeg,index2U,uperiodic,umults->Array1()); + Standard_Integer pindex1U + = BSplCLib::PoleIndex(udeg, index1U, uperiodic, umults->Array1()); + Standard_Integer pindex2U + = BSplCLib::PoleIndex(udeg, index2U, uperiodic, umults->Array1()); pindex1U++; - pindex2U = Min( pindex2U+1, poles->ColLength()); + pindex2U = Min(pindex2U + 1, poles->ColLength()); - Standard_Integer nbupoles = pindex2U - pindex1U + 1; + Standard_Integer nbupoles = pindex2U - pindex1U + 1; // compute index1 and index2 to set the new poles and weights - Standard_Integer pindex1V - = BSplCLib::PoleIndex(vdeg,index1V,vperiodic,vmults->Array1()); - Standard_Integer pindex2V - = BSplCLib::PoleIndex(vdeg,index2V,vperiodic,vmults->Array1()); + Standard_Integer pindex1V + = BSplCLib::PoleIndex(vdeg, index1V, vperiodic, vmults->Array1()); + Standard_Integer pindex2V + = BSplCLib::PoleIndex(vdeg, index2V, vperiodic, vmults->Array1()); pindex1V++; - pindex2V = Min( pindex2V+1, poles->RowLength()); + pindex2V = Min(pindex2V + 1, poles->RowLength()); - Standard_Integer nbvpoles = pindex2V - pindex1V + 1; + Standard_Integer nbvpoles = pindex2V - pindex1V + 1; - Handle(TColStd_HArray2OfReal) nweights; + Handle(TColStd_HArray2OfReal) nweights; Handle(TColgp_HArray2OfPnt) - npoles = new TColgp_HArray2OfPnt(1,nbupoles,1,nbvpoles); - + npoles = new TColgp_HArray2OfPnt(1, nbupoles, 1, nbvpoles); k = 1; Standard_Integer j, l; - if ( urational || vrational) { - nweights = new TColStd_HArray2OfReal( 1,nbupoles,1,nbvpoles); - for ( i = pindex1U; i <= pindex2U; i++) { + if (urational || vrational) { + nweights = new TColStd_HArray2OfReal(1, nbupoles, 1, nbvpoles); + for (i = pindex1U; i <= pindex2U; i++) { l = 1; - for ( j = pindex1V; j <= pindex2V; j++) { - npoles->SetValue(k,l, poles->Value(i,j)); - nweights->SetValue(k,l, weights->Value(i,j)); - l++; + for (j = pindex1V; j <= pindex2V; j++) { + npoles->SetValue(k, l, poles->Value(i, j)); + nweights->SetValue(k, l, weights->Value(i, j)); + l++; } k++; } } else { - for ( i = pindex1U; i <= pindex2U; i++) { + for (i = pindex1U; i <= pindex2U; i++) { l = 1; - for ( j = pindex1V; j <= pindex2V; j++) { - npoles->SetValue(k,l, poles->Value(i,j)); - l++; + for (j = pindex1V; j <= pindex2V; j++) { + npoles->SetValue(k, l, poles->Value(i, j)); + l++; } k++; } @@ -737,16 +740,39 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, vknots = nvknots; vmults = nvmults; poles = npoles; - if ( urational || vrational) + if (urational || vrational) weights = nweights; - else - weights = new TColStd_HArray2OfReal (1,poles->ColLength(), - 1,poles->RowLength(), 1.0); + else + weights = new TColStd_HArray2OfReal(1, poles->ColLength(), + 1, poles->RowLength(), 1.0); maxderivinvok = 0; UpdateUKnots(); UpdateVKnots(); +} + +//======================================================================= +//function : Segment +//purpose : +//======================================================================= +void Geom_BSplineSurface::Segment(const Standard_Real U1, + const Standard_Real U2, + const Standard_Real V1, + const Standard_Real V2, + const Standard_Real theUTolerance, + const Standard_Real theVTolerance) +{ + if ((U2 < U1) || (V2 < V1)) + throw Standard_DomainError("Geom_BSplineSurface::Segment"); + + Standard_Real aMaxU = Max(Abs(U2), Abs(U1)); + Standard_Real EpsU = Max(Epsilon(aMaxU), theUTolerance); + + Standard_Real aMaxV = Max(Abs(V2), Abs(V1)); + Standard_Real EpsV = Max(Epsilon(aMaxV), theVTolerance); + + segment(U1, U2, V1, V2, EpsU, EpsV, Standard_True, Standard_True); } //======================================================================= @@ -755,38 +781,21 @@ void Geom_BSplineSurface::Segment(const Standard_Real U1, //======================================================================= void Geom_BSplineSurface::CheckAndSegment(const Standard_Real U1, - const Standard_Real U2, - const Standard_Real V1, - const Standard_Real V2) + const Standard_Real U2, + const Standard_Real V1, + const Standard_Real V2, + const Standard_Real theUTolerance, + const Standard_Real theVTolerance) { if ((U2 < U1) || (V2 < V1)) throw Standard_DomainError("Geom_BSplineSurface::CheckAndSegment"); - Standard_Real deltaU = Max(Abs(U2),Abs(U1)); - Standard_Real EpsU = Epsilon(deltaU); - deltaU = U2 - U1; - if (uperiodic) { - Standard_Real aUPeriod = uknots->Last() - uknots->First(); - if (deltaU - aUPeriod > Precision::PConfusion()) - throw Standard_DomainError("Geom_BSplineSurface::CheckAndSegment"); - if (deltaU > aUPeriod) - deltaU = aUPeriod; - } - - Standard_Real deltaV = Max(Abs(V2),Abs(V1)); - Standard_Real EpsV = Epsilon(deltaV); - deltaV = V2 - V1; - if (vperiodic) { - Standard_Real aVPeriod = vknots->Last() - vknots->First(); - if (deltaV - aVPeriod > Precision::PConfusion()) - throw Standard_DomainError("Geom_BSplineSurface::CheckAndSegment"); - if (deltaV > aVPeriod) - deltaV = aVPeriod; - } - Standard_Real NewU1, NewU2, NewV1, NewV2; - Standard_Real U,V; - Standard_Integer indexU, indexV; + Standard_Real aMaxU = Max(Abs(U2), Abs(U1)); + Standard_Real EpsU = Max(Epsilon(aMaxU), theUTolerance); + + Standard_Real aMaxV = Max(Abs(V2), Abs(V1)); + Standard_Real EpsV = Max(Epsilon(aMaxV), theVTolerance); Standard_Boolean segment_in_U = Standard_True; Standard_Boolean segment_in_V = Standard_True; @@ -795,192 +804,7 @@ void Geom_BSplineSurface::CheckAndSegment(const Standard_Real U1, segment_in_V = ( Abs(V1 - vknots->Value(vknots->Lower())) > EpsV ) || ( Abs(V2 - vknots->Value(vknots->Upper())) > EpsV ); - indexU = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U1,uperiodic,uknots->Lower(),uknots->Upper(), - indexU,NewU1); - indexU = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U2,uperiodic,uknots->Lower(),uknots->Upper(), - indexU,NewU2); - if (segment_in_U) { - // inserting the UKnots - TColStd_Array1OfReal UKnots(1,2); - TColStd_Array1OfInteger UMults(1,2); - UKnots( 1) = Min( NewU1, NewU2); - UKnots( 2) = Max( NewU1, NewU2); - UMults( 1) = UMults( 2) = udeg; - - InsertUKnots( UKnots, UMults, EpsU); - } - - indexV = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V1,vperiodic,vknots->Lower(),vknots->Upper(), - indexV,NewV1); - indexV = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V2,vperiodic,vknots->Lower(),vknots->Upper(), - indexV,NewV2); - if (segment_in_V) { - // Inserting the VKnots - TColStd_Array1OfReal VKnots(1,2); - TColStd_Array1OfInteger VMults(1,2); - - VKnots( 1) = Min( NewV1, NewV2); - VKnots( 2) = Max( NewV1, NewV2); - VMults( 1) = VMults( 2) = vdeg; - InsertVKnots( VKnots, VMults, EpsV); - } - - if (uperiodic && segment_in_U) { // set the origine at NewU1 - Standard_Integer index = 0; - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - U1,uperiodic,uknots->Lower(),uknots->Upper(), - index,U); - if ( Abs(uknots->Value(index+1)-U) <= EpsU) - index++; - SetUOrigin(index); - SetUNotPeriodic(); - } - - // compute index1 and index2 to set the new knots and mults - Standard_Integer index1U = 0, index2U = 0; - Standard_Integer FromU1 = uknots->Lower(); - Standard_Integer ToU2 = uknots->Upper(); - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - NewU1,uperiodic,FromU1,ToU2,index1U,U); - BSplCLib::LocateParameter(udeg,uknots->Array1(),umults->Array1(), - NewU1 + deltaU,uperiodic,FromU1,ToU2,index2U,U); - if ( Abs(uknots->Value(index2U+1)-U) <= EpsU) - index2U++; - - Standard_Integer nbuknots = index2U - index1U + 1; - - Handle(TColStd_HArray1OfReal) - nuknots = new TColStd_HArray1OfReal(1,nbuknots); - Handle(TColStd_HArray1OfInteger) - numults = new TColStd_HArray1OfInteger(1,nbuknots); - - Standard_Integer i , k = 1; - for ( i = index1U; i<= index2U; i++) { - nuknots->SetValue(k, uknots->Value(i)); - numults->SetValue(k, umults->Value(i)); - k++; - } - if (segment_in_U) { - numults->SetValue( 1, udeg + 1); - numults->SetValue(nbuknots, udeg + 1); - } - - if (vperiodic&& segment_in_V) { // set the origine at NewV1 - Standard_Integer index = 0; - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - V1,vperiodic,vknots->Lower(),vknots->Upper(), - index,V); - if ( Abs(vknots->Value(index+1)-V) <= EpsV) - index++; - SetVOrigin(index); - SetVNotPeriodic(); - } - - // compute index1 and index2 to set the new knots and mults - Standard_Integer index1V = 0, index2V = 0; - Standard_Integer FromV1 = vknots->Lower(); - Standard_Integer ToV2 = vknots->Upper(); - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - NewV1,vperiodic,FromV1,ToV2,index1V,V); - BSplCLib::LocateParameter(vdeg,vknots->Array1(),vmults->Array1(), - NewV1 + deltaV,vperiodic,FromV1,ToV2,index2V,V); - if ( Abs(vknots->Value(index2V+1)-V) <= EpsV) - index2V++; - - Standard_Integer nbvknots = index2V - index1V + 1; - - Handle(TColStd_HArray1OfReal) - nvknots = new TColStd_HArray1OfReal(1,nbvknots); - Handle(TColStd_HArray1OfInteger) - nvmults = new TColStd_HArray1OfInteger(1,nbvknots); - - k = 1; - for ( i = index1V; i<= index2V; i++) { - nvknots->SetValue(k, vknots->Value(i)); - nvmults->SetValue(k, vmults->Value(i)); - k++; - } - if (segment_in_V) { - nvmults->SetValue( 1, vdeg + 1); - nvmults->SetValue(nbvknots, vdeg + 1); - } - - // compute index1 and index2 to set the new poles and weights - Standard_Integer pindex1U - = BSplCLib::PoleIndex(udeg,index1U,uperiodic,umults->Array1()); - Standard_Integer pindex2U - = BSplCLib::PoleIndex(udeg,index2U,uperiodic,umults->Array1()); - - pindex1U++; - pindex2U = Min( pindex2U+1, poles->ColLength()); - - Standard_Integer nbupoles = pindex2U - pindex1U + 1; - - // compute index1 and index2 to set the new poles and weights - Standard_Integer pindex1V - = BSplCLib::PoleIndex(vdeg,index1V,vperiodic,vmults->Array1()); - Standard_Integer pindex2V - = BSplCLib::PoleIndex(vdeg,index2V,vperiodic,vmults->Array1()); - - pindex1V++; - pindex2V = Min( pindex2V+1, poles->RowLength()); - - Standard_Integer nbvpoles = pindex2V - pindex1V + 1; - - - Handle(TColStd_HArray2OfReal) nweights; - - Handle(TColgp_HArray2OfPnt) - npoles = new TColgp_HArray2OfPnt(1,nbupoles,1,nbvpoles); - - k = 1; - Standard_Integer j, l; - if ( urational || vrational) { - nweights = new TColStd_HArray2OfReal( 1,nbupoles,1,nbvpoles); - for ( i = pindex1U; i <= pindex2U; i++) { - l = 1; - for ( j = pindex1V; j <= pindex2V; j++) { - npoles->SetValue(k,l, poles->Value(i,j)); - nweights->SetValue(k,l, weights->Value(i,j)); - l++; - } - k++; - } - } - else { - for ( i = pindex1U; i <= pindex2U; i++) { - l = 1; - for ( j = pindex1V; j <= pindex2V; j++) { - npoles->SetValue(k,l, poles->Value(i,j)); - l++; - } - k++; - } - } - - uknots = nuknots; - umults = numults; - vknots = nvknots; - vmults = nvmults; - poles = npoles; - if ( urational || vrational) - weights = nweights; - else - weights = new TColStd_HArray2OfReal (1,poles->ColLength(), - 1,poles->RowLength(), 1.0); - - maxderivinvok = 0; - UpdateUKnots(); - UpdateVKnots(); - + segment(U1, U2, V1, V2, EpsU, EpsV, segment_in_U, segment_in_V); } //======================================================================= diff --git a/src/Geom/Geom_BSplineSurface.hxx b/src/Geom/Geom_BSplineSurface.hxx index 9a54bf071d..40decdef99 100644 --- a/src/Geom/Geom_BSplineSurface.hxx +++ b/src/Geom/Geom_BSplineSurface.hxx @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -547,6 +548,10 @@ public: //! between V1 and V2 in the V-Direction. //! The control points are modified, the first and the last point //! are not the same. + //! + //! Parameters theUTolerance, theVTolerance define the possible proximity along the correponding + //! direction of the segment boundaries and B-spline knots to treat them as equal. + //! //! Warnings : //! Even if is not closed it can become closed after the //! segmentation for example if U1 or U2 are out of the bounds @@ -556,7 +561,9 @@ public: //! i.e. ((U2 - U1) - UPeriod) > Precision::PConfusion(). //! Standard_DomainError if V2 - V1 exceeds the vperiod for vperiodic surfaces. //! i.e. ((V2 - V1) - VPeriod) > Precision::PConfusion()). - Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2, const Standard_Real V1, const Standard_Real V2); + Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2, const Standard_Real V1, const Standard_Real V2, + const Standard_Real theUTolerance = Precision::PConfusion(), + const Standard_Real theVTolerance = Precision::PConfusion()); //! Segments the surface between U1 and U2 in the U-Direction. @@ -567,6 +574,9 @@ public: //! For example, if is periodic in V, it will be always periodic //! in V after the segmentation if the bounds in V are unchanged //! + //! Parameters theUTolerance, theVTolerance define the possible proximity along the correponding + //! direction of the segment boundaries and B-spline knots to treat them as equal. + //! //! Warnings : //! Even if is not closed it can become closed after the //! segmentation for example if U1 or U2 are out of the bounds @@ -576,7 +586,9 @@ public: //! i.e. ((U2 - U1) - UPeriod) > Precision::PConfusion(). //! Standard_DomainError if V2 - V1 exceeds the vperiod for vperiodic surfaces. //! i.e. ((V2 - V1) - VPeriod) > Precision::PConfusion()). - Standard_EXPORT void CheckAndSegment (const Standard_Real U1, const Standard_Real U2, const Standard_Real V1, const Standard_Real V2); + Standard_EXPORT void CheckAndSegment (const Standard_Real U1, const Standard_Real U2, const Standard_Real V1, const Standard_Real V2, + const Standard_Real theUTolerance = Precision::PConfusion(), + const Standard_Real theVTolerance = Precision::PConfusion()); //! Substitutes the UKnots of range UIndex with K. //! @@ -1184,7 +1196,16 @@ public: protected: - + //! Segments the surface between U1 and U2 in the U-Direction. + //! between V1 and V2 in the V-Direction. + //! The control points are modified, the first and the last point + //! are not the same. + //! + //! Parameters EpsU, EpsV define the proximity along U-Direction and V-Direction respectively. + void segment(const Standard_Real U1, const Standard_Real U2, + const Standard_Real V1, const Standard_Real V2, + const Standard_Real EpsU, const Standard_Real EpsV, + const Standard_Boolean SegmentInU, const Standard_Boolean SegmentInV); private: diff --git a/src/Geom2d/Geom2d_BSplineCurve.cxx b/src/Geom2d/Geom2d_BSplineCurve.cxx index 9ab6e279fb..1229c61c5c 100644 --- a/src/Geom2d/Geom2d_BSplineCurve.cxx +++ b/src/Geom2d/Geom2d_BSplineCurve.cxx @@ -650,13 +650,14 @@ Standard_Real Geom2d_BSplineCurve::ReversedParameter( const Standard_Real U) con //purpose : //======================================================================= void Geom2d_BSplineCurve::Segment(const Standard_Real aU1, - const Standard_Real aU2) + const Standard_Real aU2, + const Standard_Real theTolerance) { if (aU2 < aU1) throw Standard_DomainError("Geom2d_BSplineCurve::Segment"); // Standard_Real AbsUMax = Max(Abs(FirstParameter()),Abs(LastParameter())); - Standard_Real Eps = Max (Epsilon(AbsUMax), Precision::PConfusion()); + Standard_Real Eps = Max (Epsilon(AbsUMax), theTolerance); Standard_Real NewU1, NewU2; Standard_Real U, DU=0; Standard_Integer i, k, index; diff --git a/src/Geom2d/Geom2d_BSplineCurve.hxx b/src/Geom2d/Geom2d_BSplineCurve.hxx index 948a01f849..822ded7de1 100644 --- a/src/Geom2d/Geom2d_BSplineCurve.hxx +++ b/src/Geom2d/Geom2d_BSplineCurve.hxx @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -356,6 +357,10 @@ public: //! All data structure tables of this BSpline curve are //! modified, but the knots located between U1 and U2 //! are retained. The degree of the curve is not modified. + //! + //! Parameter theTolerance defines the possible proximity of the segment + //! boundaries and B-spline knots to treat them as equal. + //! //! Warnings : //! Even if is not closed it can become closed after the //! segmentation for example if U1 or U2 are out of the bounds @@ -369,7 +374,8 @@ public: //! raises if U2 < U1. //! Standard_DomainError if U2 - U1 exceeds the period for periodic curves. //! i.e. ((U2 - U1) - Period) > Precision::PConfusion(). - Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2); + Standard_EXPORT void Segment (const Standard_Real U1, const Standard_Real U2, + const Standard_Real theTolerance = Precision::PConfusion()); //! Modifies this BSpline curve by assigning the value K //! to the knot of index Index in the knots table. This is a diff --git a/src/GeomliteTest/GeomliteTest_CurveCommands.cxx b/src/GeomliteTest/GeomliteTest_CurveCommands.cxx index 426d8d7981..c198f14746 100644 --- a/src/GeomliteTest/GeomliteTest_CurveCommands.cxx +++ b/src/GeomliteTest/GeomliteTest_CurveCommands.cxx @@ -1131,7 +1131,7 @@ static Standard_Integer value2d (Draw_Interpretor& , static Standard_Integer segment (Draw_Interpretor& , Standard_Integer n, const char** a) { - if (n < 4) return 1; + if (n < 4 || n > 5) return 1; Handle(Geom_BezierCurve) GBz = DrawTrSurf::GetBezierCurve(a[1]); Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]); @@ -1140,14 +1140,18 @@ static Standard_Integer segment (Draw_Interpretor& , Standard_Integer n, const c Standard_Real f = Draw::Atof(a[2]), l = Draw::Atof(a[3]); + Standard_Real aTolerance = Precision::PConfusion(); + if (n == 5) + aTolerance = Draw::Atof(a[4]); + if (!GBz.IsNull()) GBz->Segment(f,l); else if (!GBs.IsNull()) - GBs->Segment(f,l); + GBs->Segment(f, l, aTolerance); else if (!GBz2d.IsNull()) GBz2d->Segment(f,l); else if (!GBs2d.IsNull()) - GBs2d->Segment(f,l); + GBs2d->Segment(f, l, aTolerance); else return 1; @@ -2135,7 +2139,7 @@ void GeomliteTest::CurveCommands(Draw_Interpretor& theCommands) csetperiodic,g); theCommands.Add("segment", - "segment name Ufirst Ulast", + "segment name Ufirst Ulast [tol]", __FILE__, segment , g); diff --git a/src/GeomliteTest/GeomliteTest_SurfaceCommands.cxx b/src/GeomliteTest/GeomliteTest_SurfaceCommands.cxx index 7106656160..5716fe7b7a 100644 --- a/src/GeomliteTest/GeomliteTest_SurfaceCommands.cxx +++ b/src/GeomliteTest/GeomliteTest_SurfaceCommands.cxx @@ -1351,7 +1351,7 @@ static Standard_Integer exchuv (Draw_Interpretor& , Standard_Integer n, const ch static Standard_Integer segsur (Draw_Interpretor& , Standard_Integer n, const char** a) { - if (n < 6) return 1; + if (n < 6 || n > 8) return 1; Handle(Geom_BezierSurface) GBz = DrawTrSurf::GetBezierSurface(a[1]); Handle(Geom_BSplineSurface) GBs; @@ -1359,7 +1359,15 @@ static Standard_Integer segsur (Draw_Interpretor& , Standard_Integer n, const ch GBs = DrawTrSurf::GetBSplineSurface(a[1]); if (GBs.IsNull()) return 1; - GBs->Segment(Draw::Atof(a[2]),Draw::Atof(a[3]),Draw::Atof(a[4]),Draw::Atof(a[5])); + + Standard_Real aUTolerance = Precision::PConfusion(); + Standard_Real aVTolerance = Precision::PConfusion(); + if (n >= 7) + aUTolerance = aVTolerance = Draw::Atof(a[6]); + if (n == 8) + aVTolerance = Draw::Atof(a[7]); + + GBs->Segment(Draw::Atof(a[2]),Draw::Atof(a[3]),Draw::Atof(a[4]),Draw::Atof(a[5]), aUTolerance, aVTolerance); } else { GBz->Segment(Draw::Atof(a[2]),Draw::Atof(a[3]),Draw::Atof(a[4]),Draw::Atof(a[5])); @@ -1770,7 +1778,7 @@ void GeomliteTest::SurfaceCommands(Draw_Interpretor& theCommands) exchuv,g); theCommands.Add("segsur", - "segsur name Ufirst Ulast Vfirst Vlast", + "segsur name Ufirst Ulast Vfirst Vlast [Utol [Vtol]]", __FILE__, segsur , g); diff --git a/tests/bugs/modalg_7/bug30645_1 b/tests/bugs/modalg_7/bug30645_1 new file mode 100644 index 0000000000..1674568cae --- /dev/null +++ b/tests/bugs/modalg_7/bug30645_1 @@ -0,0 +1,32 @@ +puts "========" +puts "0030645: Modeling Algorithms - B-spline segmentation produces wrong parametrization" +puts "========" +puts "" + +restore [locate_data_file bug30645.brep] result + +set tolerance 1.e-9 +segsur result 13.527990713022374 14.030423915738853 54.831990159753303 59.000000000000028 $tolerance + +set surf [dump result] + +regexp {VKnots +:\n(.*)} $surf full vknots +set is_different_knots 1 +set vknots_list {} +while { "$vknots" != "\n\n" && $is_different_knots } { + regexp { +([0-9]+) +: +([-0-9.+eE]+) *([0-9]+)\n(.*)} $vknots full index knot weight rest + foreach k $vknots_list { + if { [expr abs($k - $knot)] < $tolerance } { + set is_different_knots 0 + } + } + + lappend vknots_list $knot + set vknots $rest +} + +if { $is_different_knots } { + puts "OK: all knots are different" +} else { + puts "ERROR: segment has knots too close" +} diff --git a/tests/bugs/modalg_7/bug30645_2 b/tests/bugs/modalg_7/bug30645_2 new file mode 100644 index 0000000000..0ba33ee6c1 --- /dev/null +++ b/tests/bugs/modalg_7/bug30645_2 @@ -0,0 +1,42 @@ +puts "========" +puts "0030645: Modeling Algorithms - B-spline segmentation produces wrong parametrization" +puts "========" +puts "" + +bsplinecurve result 3 4 \ +2.0 4 2.5 2 2.9 2 3.0 4 \ +117.9 0.0 11.6 1 \ +116.7 0.0 11 1 \ +115.8 0.0 10.5 1 \ +114.4 0.0 9.7 1 \ +113.9 0.0 9.4 1 \ +113.3 0.0 9.1 1 \ +113.1 0.0 9.0 1 \ +113.0 0.0 8.9 1 + + +set tolerance 2.e-9 +segment result 2.5 2.900000001 $tolerance + +set crv [dump result] + +regexp {Knots +:\n(.*)} $crv full knots +set is_different_knots 1 +set knots_list {} +while { "$knots" != "\n" && $is_different_knots } { + regexp { +([0-9]+) +: +([-0-9.+eE]+) *([0-9]+)\n(.*)} $knots full index knot weight rest + foreach k $knots_list { + if { [expr abs($k - $knot)] < $tolerance } { + set is_different_knots 0 + } + } + + lappend knots_list $knot + set knots $rest +} + +if { $is_different_knots } { + puts "OK: all knots are different" +} else { + puts "ERROR: segment has knots too close" +} diff --git a/tests/bugs/modalg_7/bug30645_3 b/tests/bugs/modalg_7/bug30645_3 new file mode 100644 index 0000000000..0971525a7e --- /dev/null +++ b/tests/bugs/modalg_7/bug30645_3 @@ -0,0 +1,44 @@ +puts "========" +puts "0030645: Modeling Algorithms - B-spline segmentation produces wrong parametrization" +puts "========" +puts "" + +2dbsplinecurve result 3 4 \ +2.0 4 2.5 2 2.9 2 3.0 4 \ +117.9 11.6 1 \ +116.7 11 1 \ +115.8 10.5 1 \ +114.4 9.7 1 \ +113.9 9.4 1 \ +113.3 9.1 1 \ +113.1 9.0 1 \ +113.0 8.9 1 + + +set tolerance 1.e-9 +segment result 2.5 2.900000000001 $tolerance + +set crv [dump result] + +regexp {Knots +:\n(.*)} $crv full knots +set is_different_knots 1 +set knots_list {} +while { "$knots" != "\n" && $is_different_knots } { + regexp { +([0-9]+) +: +([-0-9.+eE]+) *([0-9]+)\n(.*)} $knots full index knot weight rest +puts $knot +puts $rest + foreach k $knots_list { + if { [expr abs($k - $knot)] < $tolerance } { + set is_different_knots 0 + } + } + + lappend knots_list $knot + set knots $rest +} + +if { $is_different_knots } { + puts "OK: all knots are different" +} else { + puts "ERROR: segment has knots too close" +} -- 2.20.1