0030645: Modeling Algorithms - B-spline segmentation produces wrong parametrization
authorazv <azv@opencascade.com>
Sat, 13 Apr 2019 11:57:39 +0000 (14:57 +0300)
committerbugmaster <bugmaster@opencascade.com>
Tue, 23 Apr 2019 15:17:47 +0000 (18:17 +0300)
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.

12 files changed:
src/BndLib/BndLib_Add3dCurve.cxx
src/Geom/Geom_BSplineCurve.cxx
src/Geom/Geom_BSplineCurve.hxx
src/Geom/Geom_BSplineSurface.cxx
src/Geom/Geom_BSplineSurface.hxx
src/Geom2d/Geom2d_BSplineCurve.cxx
src/Geom2d/Geom2d_BSplineCurve.hxx
src/GeomliteTest/GeomliteTest_CurveCommands.cxx
src/GeomliteTest/GeomliteTest_SurfaceCommands.cxx
tests/bugs/modalg_7/bug30645_1 [new file with mode: 0644]
tests/bugs/modalg_7/bug30645_2 [new file with mode: 0644]
tests/bugs/modalg_7/bug30645_3 [new file with mode: 0644]

index 3d9a697..c7226d9 100644 (file)
@@ -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)->
index 7792def..807eacd 100644 (file)
@@ -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);
 
index dc28c43..ae03665 100644 (file)
@@ -20,6 +20,7 @@
 #include <Standard.hxx>
 #include <Standard_Type.hxx>
 
+#include <Precision.hxx>
 #include <Standard_Boolean.hxx>
 #include <GeomAbs_BSplKnotDistribution.hxx>
 #include <GeomAbs_Shape.hxx>
@@ -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 <me> 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
index 8bbd8cb..f538442 100644 (file)
@@ -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);
 }
 
 //=======================================================================
index 9a54bf0..40decde 100644 (file)
@@ -20,6 +20,7 @@
 #include <Standard.hxx>
 #include <Standard_Type.hxx>
 
+#include <Precision.hxx>
 #include <Standard_Boolean.hxx>
 #include <GeomAbs_BSplKnotDistribution.hxx>
 #include <GeomAbs_Shape.hxx>
@@ -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 <me> 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 <me> 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 <me> 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:
index 9ab6e27..1229c61 100644 (file)
@@ -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;
index 948a01f..822ded7 100644 (file)
@@ -20,6 +20,7 @@
 #include <Standard.hxx>
 #include <Standard_Type.hxx>
 
+#include <Precision.hxx>
 #include <Standard_Boolean.hxx>
 #include <GeomAbs_BSplKnotDistribution.hxx>
 #include <GeomAbs_Shape.hxx>
@@ -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 <me> 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
index 426d8d7..c198f14 100644 (file)
@@ -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);
 
index 7106656..5716fe7 100644 (file)
@@ -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 (file)
index 0000000..1674568
--- /dev/null
@@ -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 (file)
index 0000000..0ba33ee
--- /dev/null
@@ -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 (file)
index 0000000..0971525
--- /dev/null
@@ -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"
+}