0024682: Move out B-spline cache from curves and surfaces to dedicated classes BSplCL...
authorazv <azv@opencascade.com>
Thu, 28 May 2015 10:36:57 +0000 (13:36 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 May 2015 10:38:22 +0000 (13:38 +0300)
1. B-spline cache was moved into separated classes: BSplCLib_Cache for 2D and 3D curves and BSplSLib_Cache for surfaces.

2. The cache is used now in corresponding adaptor classes (Geom2dAdaptor_Curve, GeomAdaptor_Curve and GeomAdaptor_Surface) when the curve or surface is a B-spline.

3. Algorithms were changed to use adaptors for B-spline calculations instead of curves or surfaces.

4. Precised calculation of derivatives of surface of revolution is implemented for the points of surface placed on the axis of revolution (Geom_SurfaceOfRevolution.cxx)

5. Small modifications are made to adjust algorithms to new behavior of B-spline calculation.

6. Test cases were modified according to the modern behavior.

7. Changes in BOPAlgo_WireSplitter, BOPTools_AlgoTools, BRepLib_CheckCurveOnSurface and ShapeAnalysis_Wire to use adaptors instead of geometric entities

8. Allow Geom2dAdaptor and GeomAdaptor in case of offset curve to use corresponding adaptor for basis curve

Modification of test-cases according to the new behavior.

137 files changed:
src/Adaptor3d/Adaptor3d_TopolTool.cxx
src/BOPAlgo/BOPAlgo_WireSplitter_1.cxx
src/BOPTools/BOPTools_AlgoTools.cxx
src/BOPTools/BOPTools_AlgoTools_1.cxx
src/BOPTools/BOPTools_AlgoTools_2.cxx
src/BRepCheck/BRepCheck_Wire.cxx
src/BRepFill/BRepFill_OffsetWire.cxx
src/BRepLib/BRepLib_CheckCurveOnSurface.cxx
src/BRepLib/BRepLib_MakeEdge.cxx
src/BSplCLib/BSplCLib.cdl
src/BSplCLib/BSplCLib.cxx
src/BSplCLib/BSplCLib_Cache.cxx [new file with mode: 0644]
src/BSplCLib/BSplCLib_Cache.hxx [new file with mode: 0644]
src/BSplCLib/BSplCLib_CurveComputation.gxx
src/BSplCLib/FILES
src/BSplSLib/BSplSLib.cdl
src/BSplSLib/BSplSLib.cxx
src/BSplSLib/BSplSLib_Cache.cxx [new file with mode: 0644]
src/BSplSLib/BSplSLib_Cache.hxx [new file with mode: 0644]
src/BSplSLib/FILES
src/CSLib/CSLib.cxx
src/CSLib/CSLib_Offset.cxx [new file with mode: 0644]
src/CSLib/CSLib_Offset.hxx [new file with mode: 0644]
src/CSLib/FILES [new file with mode: 0644]
src/Extrema/Extrema_GExtPC.gxx
src/Geom/Geom_BSplineCurve.cdl
src/Geom/Geom_BSplineCurve.cxx
src/Geom/Geom_BSplineCurve_1.cxx
src/Geom/Geom_BSplineSurface.cdl
src/Geom/Geom_BSplineSurface.cxx
src/Geom/Geom_BSplineSurface_1.cxx
src/Geom/Geom_OffsetCurve.cxx
src/Geom/Geom_SurfaceOfRevolution.cxx
src/Geom2d/Geom2d_BSplineCurve.cdl
src/Geom2d/Geom2d_BSplineCurve.cxx
src/Geom2d/Geom2d_BSplineCurve_1.cxx
src/Geom2d/Geom2d_OffsetCurve.cxx
src/Geom2dAdaptor/Geom2dAdaptor.cdl
src/Geom2dAdaptor/Geom2dAdaptor_Curve.cdl
src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx
src/GeomAdaptor/GeomAdaptor.cdl
src/GeomAdaptor/GeomAdaptor_Curve.cdl
src/GeomAdaptor/GeomAdaptor_Curve.cxx
src/GeomAdaptor/GeomAdaptor_Surface.cdl
src/GeomAdaptor/GeomAdaptor_Surface.cxx
src/GeomInt/GeomInt_IntSS_1.cxx
src/GeomLib/GeomLib.cxx
src/IntCurve/IntCurve_IntPolyPolyGen.gxx
src/IntPatch/IntPatch_ImpPrmIntersection.cxx
src/IntWalk/IntWalk_PWalking.cxx
src/ShapeAnalysis/ShapeAnalysis_Curve.cxx
src/ShapeAnalysis/ShapeAnalysis_Wire.cxx
src/ShapeFix/ShapeFix_EdgeProjAux.cxx
src/ShapeFix/ShapeFix_Face.cxx
src/ShapeFix/ShapeFix_IntersectionTool.cxx
src/ShapeFix/ShapeFix_Wire.cxx
src/StepToTopoDS/StepToTopoDS_TranslateEdge.cxx
src/math/math_FunctionRoots.cxx
src/math/math_TrigonometricFunctionRoots.cxx
tests/boolean/bfuse_complex/F5
tests/boolean/bfuse_complex/Q2
tests/boolean/bsection/M9
tests/boolean/bsection/N4
tests/boolean/volumemaker/F8
tests/bugs/modalg_2/bug5805_21
tests/bugs/modalg_2/bug5805_22
tests/bugs/modalg_2/bug5805_23
tests/bugs/modalg_2/bug5805_24
tests/bugs/modalg_2/bug5805_41
tests/bugs/modalg_2/bug5805_43
tests/bugs/modalg_4/bug714
tests/bugs/modalg_5/bug24200
tests/bugs/modalg_5/bug24303
tests/bugs/modalg_5/bug25175
tests/bugs/modalg_6/bug25908
tests/bugs/moddata_1/bug16119
tests/bugs/moddata_1/bug22759
tests/bugs/moddata_2/bug36
tests/bugs/moddata_2/bug498
tests/bugs/moddata_3/bug25207
tests/de/iges_1/F9
tests/de/iges_1/J2
tests/de/iges_1/J3
tests/de/iges_1/J9
tests/de/iges_1/K3
tests/de/iges_1/L8
tests/de/iges_1/M7
tests/de/iges_1/O3
tests/de/iges_1/O4
tests/de/iges_1/P5
tests/de/iges_1/P7
tests/de/iges_1/P9
tests/de/iges_1/R8
tests/de/iges_2/A9
tests/de/iges_2/B6
tests/de/iges_2/B8
tests/de/iges_2/C2
tests/de/iges_2/D8
tests/de/iges_2/F1
tests/de/iges_2/H9
tests/de/iges_3/A2
tests/de/iges_3/A4
tests/de/iges_3/B2
tests/de/step_1/A3
tests/de/step_1/D9
tests/de/step_1/G9
tests/de/step_1/J6
tests/de/step_1/J8
tests/de/step_2/B5
tests/de/step_2/B6
tests/de/step_2/E7
tests/de/step_2/F4
tests/de/step_2/M4
tests/de/step_2/N8
tests/de/step_2/R2
tests/de/step_2/S1
tests/de/step_2/T1
tests/de/step_2/T9
tests/de/step_2/U8
tests/de/step_2/Y5
tests/de/step_3/A4
tests/de/step_3/A8
tests/de/step_3/A9
tests/de/step_3/B9
tests/de/step_3/C5
tests/de/step_3/D3
tests/de/step_3/D8
tests/de/step_3/E6
tests/de/step_5/A1
tests/de/step_5/A4
tests/heal/split_angle/F2
tests/heal/split_closed_faces/G5
tests/offset/wire_closed_inside_0_005/D1
tests/offset/wire_closed_inside_0_075/E8
tests/offset/wire_closed_outside_0_005/D1
tests/offset/wire_closed_outside_0_005/E8
tests/offset/wire_closed_outside_0_075/E8

index cdecee8..deed6c2 100644 (file)
@@ -14,6 +14,7 @@
 #include <Standard_NotImplemented.hxx>
 #include <Adaptor3d_TopolTool.ixx>
 #include <Precision.hxx>
+#include <GeomAdaptor_Surface.hxx>
 
 #include <gp_Cone.hxx>
 #include <gp_Pnt.hxx>
@@ -1080,6 +1081,10 @@ void Adaptor3d_TopolTool::BSplSamplePnts(const Standard_Real theDefl,
   Standard_Real tol = Max(0.01*aDefl2, 1.e-9);
   Standard_Integer l;
 
+  // Calculations of B-spline values will be made using adaptor,
+  // because it caches the data for performance
+  GeomAdaptor_Surface aBSplAdaptor(aBS);
+
   anUFlg(1) = Standard_True;
   anUFlg(nbsu) = Standard_True;
   //myNbSamplesU = 2; 
@@ -1095,10 +1100,12 @@ void Adaptor3d_TopolTool::BSplSamplePnts(const Standard_Real theDefl,
       }
 
       t2 = anUPars(j);
-      gp_Pnt p1 = aBS->Value(t2, t1);
+//      gp_Pnt p1 = aBS->Value(t2, t1);
+      gp_Pnt p1 = aBSplAdaptor.Value(t2, t1);
       for(k = j+2; k <= nbsu; ++k) {
        t2 = anUPars(k);
-       gp_Pnt p2 = aBS->Value(t2, t1);
+//     gp_Pnt p2 = aBS->Value(t2, t1);
+       gp_Pnt p2 = aBSplAdaptor.Value(t2, t1);
        //gce_MakeLin MkLin(p1, p2);
        //const gp_Lin& lin = MkLin.Value();
 
@@ -1113,7 +1120,8 @@ void Adaptor3d_TopolTool::BSplSamplePnts(const Standard_Real theDefl,
            break;
          }
 
-         gp_Pnt pp =  aBS->Value(anUPars(l), t1);
+//       gp_Pnt pp =  aBS->Value(anUPars(l), t1);
+         gp_Pnt pp =  aBSplAdaptor.Value(anUPars(l), t1);
          Standard_Real d = lin.SquareDistance(pp);
          
          if(d <= aDefl2) continue;
@@ -1180,10 +1188,12 @@ void Adaptor3d_TopolTool::BSplSamplePnts(const Standard_Real theDefl,
       }
 
       t2 = aVPars(j);
-      gp_Pnt p1 = aBS->Value(t1, t2);
+//      gp_Pnt p1 = aBS->Value(t1, t2);
+      gp_Pnt p1 = aBSplAdaptor.Value(t1, t2);
       for(k = j+2; k <= nbsv; ++k) {
        t2 = aVPars(k);
-       gp_Pnt p2 = aBS->Value(t1, t2);
+//     gp_Pnt p2 = aBS->Value(t1, t2);
+       gp_Pnt p2 = aBSplAdaptor.Value(t1, t2);
 
        if(p1.SquareDistance(p2) <= tol) continue;
        //gce_MakeLin MkLin(p1, p2);
@@ -1197,7 +1207,8 @@ void Adaptor3d_TopolTool::BSplSamplePnts(const Standard_Real theDefl,
            break;
          }
 
-         gp_Pnt pp =  aBS->Value(t1, aVPars(l));
+//       gp_Pnt pp =  aBS->Value(t1, aVPars(l));
+         gp_Pnt pp =  aBSplAdaptor.Value(t1, aVPars(l));
          Standard_Real d = lin.SquareDistance(pp);
          
          if(d <= aDefl2) continue;
index 3440866..7e6d9fc 100644 (file)
@@ -762,8 +762,8 @@ Standard_Integer NbWaysOut(const BOPAlgo_ListOfEdgeInfo& aLEInfo)
     aTV1=aTV - dt;
   }
   //
-  aC2D->D0 (aTV1, aPV1);
-  aC2D->D0 (aTV, aPV);
+  aGAC2D.D0 (aTV1, aPV1);
+  aGAC2D.D0 (aTV, aPV);
   //
   aV2D = bIsIN ? gp_Vec2d(aPV1, aPV) : gp_Vec2d(aPV, aPV1);
   //
@@ -1017,15 +1017,15 @@ Standard_Boolean RefineAngle2D(const TopoDS_Vertex& aV,
   aTolInt=1.e-10;  
   //
   BOPTools_AlgoTools2D::CurveOnSurface(aE, myFace, aC2D, aT1, aT2, aTol);
+  aGAC1.Load(aC2D, aT1, aT2);
   //
   aTV=BRep_Tool::Parameter (aV, aE, myFace);
-  aC2D->D0(aTV, aPV);
+  aGAC1.D0(aTV, aPV);
   //
   aTOp = (fabs(aTV-aT1) < fabs(aTV-aT2)) ? aT2 : aT1;
   //
-  aGAC1.Load(aC2D, aT1, aT2);
-  aC2D->D0(aT1, aP1);
-  aC2D->D0(aT2, aP2);
+  aGAC1.D0(aT1, aP1);
+  aGAC1.D0(aT2, aP2);
   aDomain1.SetValues(aP1, aT1, aTolInt, aP2, aT2, aTolInt);
   //
   for (i=0; i<2; ++i) {
@@ -1066,7 +1066,7 @@ Standard_Boolean RefineAngle2D(const TopoDS_Vertex& aV,
     }
     //
     aT=aT1max + aCf*dT;
-    aC2D->D0(aT, aP);
+    aGAC1.D0(aT, aP);
     gp_Vec2d aV2D(aPV, aP);
     gp_Dir2d aDir2D(aV2D);
     //
index 1ed5095..85d1e8a 100644 (file)
@@ -1281,10 +1281,10 @@ Standard_Boolean BOPTools_AlgoTools::IsHole(const TopoDS_Shape& aW,
       dU=-dU;
     }
     //
-    aC2D->D0(aU, aP2D0);
+    aBAC2D.D0(aU, aP2D0);
     for(i=2; i<=aNbS; i++) {
       aU=aU1+(i-1)*dU;
-      aC2D->D0(aU, aP2D1);
+      aBAC2D.D0(aU, aP2D1);
       aP2D0.Coord(aX0, aY0);
       aP2D1.Coord(aX1, aY1);
       //
index 1bfcdfc..10efe77 100644 (file)
@@ -111,7 +111,7 @@ static
 static 
   Standard_Real IntersectCurves2d(const gp_Pnt& aPV,
                                   const TopoDS_Face& aF,
-                                  const Handle(Geom_Surface)& aS,
+                                  const GeomAdaptor_Surface& aS,
                                   const TopoDS_Edge& aE1,
                                   const TopoDS_Edge& aE2);
 
@@ -558,7 +558,7 @@ void CorrectWires(const TopoDS_Face& aFx)
       aT=BRep_Tool::Parameter(aV, aE);
       //
       aC2D->D0(aT, aP2D);
-      aS->D0(aP2D.X(), aP2D.Y(), aP);
+      aGAS.D0(aP2D.X(), aP2D.Y(), aP);
       aD2=aPV.SquareDistance(aP);
       if (aD2>aD2max) {
         aD2max=aD2;
@@ -586,7 +586,7 @@ void CorrectWires(const TopoDS_Face& aFx)
           continue;
         }
         //
-        aD2=IntersectCurves2d(aPV, aF, aS, aE, aE1);
+        aD2=IntersectCurves2d(aPV, aF, aGAS, aE, aE1);
         if (aD2>aD2max) {
           aD2max=aD2;
         }
@@ -606,7 +606,7 @@ void CorrectWires(const TopoDS_Face& aFx)
 //=======================================================================
 Standard_Real IntersectCurves2d(const gp_Pnt& aPV,
                                 const TopoDS_Face& aF,
-                                const Handle(Geom_Surface)& aS,
+                                const GeomAdaptor_Surface& aGAS,
                                 const TopoDS_Edge& aE1,
                                 const TopoDS_Edge& aE2)
 {
@@ -650,7 +650,7 @@ Standard_Real IntersectCurves2d(const gp_Pnt& aPV,
         }          
         //
         aP2D = aPoint.Value();
-        aS->D0(aP2D.X(), aP2D.Y(), aP);
+        aGAS.D0(aP2D.X(), aP2D.Y(), aP);
         aD=aPV.SquareDistance(aP);
         if (aD > aDist) {
           aDist = 1.01 * aD;
index 78e6181..19003d5 100644 (file)
@@ -74,8 +74,8 @@ void BOPTools_AlgoTools::UpdateVertex (const TopoDS_Edge& aE,
   gp_Pnt aPv=BRep_Tool::Pnt(aV);
   aTolV=BRep_Tool::Tolerance(aV);
 
-  Handle(Geom_Curve) aC3D=BRep_Tool::Curve(aE, aFirst, aLast);
-  aC3D->D0(aT, aPc);
+  GeomAdaptor_Curve aCA( BRep_Tool::Curve(aE, aFirst, aLast) );
+  aCA.D0(aT, aPc);
   aDist=aPv.Distance(aPc);
   if (aDist>aTolV) {
     BRep_Builder BB;
@@ -97,8 +97,8 @@ void BOPTools_AlgoTools::UpdateVertex (const IntTools_Curve& aC,
   gp_Pnt aPv=BRep_Tool::Pnt(aV);
   aTolV=BRep_Tool::Tolerance(aV);
 
-  Handle(Geom_Curve) aC3D=aC.Curve();
-  aC3D->D0(aT, aPc);
+  GeomAdaptor_Curve aCA( aC.Curve() );
+  aCA.D0(aT, aPc);
   aDist=aPv.Distance(aPc);
   if (aDist>aTolV) {
     BRep_Builder BB;
index e59fae7..e07e896 100644 (file)
@@ -108,7 +108,7 @@ inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
 }
 
 static
-  void CurveDirForParameter(const Handle(Geom2d_Curve)& aC2d,
+  void CurveDirForParameter(const Geom2dAdaptor_Curve& aC2d,
                            const Standard_Real aPrm,
                            gp_Pnt2d& Pnt,
                            gp_Vec2d& aVec2d);
@@ -1653,14 +1653,15 @@ void ChoixUV(const TopoDS_Vertex& theVertex,
     C2d = BRep_Tool::CurveOnSurface(anE, theFace, aFirstParam, aLastParam);
     if(C2d.IsNull())
       continue;
+    Geom2dAdaptor_Curve aCA(C2d);
 
     aParam =(aVOrientation != anE.Orientation()) ? aFirstParam : aLastParam;
-    aPnt = C2d->Value(aParam);
+    aPnt = aCA.Value(aParam);
 
     if(!IsDistanceIn2DTolerance(aFaceSurface, aPnt, aPntRef, aTol3d, Standard_False))
       continue;
 
-    CurveDirForParameter(C2d, aParam, aPnt, aDer);
+    CurveDirForParameter(aCA, aParam, aPnt, aDer);
 
     if (aVOrientation == anE.Orientation())
       aDer.Reverse();
@@ -1753,21 +1754,21 @@ void ChoixUV(const TopoDS_Vertex& theVertex,
 //function : CurveDirForParameter
 //purpose  : 
 //=======================================================================
-void CurveDirForParameter(const Handle(Geom2d_Curve)& aC2d,
-                         const Standard_Real aPrm,
-                         gp_Pnt2d& Pnt,
-                         gp_Vec2d& aVec2d)
+void CurveDirForParameter(const Geom2dAdaptor_Curve& aC2d,
+                          const Standard_Real aPrm,
+                          gp_Pnt2d& Pnt,
+                          gp_Vec2d& aVec2d)
 {
   Standard_Real aTol=gp::Resolution();
   Standard_Integer i;
 
-  aC2d->D1(aPrm, Pnt, aVec2d);
+  aC2d.D1(aPrm, Pnt, aVec2d);
   //
   if (aVec2d.Magnitude() <= aTol) {
     for (i = 2; i <= 100; i++){
-      aVec2d = aC2d->DN(aPrm, i);
+      aVec2d = aC2d.DN(aPrm, i);
       if (aVec2d.Magnitude() > aTol) {
-       break;
+        break;
       }
     }
   }
index 5d21673..926c880 100644 (file)
@@ -2232,10 +2232,10 @@ void TrimEdge (const TopoDS_Edge&              E,
   // otherwise preserve only one of its representations.
   //----------------------------------------------------------
   if (!BRep_Tool::Degenerated(E)) {
+    Standard_Real aParTol = 2.0 * Precision::PConfusion();
     for (Standard_Integer k = 1; k < TheVer.Length(); k ++) {
       if (TheVer.Value(k).IsSame(TheVer.Value(k+1)) || 
-
-        Abs(ThePar.Value(k)-ThePar.Value(k+1)) <= Precision::PConfusion()) {
+          Abs(ThePar.Value(k)-ThePar.Value(k+1)) <= aParTol) {
 
           if(k+1 == TheVer.Length()) {
             StoreInMap(TheVer(k), TheVer(k+1), MapVV);
index d8556a4..3219959 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <GeomAdaptor_HSurface.hxx>
 #include <GeomAdaptor_HCurve.hxx>
+#include <Geom2dAdaptor_HCurve.hxx>
 
 #include <GeomProjLib.hxx>
 
@@ -56,12 +57,12 @@ class BRepLib_CheckCurveOnSurface_GlobOptFunc :
      const Standard_Real theFirst,
      const Standard_Real theLast)
     :
-      myCurve(theC3D),
-      myPCurve(theC2D),
-      mySurf(theSurf),
       myFirst(theFirst),
       myLast(theLast)
   {
+    myCurve = new GeomAdaptor_HCurve(theC3D);
+    myPCurve = new Geom2dAdaptor_HCurve(theC2D);
+    mySurf = new GeomAdaptor_HSurface(theSurf);
   }
   //
   virtual Standard_Integer NbVariables() const {
@@ -160,9 +161,9 @@ class BRepLib_CheckCurveOnSurface_GlobOptFunc :
     return ((myFirst <= theParam) && (theParam <= myLast));
   }
 
-  Handle(Geom_Curve) myCurve;
-  Handle(Geom2d_Curve) myPCurve;
-  Handle(Geom_Surface) mySurf;
+  Handle(GeomAdaptor_HCurve) myCurve;
+  Handle(Geom2dAdaptor_HCurve) myPCurve;
+  Handle(GeomAdaptor_HSurface) mySurf;
   Standard_Real myFirst;
   Standard_Real myLast;
 };
index 74e9940..13fc409 100644 (file)
@@ -773,7 +773,7 @@ void  BRepLib_MakeEdge::Init(const Handle(Geom_Curve)& CC,
   Standard_Real cl = C->LastParameter();
   Standard_Real epsilon = Precision::PConfusion();
   Standard_Boolean periodic = C->IsPeriodic();
-
+  GeomAdaptor_Curve aCA(C);
 
   TopoDS_Vertex V1,V2;
   if (periodic) {
@@ -813,14 +813,15 @@ void  BRepLib_MakeEdge::Init(const Handle(Geom_Curve)& CC,
   Standard_Boolean p1inf = Precision::IsNegativeInfinite(p1);
   Standard_Boolean p2inf = Precision::IsPositiveInfinite(p2);
   gp_Pnt P1,P2;
-  if (!p1inf) P1 = C->Value(p1);
-  if (!p2inf) P2 = C->Value(p2);
+  if (!p1inf) P1 = aCA.Value(p1);
+  if (!p2inf) P2 = aCA.Value(p2);
 
   Standard_Real preci = BRepLib::Precision();
   BRep_Builder B;
 
   // check for closed curve
   Standard_Boolean closed = Standard_False;
+  Standard_Boolean degenerated = Standard_False;
   if (!p1inf && !p2inf)
     closed = (P1.Distance(P2) <= preci);
 
@@ -836,13 +837,19 @@ void  BRepLib_MakeEdge::Init(const Handle(Geom_Curve)& CC,
       V2 = V1;
     else {
       if (!V1.IsSame(V2)) {
-       myError = BRepLib_DifferentPointsOnClosedCurve;
-       return;
+        myError = BRepLib_DifferentPointsOnClosedCurve;
+        return;
       }
       else if (P1.Distance(BRep_Tool::Pnt(V1)) > 
-              Max(preci,BRep_Tool::Tolerance(V1))) {
-       myError = BRepLib_DifferentPointsOnClosedCurve;
-       return;
+        Max(preci,BRep_Tool::Tolerance(V1))) {
+        myError = BRepLib_DifferentPointsOnClosedCurve;
+        return;
+      }
+      else
+      {
+        gp_Pnt PM = aCA.Value((p1+p2)/2);
+        if (P1.Distance(PM) < preci)
+          degenerated = Standard_True;
       }
     }
   }
@@ -898,6 +905,7 @@ void  BRepLib_MakeEdge::Init(const Handle(Geom_Curve)& CC,
     B.Add(E,V2);
   }
   B.Range(E,p1,p2);
+  B.Degenerated(E, degenerated);
 
   myError = BRepLib_EdgeDone;
   Done();
index 70f49b7..e489b04 100644 (file)
@@ -104,6 +104,8 @@ uses TColStd, gp, TColgp, math, GeomAbs
 
 
 is
+    
+    imported transient class Cache;
 
     imported EvaluatorFunction ;
 
@@ -2063,6 +2065,30 @@ is
     --          If rational computes the homogeneous Taylor expension
     --          for the numerator and stores it in CachePoles
 
+    BuildCache(theParameter        : Real;
+               theSpanDomain       : Real;
+               thePeriodicFlag     : Boolean ;
+               theDegree           : Integer;
+               theFlatKnots        : Array1OfReal           from TColStd ;
+               thePoles            : Array1OfPnt            from TColgp;
+               theWeights          : Array1OfReal           from TColStd ;
+               theCacheArray       : in out Array2OfReal    from TColStd)   ;
+    ---Purpose: Perform the evaluation of the Taylor expansion
+    --          of the Bspline normalized between 0 and 1.
+    --          Structure of result optimized for BSplCLib_Cache.
+
+    BuildCache(theParameter        : Real;
+               theSpanDomain       : Real;
+               thePeriodicFlag     : Boolean ;
+               theDegree           : Integer;
+               theFlatKnots        : Array1OfReal           from TColStd ;
+               thePoles            : Array1OfPnt2d          from TColgp;
+               theWeights          : Array1OfReal           from TColStd ;
+               theCacheArray       : in out Array2OfReal    from TColStd)   ;
+    ---Purpose: Perform the evaluation of the Taylor expansion
+    --          of the Bspline normalized between 0 and 1.
+    --          Structure of result optimized for BSplCLib_Cache.
+
     PolesCoefficients(Poles         : Array1OfPnt2d   from TColgp;
                       CachePoles    : in out Array1OfPnt2d   from TColgp);
     ---Warning: To be used for Beziercurves ONLY!!!
@@ -2454,6 +2480,7 @@ is
     --          all u1 and u0 in the domain of the curve f(u) 
     --          | u1 - u0 | < UTolerance and 
     --          we have |f (u1) - f (u0)| < Tolerance3D
+    
 
 end BSplCLib;
 
index 0357c7e..c87c5b7 100644 (file)
@@ -73,6 +73,7 @@ void BSplCLib::Hunt (const Array1OfReal& XX,
 {
   // replaced by simple dichotomy (RLE)
   Ilc = XX.Lower();
+  if (XX.Length() <= 1) return;
   const Standard_Real *px = &XX(Ilc);
   px -= Ilc;
 
diff --git a/src/BSplCLib/BSplCLib_Cache.cxx b/src/BSplCLib/BSplCLib_Cache.cxx
new file mode 100644 (file)
index 0000000..4a4ce5a
--- /dev/null
@@ -0,0 +1,362 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <BSplCLib_Cache.hxx>
+#include <BSplCLib.hxx>
+
+#include <NCollection_LocalArray.hxx>
+
+#include <TColgp_HArray1OfPnt.hxx>
+#include <TColgp_HArray1OfPnt2d.hxx>
+#include <TColStd_HArray1OfReal.hxx>
+#include <TColStd_HArray2OfReal.hxx>
+
+IMPLEMENT_STANDARD_HANDLE(BSplCLib_Cache, Standard_Transient)
+IMPLEMENT_STANDARD_RTTIEXT(BSplCLib_Cache, Standard_Transient)
+
+//! Converts handle of array of Standard_Real into the pointer to Standard_Real
+static Standard_Real* ConvertArray(const Handle_TColStd_HArray2OfReal& theHArray)
+{
+  const TColStd_Array2OfReal& anArray = theHArray->Array2();
+  return (Standard_Real*) &(anArray(anArray.LowerRow(), anArray.LowerCol()));
+}
+
+
+BSplCLib_Cache::BSplCLib_Cache()
+{
+  myPolesWeights.Nullify();
+  myIsRational = Standard_False;
+  mySpanStart = 0.0;
+  mySpanLength = 0.0;
+  mySpanIndex = 0;
+  myDegree = 0;
+  myFlatKnots.Nullify();
+}
+
+BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer&        theDegree,
+                               const Standard_Boolean&        thePeriodic,
+                               const TColStd_Array1OfReal&    theFlatKnots,
+                               const TColgp_Array1OfPnt2d&    thePoles2d,
+                               const TColStd_Array1OfReal&    theWeights)
+{
+  Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree);
+  BuildCache(aCacheParam, theDegree, thePeriodic, 
+             theFlatKnots, thePoles2d, theWeights);
+}
+
+BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer&        theDegree,
+                               const Standard_Boolean&        thePeriodic,
+                               const TColStd_Array1OfReal&    theFlatKnots,
+                               const TColgp_Array1OfPnt&      thePoles,
+                               const TColStd_Array1OfReal&    theWeights)
+{
+  Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree);
+  BuildCache(aCacheParam, theDegree, thePeriodic, 
+             theFlatKnots, thePoles, theWeights);
+}
+
+
+Standard_Boolean BSplCLib_Cache::IsCacheValid(Standard_Real theParameter) const
+{
+  Standard_Real aNewParam = theParameter;
+  if (!myFlatKnots.IsNull())
+    PeriodicNormalization(myFlatKnots->Array1(), aNewParam);
+
+  Standard_Real aDelta = aNewParam - mySpanStart;
+  return (aDelta >= 0.0 && (aDelta < mySpanLength || mySpanIndex == mySpanIndexMax));
+}
+
+void BSplCLib_Cache::PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, 
+                                           Standard_Real& theParameter) const
+{
+  Standard_Real aPeriod = theFlatKnots.Value(theFlatKnots.Upper() - myDegree) - 
+                          theFlatKnots.Value(myDegree + 1) ;
+  if (theParameter < theFlatKnots.Value(myDegree + 1))
+  {
+    Standard_Real aScale = IntegerPart(
+        (theFlatKnots.Value(myDegree + 1) - theParameter) / aPeriod);
+    theParameter += aPeriod * (aScale + 1.0);
+  }
+  if (theParameter > theFlatKnots.Value(theFlatKnots.Upper() - myDegree))
+  {
+    Standard_Real aScale = IntegerPart(
+        (theParameter - theFlatKnots.Value(theFlatKnots.Upper() - myDegree)) / aPeriod);
+    theParameter -= aPeriod * (aScale + 1.0);
+  }
+}
+
+
+void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
+                                const Standard_Integer&        theDegree,
+                                const Standard_Boolean&        thePeriodic,
+                                const TColStd_Array1OfReal&    theFlatKnots,
+                                const TColgp_Array1OfPnt2d&    thePoles2d,
+                                const TColStd_Array1OfReal&    theWeights)
+{
+  // Normalize theParameter for periodical B-splines
+  Standard_Real aNewParam = theParameter;
+  if (thePeriodic)
+  {
+    PeriodicNormalization(theFlatKnots, aNewParam);
+    myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length());
+    myFlatKnots->ChangeArray1() = theFlatKnots;
+  }
+  else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical
+    myFlatKnots.Nullify();
+
+  // Change the size of cached data if needed
+  myIsRational = (&theWeights != NULL);
+  Standard_Integer aPWColNumber = myIsRational ? 3 : 2;
+  if (theDegree > myDegree)
+    myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber);
+
+  myDegree = theDegree;
+  mySpanIndex = 0;
+  BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), 
+                            aNewParam, thePeriodic, mySpanIndex, aNewParam);
+  mySpanStart  = theFlatKnots.Value(mySpanIndex);
+  mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
+  mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
+
+  // Calculate new cache data
+  BSplCLib::BuildCache(mySpanStart, mySpanLength, thePeriodic, theDegree, 
+                       theFlatKnots, thePoles2d, theWeights, 
+                       myPolesWeights->ChangeArray2());
+}
+
+void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
+                                const Standard_Integer&        theDegree,
+                                const Standard_Boolean&        thePeriodic,
+                                const TColStd_Array1OfReal&    theFlatKnots,
+                                const TColgp_Array1OfPnt&      thePoles,
+                                const TColStd_Array1OfReal&    theWeights)
+{
+  // Create list of knots with repetitions and normalize theParameter for periodical B-splines
+  Standard_Real aNewParam = theParameter;
+  if (thePeriodic)
+  {
+    PeriodicNormalization(theFlatKnots, aNewParam);
+    myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length());
+    myFlatKnots->ChangeArray1() = theFlatKnots;
+  }
+  else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical
+    myFlatKnots.Nullify();
+
+  // Change the size of cached data if needed
+  myIsRational = (&theWeights != NULL);
+  Standard_Integer aPWColNumber = myIsRational ? 4 : 3;
+  if (theDegree > myDegree)
+    myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber);
+
+  myDegree = theDegree;
+  mySpanIndex = 0;
+  BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), 
+                            aNewParam, thePeriodic, mySpanIndex, aNewParam);
+  mySpanStart  = theFlatKnots.Value(mySpanIndex);
+  mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
+  mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
+
+  // Calculate new cache data
+  BSplCLib::BuildCache(mySpanStart, mySpanLength, thePeriodic, theDegree, 
+                       theFlatKnots, thePoles, theWeights, 
+                       myPolesWeights->ChangeArray2());
+}
+
+
+void BSplCLib_Cache::CalculateDerivative(const Standard_Real&    theParameter, 
+                                         const Standard_Integer& theDerivative, 
+                                               Standard_Real&    theDerivArray) const
+{
+  Standard_Real aNewParameter = theParameter;
+  if (!myFlatKnots.IsNull()) // B-spline is periodical
+    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
+  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+
+  // Temporary container. The maximal size of this container is defined by:
+  //    1) maximal derivative for cache evaluation, which is 3, plus one row for function values, 
+  //    2) and maximal dimension of the point, which is 3, plus one column for weights.
+  Standard_Real aTmpContainer[16];
+
+  // When the PLib::RationaDerivative needs to be called, use temporary container
+  Standard_Real* aPntDeriv = myIsRational ? aTmpContainer : &theDerivArray;
+
+  // When the degree of curve is lesser than the requested derivative,
+  // nullify array cells corresponding to greater derivatives
+  Standard_Integer aDerivative = theDerivative;
+  if (myDegree < theDerivative)
+  {
+    aDerivative = myDegree;
+    for (Standard_Integer ind = myDegree * aDimension; ind < (theDerivative + 1) * aDimension; ind++)
+    {
+      aPntDeriv[ind] = 0.0;
+      (&theDerivArray)[ind] = 0.0; // should be cleared separately, because aPntDeriv may look to another memory area
+    }
+  }
+
+  PLib::EvalPolynomial(aNewParameter, aDerivative, myDegree, aDimension, 
+                       aPolesArray[0], aPntDeriv[0]);
+  // Unnormalize derivatives since those are computed normalized
+  Standard_Real aFactor = 1.0;
+  for (Standard_Integer deriv = 1; deriv <= aDerivative; deriv++)
+  {
+    aFactor /= mySpanLength;
+    for (Standard_Integer ind = 0; ind < aDimension; ind++)
+      aPntDeriv[aDimension * deriv + ind] *= aFactor;
+  }
+
+  if (myIsRational) // calculate derivatives divided by weights derivatives
+    PLib::RationalDerivative(aDerivative, aDerivative, aDimension - 1, aPntDeriv[0], theDerivArray);
+}
+
+
+void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) const
+{
+  Standard_Real aNewParameter = theParameter;
+  if (!myFlatKnots.IsNull()) // B-spline is periodical
+    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
+  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Real aPoint[4];
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+
+  PLib::NoDerivativeEvalPolynomial(aNewParameter, myDegree,
+                                   aDimension, myDegree * aDimension,
+                                   aPolesArray[0], aPoint[0]);
+
+  thePoint.SetCoord(aPoint[0], aPoint[1]);
+  if (myIsRational)
+    thePoint.ChangeCoord().Divide(aPoint[2]);
+}
+
+void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt& thePoint) const
+{
+  Standard_Real aNewParameter = theParameter;
+  if (!myFlatKnots.IsNull()) // B-spline is periodical
+    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
+  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Real aPoint[4];
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+
+  PLib::NoDerivativeEvalPolynomial(aNewParameter, myDegree,
+                                   aDimension, myDegree * aDimension,
+                                   aPolesArray[0], aPoint[0]);
+
+  thePoint.SetCoord(aPoint[0], aPoint[1], aPoint[2]);
+  if (myIsRational)
+    thePoint.ChangeCoord().Divide(aPoint[3]);
+}
+
+
+void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[8]; // result storage (point and derivative coordinates)
+
+  this->CalculateDerivative(theParameter, 1, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1]);
+}
+
+void BSplCLib_Cache::D1(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_Vec& theTangent) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[8]; // result storage (point and derivative coordinates)
+
+  this->CalculateDerivative(theParameter, 1, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1], aPntDeriv[2]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1], aPntDeriv[aDimension + 2]);
+}
+
+void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent, gp_Vec2d& theCurvature) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[12]; // result storage (point and derivatives coordinates)
+
+  this->CalculateDerivative(theParameter, 2, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1]);
+  theCurvature.SetCoord(aPntDeriv[aDimension<<1], aPntDeriv[(aDimension<<1) + 1]);
+}
+
+void BSplCLib_Cache::D2(const Standard_Real& theParameter, gp_Pnt& thePoint, gp_Vec& theTangent, gp_Vec& theCurvature) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[12]; // result storage (point and derivatives coordinates)
+
+  this->CalculateDerivative(theParameter, 2, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1], aPntDeriv[2]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1], aPntDeriv[aDimension + 2]);
+  theCurvature.SetCoord(aPntDeriv[aDimension<<1], aPntDeriv[(aDimension<<1) + 1], aPntDeriv[(aDimension<<1) + 2]);
+}
+
+
+void BSplCLib_Cache::D3(const Standard_Real& theParameter, 
+                              gp_Pnt2d&      thePoint, 
+                              gp_Vec2d&      theTangent, 
+                              gp_Vec2d&      theCurvature,
+                              gp_Vec2d&      theTorsion) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[16]; // result storage (point and derivatives coordinates)
+
+  this->CalculateDerivative(theParameter, 3, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1]);
+  Standard_Integer aShift = aDimension << 1;
+  theCurvature.SetCoord(aPntDeriv[aShift], aPntDeriv[aShift + 1]);
+  aShift += aDimension;
+  theTorsion.SetCoord(aPntDeriv[aShift], aPntDeriv[aShift + 1]);
+}
+
+void BSplCLib_Cache::D3(const Standard_Real& theParameter, 
+                              gp_Pnt&        thePoint, 
+                              gp_Vec&        theTangent, 
+                              gp_Vec&        theCurvature,
+                              gp_Vec&        theTorsion) const
+{
+  Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
+  Standard_Real aPntDeriv[16]; // result storage (point and derivatives coordinates)
+
+  this->CalculateDerivative(theParameter, 3, aPntDeriv[0]);
+  if (myIsRational) // the size of aPntDeriv was changed by PLib::RationalDerivative
+    aDimension -= 1;
+
+  thePoint.SetCoord(aPntDeriv[0], aPntDeriv[1], aPntDeriv[2]);
+  theTangent.SetCoord(aPntDeriv[aDimension], aPntDeriv[aDimension + 1], aPntDeriv[aDimension + 2]);
+  Standard_Integer aShift = aDimension << 1;
+  theCurvature.SetCoord(aPntDeriv[aShift], aPntDeriv[aShift + 1], aPntDeriv[aShift + 2]);
+  aShift += aDimension;
+  theTorsion.SetCoord(aPntDeriv[aShift], aPntDeriv[aShift + 1], aPntDeriv[aShift + 2]);
+}
+
diff --git a/src/BSplCLib/BSplCLib_Cache.hxx b/src/BSplCLib/BSplCLib_Cache.hxx
new file mode 100644 (file)
index 0000000..05a3c86
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _BSplCLib_Cache_Headerfile
+#define _BSplCLib_Cache_Headerfile
+
+#include <Standard.hxx>
+#include <Standard_Macro.hxx>
+#include <Standard_DefineHandle.hxx>
+#include <Standard_Transient.hxx>
+
+#include <Handle_TColStd_HArray1OfReal.hxx>
+#include <Handle_TColStd_HArray2OfReal.hxx>
+
+#include <gp_Pnt2d.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Vec2d.hxx>
+#include <gp_Vec.hxx>
+
+class Handle(BSplCLib_Cache);
+class TColStd_Array1OfReal;
+class TColgp_Array1OfPnt;
+class TColgp_Array1OfPnt2d;
+
+#ifndef NOWEIGHTS_CURVE
+#define NOWEIGHTS_CURVE (*((TColStd_Array1OfReal*) NULL))
+#endif
+
+//! \brief A cache class for B-spline curves.
+//!
+//! Defines all data, that can be cached on a span of B-spline curve.
+//! The data should be recalculated in going from span to span.
+class BSplCLib_Cache : public Standard_Transient
+{
+public:
+  //! Default constructor
+  Standard_EXPORT BSplCLib_Cache();
+  //! Constructor for caching of 2D curves
+  //! \param theDegree     degree of the B-spline
+  //! \param thePeriodic   identify the B-spline is periodic
+  //! \param theFlatKnots  knots of B-spline curve (with repetitions)
+  //! \param thePoles2d    array of poles of 2D B-spline
+  //! \param theWeights    array of weights of corresponding poles
+  Standard_EXPORT BSplCLib_Cache(const Standard_Integer&        theDegree,
+                                 const Standard_Boolean&        thePeriodic,
+                                 const TColStd_Array1OfReal&    theFlatKnots,
+                                 const TColgp_Array1OfPnt2d&    thePoles2d,
+                                 const TColStd_Array1OfReal&    theWeights = NOWEIGHTS_CURVE);
+  //! Constructor for caching of 3D curves
+  //! \param theDegree     degree of the B-spline
+  //! \param thePeriodic   identify the B-spline is periodic
+  //! \param theFlatKnots  knots of B-spline curve (with repetitions)
+  //! \param thePoles      array of poles of 3D B-spline
+  //! \param theWeights    array of weights of corresponding poles
+  Standard_EXPORT BSplCLib_Cache(const Standard_Integer&        theDegree,
+                                 const Standard_Boolean&        thePeriodic,
+                                 const TColStd_Array1OfReal&    theFlatKnots,
+                                 const TColgp_Array1OfPnt&      thePoles,
+                                 const TColStd_Array1OfReal&    theWeights = NOWEIGHTS_CURVE);
+
+  //! Verifies validity of the cache using flat parameter of the point
+  //! \param theParameter parameter of the point placed in the span
+  Standard_EXPORT Standard_Boolean IsCacheValid(Standard_Real theParameter) const;
+
+  //! Recomputes the cache data for 2D curves. Does not verify validity of the cache
+  //! \param theParameter  the value on the knot's axis to identify the span
+  //! \param theDegree     degree of the B-spline
+  //! \param thePeriodic   identify the B-spline is periodic
+  //! \param theFlatKnots  knots of B-spline curve (with repetitions)
+  //! \param thePoles2d    array of poles of 2D B-spline
+  //! \param theWeights    array of weights of corresponding poles
+  Standard_EXPORT void BuildCache(const Standard_Real&           theParameter,
+                                  const Standard_Integer&        theDegree,
+                                  const Standard_Boolean&        thePeriodic,
+                                  const TColStd_Array1OfReal&    theFlatKnots,
+                                  const TColgp_Array1OfPnt2d&    thePoles2d,
+                                  const TColStd_Array1OfReal&    theWeights = NOWEIGHTS_CURVE);
+  //! Recomputes the cache data for 3D curves. Does not verify validity of the cache
+  //! \param theParameter  the value on the knot's axis to identify the span
+  //! \param theDegree     degree of the B-spline
+  //! \param thePeriodic   identify the B-spline is periodic
+  //! \param theFlatKnots  knots of B-spline curve (with repetitions)
+  //! \param thePoles      array of poles of 3D B-spline
+  //! \param theWeights    array of weights of corresponding poles
+  Standard_EXPORT void BuildCache(const Standard_Real&           theParameter,
+                                  const Standard_Integer&        theDegree,
+                                  const Standard_Boolean&        thePeriodic,
+                                  const TColStd_Array1OfReal&    theFlatKnots,
+                                  const TColgp_Array1OfPnt&      thePoles,
+                                  const TColStd_Array1OfReal&    theWeights = NOWEIGHTS_CURVE);
+
+  //! Calculates the point on B-spline in the selected point
+  //! \param[in]  theParameter parameter of calculation of the value
+  //! \param[out] thePoint     the result of calculation (the point on B-spline)
+  Standard_EXPORT void D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) const;
+  Standard_EXPORT void D0(const Standard_Real& theParameter, gp_Pnt&   thePoint) const;
+
+  //! Calculates the point on B-spline and its first derivative in the selected point
+  //! \param[in]  theParameter parameter of calculation of the value
+  //! \param[out] thePoint     the result of calculation (the point on B-spline)
+  //! \param[out] theTangent   tangent vector (first derivatives) for B-spline in the calculated point
+  Standard_EXPORT void D1(const Standard_Real& theParameter, gp_Pnt2d& thePoint, gp_Vec2d& theTangent) const;
+  Standard_EXPORT void D1(const Standard_Real& theParameter, gp_Pnt&   thePoint, gp_Vec&   theTangent) const;
+
+  //! Calculates the point on B-spline and two derivatives in the selected point
+  //! \param[in]  theParameter parameter of calculation of the value
+  //! \param[out] thePoint     the result of calculation (the point on B-spline)
+  //! \param[out] theTangent   tangent vector (1st derivatives) for B-spline in the calculated point
+  //! \param[out] theCurvature curvature vector (2nd derivatives) for B-spline in the calculated point
+  Standard_EXPORT void D2(const Standard_Real& theParameter, 
+                                gp_Pnt2d&      thePoint, 
+                                gp_Vec2d&      theTangent, 
+                                gp_Vec2d&      theCurvature) const;
+  Standard_EXPORT void D2(const Standard_Real& theParameter, 
+                                gp_Pnt&        thePoint, 
+                                gp_Vec&        theTangent, 
+                                gp_Vec&        theCurvature) const;
+
+  //! Calculates the point on B-spline and three derivatives in the selected point
+  //! \param[in]  theParameter parameter of calculation of the value
+  //! \param[out] thePoint     the result of calculation (the point on B-spline)
+  //! \param[out] theTangent   tangent vector (1st derivatives) for B-spline in the calculated point
+  //! \param[out] theCurvature curvature vector (2nd derivatives) for B-spline in the calculated point
+  //! \param[out] theTorsion   second curvature vector (3rd derivatives) for B-spline in the calculated point
+  Standard_EXPORT void D3(const Standard_Real& theParameter, 
+                                gp_Pnt2d&      thePoint, 
+                                gp_Vec2d&      theTangent, 
+                                gp_Vec2d&      theCurvature,
+                                gp_Vec2d&      theTorsion) const;
+  Standard_EXPORT void D3(const Standard_Real& theParameter, 
+                                gp_Pnt&        thePoint, 
+                                gp_Vec&        theTangent, 
+                                gp_Vec&        theCurvature,
+                                gp_Vec&        theTorsion) const;
+
+
+  DEFINE_STANDARD_RTTI(BSplCLib_Cache)
+
+protected:
+  //! Normalizes the parameter for periodical B-splines
+  //! \param theFlatKnots knots with repetitions
+  //! \param theParameter the value to be normalized into the knots array
+  void PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, Standard_Real& theParameter) const;
+
+  //! Fills array of derivatives in the selected point of the B-spline
+  //! \param[in]  theParameter  parameter of the calculation
+  //! \param[in]  theDerivative maximal derivative to be calculated (computes all derivatives lesser than specified)
+  //! \param[out] theDerivArray result array of derivatives (with size (theDerivative+1)*(PntDim+1), 
+  //!                           where PntDim = 2 or 3 is a dimension of B-spline curve)
+  void CalculateDerivative(const Standard_Real&    theParameter, 
+                           const Standard_Integer& theDerivative, 
+                                 Standard_Real&    theDerivArray) const;
+
+private:
+  Handle(TColStd_HArray2OfReal) myPolesWeights; ///< array of poles and weights of calculated cache
+                                                // the array has following structure:
+                                                //       x1 y1 [z1] [w1]
+                                                //       x2 y2 [z2] [w2] etc
+                                                // for 2D-curves there is no z conponent, for non-rational curves there is no weight
+
+  Standard_Boolean              myIsRational; ///< identifies the rationality of B-spline
+  Standard_Real                 mySpanStart;  ///< parameter for the first point of the span
+  Standard_Real                 mySpanLength; ///< length of the span
+  Standard_Integer              mySpanIndex;  ///< index of the span on B-spline curve
+  Standard_Integer              mySpanIndexMax; ///< maximal number of spans on B-spline curve
+  Standard_Integer              myDegree;     ///< degree of B-spline
+  Handle(TColStd_HArray1OfReal) myFlatKnots;  ///< knots of B-spline (used for periodic normalization of parameters, exists only for periodical splines)
+};
+
+DEFINE_STANDARD_HANDLE(BSplCLib_Cache, Standard_Transient)
+
+#endif
index e71b4e0..f35fdd5 100644 (file)
@@ -19,6 +19,7 @@
 // xab : 12-Mar-96 : added MovePointAndTangent
 #include <TColStd_Array1OfInteger.hxx>
 #include <TColStd_Array1OfReal.hxx>
+#include <TColStd_Array2OfReal.hxx>
 #include <gp_Vec2d.hxx>
 #include <Standard_ConstructionError.hxx>
 #include <PLib.hxx>
@@ -1089,6 +1090,65 @@ void BSplCLib::BuildCache
   }
 }
 
+void BSplCLib::BuildCache(const Standard_Real          theParameter,
+                          const Standard_Real          theSpanDomain,
+                          const Standard_Boolean       thePeriodicFlag,
+                          const Standard_Integer       theDegree,
+                          const TColStd_Array1OfReal&  theFlatKnots,
+                          const Array1OfPoints&        thePoles,
+                          const TColStd_Array1OfReal&  theWeights,
+                                TColStd_Array2OfReal&  theCacheArray)
+{
+  Standard_Real    aParam = theParameter;
+  Standard_Integer anIndex = 0;
+  Standard_Integer aDimension;
+  Standard_Boolean isRational;
+  
+  BSplCLib_DataContainer dc(theDegree);
+  PrepareEval(aParam,
+              anIndex,
+              aDimension,
+              isRational,
+              theDegree,
+              thePeriodicFlag,
+              thePoles,
+              theWeights,
+              theFlatKnots,
+              (BSplCLib::NoMults()),
+              dc);
+  //
+  // Watch out : PrepareEval checks if locally the Bspline is polynomial
+  // therefore rational flag could be set to False even if there are 
+  // Weights. The Dimension is set accordingly.
+  //
+
+  Standard_Integer aCacheShift = // helps to store weights when PrepareEval did not found that the curve is locally polynomial
+    (&theWeights != NULL && !isRational) ? aDimension + 1 : aDimension;
+
+  BSplCLib::Bohm(aParam, theDegree, theDegree, *dc.knots, aDimension, *dc.poles);
+
+  Standard_Real aCoeff = 1.0;
+  Standard_Real* aCache = (Standard_Real *) &(theCacheArray(theCacheArray.LowerRow(), theCacheArray.LowerCol()));
+  Standard_Real* aPolyCoeffs = dc.poles;
+
+  for (Standard_Integer i = 0; i <= theDegree; i++)
+  {
+    for (Standard_Integer j = 0; j< aDimension; j++)
+      aCache[j] = aPolyCoeffs[j] * aCoeff;
+    aCoeff *= theSpanDomain / (i+1);
+    aPolyCoeffs += aDimension;
+    aCache += aDimension;
+    if (aCacheShift > aDimension)
+    {
+      aCache[0] = 0.0;
+      aCache++;
+    }
+  }
+
+  if (aCacheShift > aDimension)
+    theCacheArray.SetValue(theCacheArray.LowerRow(), theCacheArray.LowerCol() + aCacheShift - 1, 1.0);
+}
+
 //=======================================================================
 //function : Interpolate
 //purpose  : 
index ed982fe..e6705be 100755 (executable)
@@ -4,4 +4,5 @@ BSplCLib_3.cxx
 BSplCLib_BzSyntaxes.cxx
 BSplCLib_CurveComputation.gxx
 BSplCLib_EvaluatorFunction.hxx
-
+BSplCLib_Cache.hxx
+BSplCLib_Cache.cxx
index 73c053d..b413650 100644 (file)
@@ -71,6 +71,8 @@ uses TColStd, gp, TColgp
 
 
 is 
+    
+    imported transient class Cache;
 
     imported EvaluatorFunction ;
     ---Purpose:
@@ -465,6 +467,19 @@ is
     --          
     --     
 
+    BuildCache(theU,           theV           : Real;
+               theUSpanDomain, theVSpanDomain : Real;
+               theUPeriodic,   theVPeriodic   : Boolean;
+               theUDegree,     theVDegree     : Integer;
+               theUIndex,      theVIndex      : Integer;
+               theUFlatKnots,  theVFlatKnots  : Array1OfReal  from TColStd;
+               thePoles                       : Array2OfPnt   from TColgp;
+               theWeights                     : Array2OfReal  from TColStd;
+               theCacheArray           : in out Array2OfReal  from TColStd);
+    ---Purpose: Perform the evaluation of the Taylor expansion
+    --          of the Bspline normalized between 0 and 1.
+    --          Structure of result optimized for BSplSLib_Cache.
+
     CacheD0(U,V                             : Real;
            UDegree,VDegree                 : Integer;
             UCacheParameter,VCacheParameter : Real;
index 5ad633c..813d6ae 100644 (file)
@@ -2043,6 +2043,101 @@ void BSplSLib::BuildCache
   }
 }
 
+void BSplSLib::BuildCache(const Standard_Real          theU,
+                          const Standard_Real          theV,
+                          const Standard_Real          theUSpanDomain,
+                          const Standard_Real          theVSpanDomain,
+                          const Standard_Boolean       theUPeriodicFlag,
+                          const Standard_Boolean       theVPeriodicFlag,
+                          const Standard_Integer       theUDegree,
+                          const Standard_Integer       theVDegree,
+                          const Standard_Integer       theUIndex,
+                          const Standard_Integer       theVIndex,
+                          const TColStd_Array1OfReal&  theUFlatKnots,
+                          const TColStd_Array1OfReal&  theVFlatKnots,
+                          const TColgp_Array2OfPnt&    thePoles,
+                          const TColStd_Array2OfReal&  theWeights,
+                                TColStd_Array2OfReal&  theCacheArray)
+{
+  Standard_Boolean flag_u_or_v;
+  Standard_Integer d1, d2;
+  Standard_Real    u1, u2;
+  Standard_Boolean isRationalOnParam = (&theWeights != NULL);
+  Standard_Boolean isRational;
+
+  BSplSLib_DataContainer dc(theUDegree, theVDegree);
+  flag_u_or_v =
+    PrepareEval(theU, theV, theUIndex, theVIndex, theUDegree, theVDegree,
+                isRationalOnParam, isRationalOnParam,
+                theUPeriodicFlag, theVPeriodicFlag,
+                thePoles, theWeights,
+                theUFlatKnots, theVFlatKnots,
+                (BSplCLib::NoMults()), (BSplCLib::NoMults()),
+                u1, u2, d1, d2, isRational, dc);
+
+  Standard_Integer d2p1 = d2 + 1;
+  Standard_Integer aDimension = isRational ? 4 : 3;
+  Standard_Integer aCacheShift = // helps to store weights when PrepareEval did not found that the surface is locally polynomial
+    (isRationalOnParam && !isRational) ? aDimension + 1 : aDimension;
+
+  Standard_Real aDomains[2];
+  // aDomains[0] corresponds to variable with minimal degree
+  // aDomains[1] corresponds to variable with maximal degree
+  if (flag_u_or_v)
+  {
+    aDomains[0] = theUSpanDomain;
+    aDomains[1] = theVSpanDomain;
+  }
+  else
+  {
+    aDomains[0] = theVSpanDomain;
+    aDomains[1] = theUSpanDomain;
+  }
+
+  BSplCLib::Bohm(u1, d1, d1, *dc.knots1, aDimension * d2p1, *dc.poles);
+  for (Standard_Integer kk = 0; kk <= d1 ; kk++) 
+    BSplCLib::Bohm(u2, d2, d2, *dc.knots2, aDimension, *(dc.poles + kk * aDimension * d2p1));
+
+  Standard_Real* aCache = (Standard_Real *) &(theCacheArray(theCacheArray.LowerRow(), theCacheArray.LowerCol()));
+  Standard_Real* aPolyCoeffs = dc.poles;
+
+  Standard_Real aFactors[2];
+  // aFactors[0] corresponds to variable with minimal degree
+  // aFactors[1] corresponds to variable with maximal degree
+  aFactors[1] = 1.0;
+  Standard_Integer aRow, aCol, i;
+  Standard_Real aCoeff;
+  for (aRow = 0; aRow <= d2; aRow++)
+  {
+    aFactors[0] = 1.0;
+    for (aCol = 0; aCol <= d1; aCol++)
+    {
+      aPolyCoeffs = dc.poles + (aCol * d2p1 + aRow) * aDimension;
+      aCoeff = aFactors[0] * aFactors[1];
+      for (i = 0; i < aDimension; i++)
+        aCache[i] = aPolyCoeffs[i] * aCoeff;
+      aCache += aCacheShift;
+      aFactors[0] *= aDomains[0] / (aCol + 1);
+    }
+    aFactors[1] *= aDomains[1] / (aRow + 1);
+  }
+
+  // Fill the weights for the surface which is not locally polynomial
+  if (aCacheShift > aDimension)
+  {
+    aCache = (Standard_Real *) &(theCacheArray(theCacheArray.LowerRow(), theCacheArray.LowerCol()));
+    aCache += aCacheShift - 1;
+    for (aRow = 0; aRow <= d2; aRow++)
+      for (aCol = 0; aCol <= d1; aCol++)
+      {
+        *aCache = 0.0;
+        aCache += aCacheShift;
+      }
+    theCacheArray.SetValue(theCacheArray.LowerRow(), theCacheArray.LowerCol() + aCacheShift - 1, 1.0);
+  }
+}
+
+
 //=======================================================================
 //function : CacheD0
 //purpose  : Evaluates the polynomial cache of the Bspline Curve
diff --git a/src/BSplSLib/BSplSLib_Cache.cxx b/src/BSplSLib/BSplSLib_Cache.cxx
new file mode 100644 (file)
index 0000000..dbc8e41
--- /dev/null
@@ -0,0 +1,407 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <BSplSLib_Cache.hxx>
+#include <BSplSLib.hxx>
+
+#include <NCollection_LocalArray.hxx>
+
+#include <TColgp_HArray2OfPnt.hxx>
+#include <TColStd_HArray1OfInteger.hxx>
+#include <TColStd_HArray1OfReal.hxx>
+#include <TColStd_HArray2OfReal.hxx>
+
+IMPLEMENT_STANDARD_HANDLE(BSplSLib_Cache, Standard_Transient)
+IMPLEMENT_STANDARD_RTTIEXT(BSplSLib_Cache, Standard_Transient)
+
+//! Converts handle of array of Standard_Real into the pointer to Standard_Real
+static Standard_Real* ConvertArray(const Handle_TColStd_HArray2OfReal& theHArray)
+{
+  const TColStd_Array2OfReal& anArray = theHArray->Array2();
+  return (Standard_Real*) &(anArray(anArray.LowerRow(), anArray.LowerCol()));
+}
+
+
+BSplSLib_Cache::BSplSLib_Cache()
+{
+  myPolesWeights.Nullify();
+  myIsRational = Standard_False;
+  mySpanStart[0]  = mySpanStart[1]  = 0.0;
+  mySpanLength[0] = mySpanLength[1] = 0.0;
+  mySpanIndex[0]  = mySpanIndex[1]  = 0;
+  myDegree[0]     = myDegree[1]     = 0;
+  myFlatKnots[0].Nullify();
+  myFlatKnots[1].Nullify();
+}
+
+BSplSLib_Cache::BSplSLib_Cache(const Standard_Integer&        theDegreeU,
+                               const Standard_Boolean&        thePeriodicU,
+                               const TColStd_Array1OfReal&    theFlatKnotsU,
+                               const Standard_Integer&        theDegreeV,
+                               const Standard_Boolean&        thePeriodicV,
+                               const TColStd_Array1OfReal&    theFlatKnotsV,
+                               const TColgp_Array2OfPnt&      thePoles,
+                               const TColStd_Array2OfReal&    theWeights)
+{
+  Standard_Real aU = theFlatKnotsU.Value(theFlatKnotsU.Lower() + theDegreeU);
+  Standard_Real aV = theFlatKnotsV.Value(theFlatKnotsV.Lower() + theDegreeV);
+
+  BuildCache(aU, aV, 
+             theDegreeU, thePeriodicU, theFlatKnotsU, 
+             theDegreeV, thePeriodicV, theFlatKnotsV, 
+             thePoles, theWeights);
+}
+
+
+Standard_Boolean BSplSLib_Cache::IsCacheValid(Standard_Real theParameterU,
+                                              Standard_Real theParameterV) const
+{
+  Standard_Real aNewU = theParameterU;
+  Standard_Real aNewV = theParameterV;
+  if (!myFlatKnots[0].IsNull())
+    PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU);
+  if (!myFlatKnots[1].IsNull())
+    PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV);
+
+  Standard_Real aDelta0 = aNewU - mySpanStart[0];
+  Standard_Real aDelta1 = aNewV - mySpanStart[1];
+  return (aDelta0 >= -mySpanLength[0] && (aDelta0 < mySpanLength[0] || mySpanIndex[0] == mySpanIndexMax[0]) && 
+          aDelta1 >= -mySpanLength[1] && (aDelta1 < mySpanLength[1] || mySpanIndex[1] == mySpanIndexMax[1]));
+}
+
+void BSplSLib_Cache::PeriodicNormalization(const Standard_Integer& theDegree, 
+                                           const TColStd_Array1OfReal& theFlatKnots, 
+                                           Standard_Real& theParameter) const
+{
+  Standard_Real aPeriod = theFlatKnots.Value(theFlatKnots.Upper() - theDegree) - 
+                          theFlatKnots.Value(theDegree + 1) ;
+  if (theParameter < theFlatKnots.Value(theDegree + 1))
+  {
+    Standard_Real aScale = IntegerPart(
+        (theFlatKnots.Value(theDegree + 1) - theParameter) / aPeriod);
+    theParameter += aPeriod * (aScale + 1.0);
+  }
+  if (theParameter > theFlatKnots.Value(theFlatKnots.Upper() - theDegree))
+  {
+    Standard_Real aScale = IntegerPart(
+        (theParameter - theFlatKnots.Value(theFlatKnots.Upper() - theDegree)) / aPeriod);
+    theParameter -= aPeriod * (aScale + 1.0);
+  }
+}
+
+
+void BSplSLib_Cache::BuildCache(const Standard_Real&           theParameterU, 
+                                const Standard_Real&           theParameterV, 
+                                const Standard_Integer&        theDegreeU, 
+                                const Standard_Boolean&        thePeriodicU, 
+                                const TColStd_Array1OfReal&    theFlatKnotsU, 
+                                const Standard_Integer&        theDegreeV, 
+                                const Standard_Boolean&        thePeriodicV, 
+                                const TColStd_Array1OfReal&    theFlatKnotsV, 
+                                const TColgp_Array2OfPnt&      thePoles, 
+                                const TColStd_Array2OfReal&    theWeights)
+{
+  // Normalize the parameters for periodical B-splines
+  Standard_Real aNewParamU = theParameterU;
+  if (thePeriodicU)
+  {
+    PeriodicNormalization(theDegreeU, theFlatKnotsU, aNewParamU);
+    myFlatKnots[0] = new TColStd_HArray1OfReal(1, theFlatKnotsU.Length());
+    myFlatKnots[0]->ChangeArray1() = theFlatKnotsU;
+  }
+  else if (!myFlatKnots[0].IsNull()) // Periodical curve became non-periodical
+    myFlatKnots[0].Nullify();
+
+  Standard_Real aNewParamV = theParameterV;
+  if (thePeriodicV)
+  {
+    PeriodicNormalization(theDegreeV, theFlatKnotsV, aNewParamV);
+    myFlatKnots[1] = new TColStd_HArray1OfReal(1, theFlatKnotsV.Length());
+    myFlatKnots[1]->ChangeArray1() = theFlatKnotsV;
+  }
+  else if (!myFlatKnots[1].IsNull()) // Periodical curve became non-periodical
+    myFlatKnots[1].Nullify();
+
+  Standard_Integer aMinDegree = Min(theDegreeU, theDegreeV);
+  Standard_Integer aMaxDegree = Max(theDegreeU, theDegreeV);
+
+  // Change the size of cached data if needed
+  myIsRational = (&theWeights != NULL);
+  Standard_Integer aPWColNumber = myIsRational ? 4 : 3;
+  if (theDegreeU > myDegree[0] || theDegreeV > myDegree[1])
+    myPolesWeights = new TColStd_HArray2OfReal(1, aMaxDegree + 1, 1, aPWColNumber * (aMinDegree + 1));
+
+  myDegree[0] = theDegreeU;
+  myDegree[1] = theDegreeV;
+  mySpanIndex[0] = mySpanIndex[1] = 0;
+  BSplCLib::LocateParameter(theDegreeU, theFlatKnotsU, BSplCLib::NoMults(), aNewParamU, 
+                            thePeriodicU, mySpanIndex[0], aNewParamU);
+  BSplCLib::LocateParameter(theDegreeV, theFlatKnotsV, BSplCLib::NoMults(), aNewParamV, 
+                            thePeriodicV, mySpanIndex[1], aNewParamV);
+  mySpanLength[0] = (theFlatKnotsU.Value(mySpanIndex[0] + 1) - theFlatKnotsU.Value(mySpanIndex[0])) * 0.5;
+  mySpanStart[0]  = theFlatKnotsU.Value(mySpanIndex[0]) + mySpanLength[0];
+  mySpanLength[1] = (theFlatKnotsV.Value(mySpanIndex[1] + 1) - theFlatKnotsV.Value(mySpanIndex[1])) * 0.5;
+  mySpanStart[1]  = theFlatKnotsV.Value(mySpanIndex[1]) + mySpanLength[1];
+  mySpanIndexMax[0] = theFlatKnotsU.Length() - 1 - theDegreeU;
+  mySpanIndexMax[1] = theFlatKnotsV.Length() - 1 - theDegreeV;
+
+  // Calculate new cache data
+  BSplSLib::BuildCache(mySpanStart[0],  mySpanStart[1], 
+                       mySpanLength[0], mySpanLength[1], 
+                       thePeriodicU,    thePeriodicV, 
+                       theDegreeU,      theDegreeV, 
+                       mySpanIndex[0],  mySpanIndex[1], 
+                       theFlatKnotsU,   theFlatKnotsV, 
+                       thePoles, theWeights, myPolesWeights->ChangeArray2());
+}
+
+
+void BSplSLib_Cache::D0(const Standard_Real& theU, 
+                        const Standard_Real& theV, 
+                              gp_Pnt&        thePoint) const
+{
+  Standard_Real aNewU = theU;
+  Standard_Real aNewV = theV;
+  if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical
+    PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU);
+  aNewU = (aNewU - mySpanStart[0]) / mySpanLength[0];
+  if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical
+    PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV);
+  aNewV = (aNewV - mySpanStart[1]) / mySpanLength[1];
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Real aPoint[4];
+
+  Standard_Integer aDimension = myIsRational ? 4 : 3;
+  Standard_Integer aCacheCols = myPolesWeights->RowLength();
+  Standard_Integer aMinMaxDegree[2] = {Min(myDegree[0], myDegree[1]), 
+                                       Max(myDegree[0], myDegree[1])};
+  Standard_Real aParameters[2];
+  if (myDegree[0] > myDegree[1])
+  {
+    aParameters[0] = aNewV;
+    aParameters[1] = aNewU;
+  }
+  else
+  {
+    aParameters[0] = aNewU;
+    aParameters[1] = aNewV;
+  }
+
+  NCollection_LocalArray<Standard_Real> aTransientCoeffs(aCacheCols); // array for intermediate results
+
+  // Calculate intermediate value of cached polynomial along columns
+  PLib::NoDerivativeEvalPolynomial(aParameters[1], aMinMaxDegree[1],
+                                   aCacheCols, aMinMaxDegree[1] * aCacheCols,
+                                   aPolesArray[0], aTransientCoeffs[0]);
+
+  // Calculate total value
+  PLib::NoDerivativeEvalPolynomial(aParameters[0], aMinMaxDegree[0],
+                                   aDimension, aDimension * aMinMaxDegree[0],
+                                   aTransientCoeffs[0], aPoint[0]);
+
+  thePoint.SetCoord(aPoint[0], aPoint[1], aPoint[2]);
+  if (myIsRational)
+    thePoint.ChangeCoord().Divide(aPoint[3]);
+}
+
+
+void BSplSLib_Cache::D1(const Standard_Real& theU, 
+                        const Standard_Real& theV, 
+                              gp_Pnt&        thePoint, 
+                              gp_Vec&        theTangentU, 
+                              gp_Vec&        theTangentV) const
+{
+  Standard_Real aNewU = theU;
+  Standard_Real aNewV = theV;
+  Standard_Real anInvU = 1.0 / mySpanLength[0];
+  Standard_Real anInvV = 1.0 / mySpanLength[1];
+  if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical
+    PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU);
+  aNewU = (aNewU - mySpanStart[0]) * anInvU;
+  if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical
+    PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV);
+  aNewV = (aNewV - mySpanStart[1]) * anInvV;
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Real aPntDeriv[16]; // result storage (point and derivative coordinates)
+  for (Standard_Integer i = 0; i< 16; i++) aPntDeriv[i] = 0.0;
+
+  Standard_Integer aDimension = myIsRational ? 4 : 3;
+  Standard_Integer aCacheCols = myPolesWeights->RowLength();
+  Standard_Integer aMinMaxDegree[2] = {Min(myDegree[0], myDegree[1]), 
+                                       Max(myDegree[0], myDegree[1])};
+
+  Standard_Real aParameters[2];
+  if (myDegree[0] > myDegree[1])
+  {
+    aParameters[0] = aNewV;
+    aParameters[1] = aNewU;
+  }
+  else
+  {
+    aParameters[0] = aNewU;
+    aParameters[1] = aNewV;
+  }
+
+  NCollection_LocalArray<Standard_Real> aTransientCoeffs(aCacheCols<<1); // array for intermediate results
+
+  // Calculate intermediate values and derivatives of bivariate polynomial along variable with maximal degree
+  PLib::EvalPolynomial(aParameters[1], 1, aMinMaxDegree[1], aCacheCols, aPolesArray[0], aTransientCoeffs[0]);
+
+  // Calculate a point on surface and a derivative along variable with minimal degree
+  PLib::EvalPolynomial(aParameters[0], 1, aMinMaxDegree[0], aDimension, aTransientCoeffs[0], aPntDeriv[0]);
+
+  // Calculate derivative along variable with maximal degree
+  PLib::NoDerivativeEvalPolynomial(aParameters[0], aMinMaxDegree[0], aDimension, 
+                                   aMinMaxDegree[0] * aDimension, aTransientCoeffs[aCacheCols], 
+                                   aPntDeriv[aDimension<<1]);
+
+  Standard_Real* aResult = aPntDeriv;
+  Standard_Real aTempStorage[12];
+  if (myIsRational) // calculate derivatives divided by weight's derivatives
+  {
+    BSplSLib::RationalDerivative(1, 1, 1, 1, aPntDeriv[0], aTempStorage[0]);
+    aResult = aTempStorage;
+    aDimension--;
+  }
+
+  thePoint.SetCoord(aResult[0], aResult[1], aResult[2]);
+  if (myDegree[0] > myDegree[1])
+  {
+    theTangentV.SetCoord(aResult[aDimension], aResult[aDimension + 1], aResult[aDimension + 2]);
+    Standard_Integer aShift = aDimension<<1;
+    theTangentU.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+  }
+  else
+  {
+    theTangentU.SetCoord(aResult[aDimension], aResult[aDimension + 1], aResult[aDimension + 2]);
+    Standard_Integer aShift = aDimension<<1;
+    theTangentV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+  }
+  theTangentU.Multiply(anInvU);
+  theTangentV.Multiply(anInvV);
+}
+
+
+void BSplSLib_Cache::D2(const Standard_Real& theU, 
+                        const Standard_Real& theV, 
+                              gp_Pnt&        thePoint, 
+                              gp_Vec&        theTangentU, 
+                              gp_Vec&        theTangentV, 
+                              gp_Vec&        theCurvatureU, 
+                              gp_Vec&        theCurvatureV, 
+                              gp_Vec&        theCurvatureUV) const
+{
+  Standard_Real aNewU = theU;
+  Standard_Real aNewV = theV;
+  Standard_Real anInvU = 1.0 / mySpanLength[0];
+  Standard_Real anInvV = 1.0 / mySpanLength[1];
+  if (!myFlatKnots[0].IsNull()) // B-spline is U-periodical
+    PeriodicNormalization(myDegree[0], myFlatKnots[0]->Array1(), aNewU);
+  aNewU = (aNewU - mySpanStart[0]) * anInvU;
+  if (!myFlatKnots[1].IsNull()) // B-spline is V-periodical
+    PeriodicNormalization(myDegree[1], myFlatKnots[1]->Array1(), aNewV);
+  aNewV = (aNewV - mySpanStart[1]) * anInvV;
+
+  Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
+  Standard_Real aPntDeriv[36]; // result storage (point and derivative coordinates)
+  for (Standard_Integer i = 0; i < 36; i++) aPntDeriv[i] = 0.0;
+
+  Standard_Integer aDimension = myIsRational ? 4 : 3;
+  Standard_Integer aCacheCols = myPolesWeights->RowLength();
+  Standard_Integer aMinMaxDegree[2] = {Min(myDegree[0], myDegree[1]), 
+                                       Max(myDegree[0], myDegree[1])};
+
+  Standard_Real aParameters[2];
+  if (myDegree[0] > myDegree[1])
+  {
+    aParameters[0] = aNewV;
+    aParameters[1] = aNewU;
+  }
+  else
+  {
+    aParameters[0] = aNewU;
+    aParameters[1] = aNewV;
+  }
+
+  NCollection_LocalArray<Standard_Real> aTransientCoeffs(3 * aCacheCols); // array for intermediate results
+  // Calculating derivative to be evaluate and
+  // nulling transient coefficients when max or min derivative is less than 2
+  Standard_Integer aMinMaxDeriv[2] = {Min(2, aMinMaxDegree[0]), 
+                                      Min(2, aMinMaxDegree[1])};
+  for (Standard_Integer i = aMinMaxDeriv[1] + 1; i < 3; i++)
+  {
+    Standard_Integer index = i * aCacheCols;
+    for (Standard_Integer j = 0; j < aCacheCols; j++) 
+      aTransientCoeffs[index++] = 0.0;
+  }
+
+  // Calculate intermediate values and derivatives of bivariate polynomial along variable with maximal degree
+  PLib::EvalPolynomial(aParameters[1], aMinMaxDeriv[1], aMinMaxDegree[1], 
+                       aCacheCols, aPolesArray[0], aTransientCoeffs[0]);
+
+  // Calculate a point on surface and a derivatives along variable with minimal degree
+  PLib::EvalPolynomial(aParameters[0], aMinMaxDeriv[0], aMinMaxDegree[0], 
+                       aDimension, aTransientCoeffs[0], aPntDeriv[0]);
+
+  // Calculate derivative along variable with maximal degree and mixed derivative
+  PLib::EvalPolynomial(aParameters[0], 1, aMinMaxDegree[0], aDimension, 
+                       aTransientCoeffs[aCacheCols], aPntDeriv[3 * aDimension]);
+
+  // Calculate second derivative along variable with maximal degree
+  PLib::NoDerivativeEvalPolynomial(aParameters[0], aMinMaxDegree[0], aDimension, 
+                                   aMinMaxDegree[0] * aDimension, aTransientCoeffs[aCacheCols<<1], 
+                                   aPntDeriv[6 * aDimension]);
+
+  Standard_Real* aResult = aPntDeriv;
+  Standard_Real aTempStorage[36];
+  if (myIsRational) // calculate derivatives divided by weight's derivatives
+  {
+    BSplSLib::RationalDerivative(2, 2, 2, 2, aPntDeriv[0], aTempStorage[0]);
+    aResult = aTempStorage;
+    aDimension--;
+  }
+
+  thePoint.SetCoord(aResult[0], aResult[1], aResult[2]);
+  if (myDegree[0] > myDegree[1])
+  {
+    theTangentV.SetCoord(aResult[aDimension], aResult[aDimension + 1], aResult[aDimension + 2]);
+    Standard_Integer aShift = aDimension<<1;
+    theCurvatureV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += aDimension;
+    theTangentU.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += aDimension;
+    theCurvatureUV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += (aDimension << 1);
+    theCurvatureU.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+  }
+  else
+  {
+    theTangentU.SetCoord(aResult[aDimension], aResult[aDimension + 1], aResult[aDimension + 2]);
+    Standard_Integer aShift = aDimension<<1;
+    theCurvatureU.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += aDimension;
+    theTangentV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += aDimension;
+    theCurvatureUV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+    aShift += (aDimension << 1);
+    theCurvatureV.SetCoord(aResult[aShift], aResult[aShift + 1], aResult[aShift + 2]);
+  }
+  theTangentU.Multiply(anInvU);
+  theTangentV.Multiply(anInvV);
+  theCurvatureU.Multiply(anInvU * anInvU);
+  theCurvatureV.Multiply(anInvV * anInvV);
+  theCurvatureUV.Multiply(anInvU * anInvV);
+}
+
diff --git a/src/BSplSLib/BSplSLib_Cache.hxx b/src/BSplSLib/BSplSLib_Cache.hxx
new file mode 100644 (file)
index 0000000..8196350
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _BSplSLib_Cache_Headerfile
+#define _BSplSLib_Cache_Headerfile
+
+#include <Standard.hxx>
+#include <Standard_Macro.hxx>
+#include <Standard_DefineHandle.hxx>
+#include <Standard_Transient.hxx>
+
+#include <Handle_TColStd_HArray1OfReal.hxx>
+#include <Handle_TColStd_HArray2OfReal.hxx>
+
+#include <gp_Pnt.hxx>
+#include <gp_Vec.hxx>
+
+class Handle(BSplSLib_Cache);
+class TColgp_Array2OfPnt;
+class TColStd_Array1OfInteger;
+class TColStd_Array1OfReal;
+class TColStd_Array2OfReal;
+
+#ifndef NOWEIGHTS_SURF
+#define NOWEIGHTS_SURF (*((TColStd_Array2OfReal*) NULL))
+#endif
+
+//! \brief A cache class for B-spline surfaces.
+//!
+//! Defines all data, that can be cached on a span of B-spline surface.
+//! The data should be recalculated in going from span to span.
+class BSplSLib_Cache : public Standard_Transient
+{
+public:
+  //! Default constructor
+  Standard_EXPORT BSplSLib_Cache();
+  //! Constructor for caching of the span for B-spline surface
+  //! \param theDegreeU    degree along the first parameter (U) of the B-spline
+  //! \param thePeriodicU  identify the B-spline is periodical along U axis
+  //! \param theFlatKnotsU knots of B-spline curve (with repetition) along U axis
+  //! \param theDegreeV    degree alogn the second parameter (V) of the B-spline
+  //! \param thePeriodicV  identify the B-spline is periodical along V axis
+  //! \param theFlatKnotsV knots of B-spline curve (with repetition) along V axis
+  //! \param thePoles      array of poles of the B-spline surface
+  //! \param theWeights    array of weights of corresponding poles
+  Standard_EXPORT BSplSLib_Cache(const Standard_Integer&        theDegreeU,
+                                 const Standard_Boolean&        thePeriodicU,
+                                 const TColStd_Array1OfReal&    theFlatKnotsU,
+                                 const Standard_Integer&        theDegreeV,
+                                 const Standard_Boolean&        thePeriodicV,
+                                 const TColStd_Array1OfReal&    theFlatKnotsV,
+                                 const TColgp_Array2OfPnt&      thePoles,
+                                 const TColStd_Array2OfReal&    theWeights = NOWEIGHTS_SURF);
+
+  //! Verifies validity of the cache using parameters of the point
+  //! \param theParameterU  first parameter of the point placed in the span
+  //! \param theParameterV  second parameter of the point placed in the span
+  Standard_EXPORT Standard_Boolean IsCacheValid(Standard_Real theParameterU,
+                                                Standard_Real theParameterV) const;
+
+  //! Recomputes the cache data. Does not verify validity of the cache
+  //! \param theParameterU  the parametric value on the U axis to identify the span
+  //! \param theParameterV  the parametric value on the V axis to identify the span
+  //! \param theDegreeU     degree of the B-spline along U axis
+  //! \param thePeriodicU   identify the B-spline is periodic along U axis
+  //! \param theFlatKnotsU  flat knots of B-spline surface along U axis
+  //! \param theDegreeV     degree of the B-spline along V axis
+  //! \param thePeriodicV   identify the B-spline is periodic along V axis
+  //! \param theFlatKnotsV  flat knots of B-spline surface along V axis
+  //! \param thePoles       array of poles of B-spline
+  //! \param theWeights     array of weights of corresponding poles
+  Standard_EXPORT void BuildCache(const Standard_Real&           theParameterU, 
+                                  const Standard_Real&           theParameterV, 
+                                  const Standard_Integer&        theDegreeU, 
+                                  const Standard_Boolean&        thePeriodicU, 
+                                  const TColStd_Array1OfReal&    theFlatKnotsU, 
+                                  const Standard_Integer&        theDegreeV, 
+                                  const Standard_Boolean&        thePeriodicV, 
+                                  const TColStd_Array1OfReal&    theFlatKnotsV, 
+                                  const TColgp_Array2OfPnt&      thePoles, 
+                                  const TColStd_Array2OfReal&    theWeights = NOWEIGHTS_SURF);
+
+  //! Calculates the point on B-spline for specified parameters
+  //! \param[in]  theU      first parameter for calculation of the value
+  //! \param[in]  theV      second parameter for calculation of the value
+  //! \param[out] thePoint  the result of calculation (the point on the B-spline)
+  Standard_EXPORT void D0(const Standard_Real& theU, const Standard_Real& theV, gp_Pnt& thePoint) const;
+
+  //! Calculates the point on B-spline and its first derivative
+  //! \param[in]  theU         first parameter of calculation of the value
+  //! \param[in]  theV         second parameter of calculation of the value
+  //! \param[out] thePoint     the result of calculation (the point on the B-spline)
+  //! \param[out] theTangentU  tangent vector along U axis in the calculated point
+  //! \param[out] theTangentV  tangent vector along V axis in the calculated point
+  Standard_EXPORT void D1(const Standard_Real& theU, 
+                          const Standard_Real& theV, 
+                                gp_Pnt&        thePoint, 
+                                gp_Vec&        theTangentU, 
+                                gp_Vec&        theTangentV) const;
+
+  //! Calculates the point on B-spline and derivatives till second order
+  //! \param[in]  theU            first parameter of calculation of the value
+  //! \param[in]  theV            second parameter of calculation of the value
+  //! \param[out] thePoint        the result of calculation (the point on B-spline)
+  //! \param[out] theTangentU     tangent vector along U axis in the calculated point
+  //! \param[out] theTangentV     tangent vector along V axis in the calculated point
+  //! \param[out] theCurvatureU   curvature vector (2nd derivative on U) along U axis
+  //! \param[out] theCurvatureV   curvature vector (2nd derivative on V) along V axis
+  //! \param[out] theCurvatureUV  2nd mixed derivative on U anv V
+  Standard_EXPORT void D2(const Standard_Real& theU, 
+                          const Standard_Real& theV, 
+                                gp_Pnt&        thePoint, 
+                                gp_Vec&        theTangentU, 
+                                gp_Vec&        theTangentV, 
+                                gp_Vec&        theCurvatureU, 
+                                gp_Vec&        theCurvatureV, 
+                                gp_Vec&        theCurvatureUV) const;
+
+
+  DEFINE_STANDARD_RTTI(BSplSLib_Cache)
+
+protected:
+  //! Normalizes the parameter for periodical B-splines
+  //! \param[in]     theDegree     degree of B-spline along selected direction
+  //! \param[in]     theFlatKnots  knots with repetitions along selected direction
+  //! \param[in,out] theParameter  the value to be normalized into the knots array
+  void PeriodicNormalization(const Standard_Integer& theDegree, 
+                             const TColStd_Array1OfReal& theFlatKnots, 
+                                   Standard_Real& theParameter) const;
+
+private:
+  Handle(TColStd_HArray2OfReal) myPolesWeights; ///< array of poles and weights of calculated cache
+                                                // the array has following structure:
+                                                //       x11 y11 z11 [w11] x12 y12 z12 [w12] ...
+                                                //       x21 y21 z21 [w21] x22 y22 z22 [w22] etc
+                                                // for non-rational surfaces there is no weight;
+                                                // size of array: (max(myDegree)+1) * A*(min(myDegree)+1), where A = 4 or 3
+
+  Standard_Boolean              myIsRational;    ///< identifies the rationality of B-spline
+  Standard_Real                 mySpanStart[2];  ///< parameters (u, v) for the frst point of the span
+  Standard_Real                 mySpanLength[2]; ///< lengths of the span along corresponding parameter
+  Standard_Integer              mySpanIndex[2];  ///< indexes of the span on B-spline surface
+  Standard_Integer              mySpanIndexMax[2]; ///< maximal indexes of span
+  Standard_Integer              myDegree[2];     ///< degrees of B-spline for each parameter
+  Handle(TColStd_HArray1OfReal) myFlatKnots[2];  ///< arrays of knots of B-spline 
+                                                 // (used for periodic normalization of parameters, Null for non-periodical splines)
+};
+
+DEFINE_STANDARD_HANDLE(BSplSLib_Cache, Standard_Transient)
+
+#endif
index 05cf83c..8781c3d 100755 (executable)
@@ -1,3 +1,4 @@
 BSplSLib_BzSyntaxes.cxx
 BSplSLib_EvaluatorFunction.hxx
-
+BSplSLib_Cache.hxx
+BSplSLib_Cache.cxx
index 77c3506..f2f3414 100644 (file)
@@ -165,7 +165,13 @@ gp_Dir&              Normal
 //     if (D1UMag <= MagTol || D1VMag <= MagTol && NMag > MagTol) MagTol = 2* NMag;
 }
   else
-     { Normal = gp_Dir (D1UvD1V);   Status = Defined; }
+  {
+    // Firstly normalize tangent vectors D1U and D1V (this method is more stable)
+    gp_Dir aD1U(D1U);
+    gp_Dir aD1V(D1V);
+    Normal = gp_Dir(aD1U.Crossed(aD1V));
+    Status = Defined;
+  }
   
 
 }
diff --git a/src/CSLib/CSLib_Offset.cxx b/src/CSLib/CSLib_Offset.cxx
new file mode 100644 (file)
index 0000000..7dc9729
--- /dev/null
@@ -0,0 +1,470 @@
+// Copyright (c) 2015-... OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <CSLib_Offset.hxx>
+
+#include <gp_Dir2d.hxx>
+#include <gp_XY.hxx>
+
+#include <Geom_UndefinedValue.hxx>
+#include <Geom_UndefinedDerivative.hxx>
+#include <Geom2d_UndefinedValue.hxx>
+#include <Geom2d_UndefinedDerivative.hxx>
+
+#include <Standard_NullValue.hxx>
+
+
+// ==========  Offset values for 2D curves  ==========
+
+void CSLib_Offset::D0(const gp_Pnt2d&  theBasePoint,
+                      const gp_Vec2d&  theBaseDeriv,
+                      Standard_Real    theOffset,
+                      Standard_Boolean , // unused
+                      gp_Pnt2d&        theResPoint)
+{
+  if (theBaseDeriv.SquareMagnitude() <= gp::Resolution())
+    Standard_NullValue::Raise("CSLib_Offset: Undefined normal vector "
+                              "because tangent vector has zero-magnitude!");
+
+  gp_Dir2d aNormal(theBaseDeriv.Y(), -theBaseDeriv.X());
+  theResPoint.SetCoord(theBasePoint.X() + aNormal.X() * theOffset,
+                       theBasePoint.Y() + aNormal.Y() * theOffset);
+}
+
+void CSLib_Offset::D1(const gp_Pnt2d& theBasePoint,
+                      const gp_Vec2d& theBaseD1,
+                      const gp_Vec2d& theBaseD2,
+                      Standard_Real   theOffset,
+                      Standard_Boolean , // unused
+                      gp_Pnt2d&       theResPoint,
+                      gp_Vec2d&       theResDeriv)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+  // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  gp_XY Ndir(theBaseD1.Y(), -theBaseD1.X());
+  gp_XY DNdir(theBaseD2.Y(), -theBaseD2.X());
+  Standard_Real R2 = Ndir.SquareModulus();
+  Standard_Real R  = Sqrt (R2);
+  Standard_Real R3 = R * R2;
+  Standard_Real Dr = Ndir.Dot(DNdir);
+  if (R3 <= gp::Resolution())
+  {
+    if (R2 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    //We try another computation but the stability is not very good.
+    DNdir.Multiply(R);
+    DNdir.Subtract(Ndir.Multiplied(Dr / R));
+    DNdir.Multiply(theOffset / R2);
+  }
+  else
+  {
+    // Same computation as IICURV in EUCLID-IS because the stability is better
+    DNdir.Multiply(theOffset / R);
+    DNdir.Subtract(Ndir.Multiplied(theOffset * Dr / R3));
+  }
+
+  // P(u)
+  D0(theBasePoint, theBaseD1, theOffset, Standard_False, theResPoint);
+  // P'(u)
+  theResDeriv = theBaseD1.Added(gp_Vec2d(DNdir));
+}
+
+void CSLib_Offset::D2(const gp_Pnt2d&  theBasePoint,
+                      const gp_Vec2d&  theBaseD1,
+                      const gp_Vec2d&  theBaseD2,
+                      const gp_Vec2d&  theBaseD3,
+                      Standard_Real    theOffset,
+                      Standard_Boolean theIsDirectionChange,
+                      gp_Pnt2d&        theResPoint,
+                      gp_Vec2d&        theResD1,
+                      gp_Vec2d&        theResD2)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+  // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+  //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+  gp_XY Ndir(theBaseD1.Y(), -theBaseD1.X());
+  gp_XY DNdir(theBaseD2.Y(), -theBaseD2.X());
+  gp_XY D2Ndir(theBaseD3.Y(), -theBaseD3.X());
+  Standard_Real R2  = Ndir.SquareModulus();
+  Standard_Real R   = Sqrt(R2);
+  Standard_Real R3  = R2 * R;
+  Standard_Real R4  = R2 * R2;
+  Standard_Real R5  = R3 * R2;
+  Standard_Real Dr  = Ndir.Dot(DNdir);
+  Standard_Real D2r = Ndir.Dot(D2Ndir) + DNdir.Dot (DNdir);
+  if (R5 <= gp::Resolution())
+  {
+    if (R4 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    //We try another computation but the stability is not very good dixit ISG.
+    // V2 = P" (U) :
+    D2Ndir.Subtract(DNdir.Multiplied (2.0 * Dr / R2));
+    D2Ndir.Add(Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
+    D2Ndir.Multiply(theOffset / R);
+
+    // V1 = P' (U) :
+    DNdir.Multiply(R);
+    DNdir.Subtract(Ndir.Multiplied(Dr / R));
+    DNdir.Multiply(theOffset / R2);
+  }
+  else
+  {
+    // Same computation as IICURV in EUCLID-IS because the stability is better.
+    // V2 = P" (U) :
+    D2Ndir.Multiply(theOffset / R);
+    D2Ndir.Subtract(DNdir.Multiplied (2.0 * theOffset * Dr / R3));
+    D2Ndir.Add (Ndir.Multiplied(theOffset * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
+
+    // V1 = P' (U) 
+    DNdir.Multiply(theOffset / R);
+    DNdir.Subtract(Ndir.Multiplied(theOffset * Dr / R3));
+  }
+
+  // P(u) :
+  D0(theBasePoint, theBaseD1, theOffset, theIsDirectionChange, theResPoint);
+  // P'(u) :
+  theResD1 = theBaseD1.Added(gp_Vec2d(DNdir));
+  // P"(u) :
+  if (theIsDirectionChange)
+    theResD2 = -theBaseD2;
+  else
+    theResD2 = theBaseD2;
+  theResD2.Add(gp_Vec2d(D2Ndir));
+}
+
+void CSLib_Offset::D3(const gp_Pnt2d&  theBasePoint,
+                      const gp_Vec2d&  theBaseD1,
+                      const gp_Vec2d&  theBaseD2,
+                      const gp_Vec2d&  theBaseD3,
+                      const gp_Vec2d&  theBaseD4,
+                      Standard_Real    theOffset,
+                      Standard_Boolean theIsDirectionChange,
+                      gp_Pnt2d&        theResPoint,
+                      gp_Vec2d&        theResD1,
+                      gp_Vec2d&        theResD2,
+                      gp_Vec2d&        theResD3)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+  // P'(u)  = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  // P"(u)  = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+  //          Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+  // P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
+  //          (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
+  //          (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
+  //          (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
+
+  gp_XY Ndir(theBaseD1.Y(), -theBaseD1.X());
+  gp_XY DNdir(theBaseD2.Y(), -theBaseD2.X());
+  gp_XY D2Ndir(theBaseD3.Y(), -theBaseD3.X());
+  gp_XY D3Ndir(theBaseD4.Y(), -theBaseD4.X());
+  Standard_Real R2  = Ndir.SquareModulus();
+  Standard_Real R   = Sqrt (R2);
+  Standard_Real R3  = R2 * R;
+  Standard_Real R4  = R2 * R2;
+  Standard_Real R5  = R3 * R2;
+  Standard_Real R6  = R3 * R3;
+  Standard_Real R7  = R5 * R2;
+  Standard_Real Dr  = Ndir.Dot(DNdir);
+  Standard_Real D2r = Ndir.Dot(D2Ndir) + DNdir.Dot (DNdir);
+  Standard_Real D3r = Ndir.Dot(D3Ndir) + 3.0 * DNdir.Dot (D2Ndir);
+
+  if (R7 <= gp::Resolution()) 
+  {
+    if (R6 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    //We try another computation but the stability is not very good dixit ISG.
+    // V3 = P"' (U) :
+    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * theOffset * Dr / R2));
+    D3Ndir.Subtract (
+      (DNdir.Multiplied ((3.0 * theOffset) * ((D2r/R2) + (Dr*Dr)/R4))));
+    D3Ndir.Add (Ndir.Multiplied (
+      (theOffset * (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 - 15.0*Dr*Dr*Dr/R6 - D3r))));
+    D3Ndir.Multiply (theOffset/R);
+    // V2 = P" (U) :
+    Standard_Real R4 = R2 * R2;
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
+    D2Ndir.Subtract (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
+    D2Ndir.Multiply (theOffset / R);
+    // V1 = P' (U) :
+    DNdir.Multiply(R);
+    DNdir.Subtract (Ndir.Multiplied (Dr/R));
+    DNdir.Multiply (theOffset/R2);
+  }
+  else
+  {
+    // Same computation as IICURV in EUCLID-IS because the stability is better.
+    // V3 = P"' (U) :
+    D3Ndir.Multiply (theOffset/R);
+    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * theOffset * Dr / R3));
+    D3Ndir.Subtract (DNdir.Multiplied (
+      ((3.0 * theOffset) * ((D2r/R3) + (Dr*Dr)/R5))) );
+    D3Ndir.Add (Ndir.Multiplied (
+      (theOffset * (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - 15.0*Dr*Dr*Dr/R7 - D3r))));
+    // V2 = P" (U) :
+    D2Ndir.Multiply (theOffset/R);
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * theOffset * Dr / R3));
+    D2Ndir.Subtract (Ndir.Multiplied (
+      theOffset * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
+    // V1 = P' (U) :
+    DNdir.Multiply (theOffset/R);
+    DNdir.Subtract (Ndir.Multiplied (theOffset*Dr/R3));
+  }
+
+  // P(u)
+  D0(theBasePoint, theBaseD1, theOffset, theIsDirectionChange, theResPoint);
+  // P'(u)
+  theResD1 = theBaseD1.Added(gp_Vec2d(DNdir));
+  // P"(u)
+  theResD2 = theBaseD2.Added(gp_Vec2d(D2Ndir));
+  // P"'(u)
+  if (theIsDirectionChange)
+    theResD3 = -theBaseD3;
+  else
+    theResD3 = theBaseD3;
+  theResD3.Add(gp_Vec2d(D2Ndir));
+}
+
+
+// ==========  Offset values for 3D curves  ==========
+
+void CSLib_Offset::D0(const gp_Pnt&    theBasePoint,
+                      const gp_Vec&    theBaseDeriv,
+                      const gp_Dir&    theOffsetDirection,
+                      Standard_Real    theOffsetValue,
+                      Standard_Boolean , // unused
+                      gp_Pnt&          theResPoint)
+{
+  gp_XYZ Ndir = (theBaseDeriv.XYZ()).Crossed(theOffsetDirection.XYZ());
+  Standard_Real R = Ndir.Modulus();
+  if (R <= gp::Resolution())
+    Standard_NullValue::Raise("CSLib_Offset: Undefined normal vector "
+          "because tangent vector has zero-magnitude!");
+
+  Ndir.Multiply(theOffsetValue / R);
+  Ndir.Add(theBasePoint.XYZ());
+  theResPoint.SetXYZ(Ndir);
+}
+
+void CSLib_Offset::D1(const gp_Pnt&   theBasePoint,
+                      const gp_Vec&   theBaseD1,
+                      const gp_Vec&   theBaseD2,
+                      const gp_Dir&   theOffsetDirection,
+                      Standard_Real   theOffsetValue,
+                      Standard_Boolean , // unused
+                      gp_Pnt&         theResPoint,
+                      gp_Vec&         theResDeriv)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
+
+  // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  gp_XYZ Ndir  = (theBaseD1.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ DNdir = (theBaseD2.XYZ()).Crossed(theOffsetDirection.XYZ());
+  Standard_Real R2 = Ndir.SquareModulus();
+  Standard_Real R  = Sqrt (R2);
+  Standard_Real R3 = R * R2;
+  Standard_Real Dr = Ndir.Dot (DNdir);
+  if (R3 <= gp::Resolution()) {
+    if (R2 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    //We try another computation but the stability is not very good.
+    DNdir.Multiply(R);
+    DNdir.Subtract(Ndir.Multiplied(Dr / R));
+    DNdir.Multiply(theOffsetValue / R2);
+  }
+  else {
+    // Same computation as IICURV in EUCLID-IS because the stability is
+    // better
+    DNdir.Multiply(theOffsetValue / R);
+    DNdir.Subtract(Ndir.Multiplied(theOffsetValue * Dr / R3));
+  }
+
+  // P(u)
+  D0(theBasePoint, theBaseD1, theOffsetDirection, theOffsetValue, Standard_False, theResPoint);
+  // P'(u)
+  theResDeriv = theBaseD1.Added(gp_Vec(DNdir));
+}
+
+void CSLib_Offset::D2(const gp_Pnt&    theBasePoint,
+                      const gp_Vec&    theBaseD1,
+                      const gp_Vec&    theBaseD2,
+                      const gp_Vec&    theBaseD3,
+                      const gp_Dir&    theOffsetDirection,
+                      Standard_Real    theOffsetValue,
+                      Standard_Boolean theIsDirectionChange,
+                      gp_Pnt&          theResPoint,
+                      gp_Vec&          theResD1,
+                      gp_Vec&          theResD2)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
+
+  // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+  //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+  gp_XYZ Ndir   = (theBaseD1.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ DNdir  = (theBaseD2.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ D2Ndir = (theBaseD3.XYZ()).Crossed(theOffsetDirection.XYZ());
+  Standard_Real R2  = Ndir.SquareModulus();
+  Standard_Real R   = Sqrt (R2);
+  Standard_Real R3  = R2 * R;
+  Standard_Real R4  = R2 * R2;
+  Standard_Real R5  = R3 * R2;
+  Standard_Real Dr  = Ndir.Dot (DNdir);
+  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
+  
+  if (R5 <= gp::Resolution()) {
+    if (R4 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    //We try another computation but the stability is not very good
+    //dixit ISG.
+    // V2 = P" (U) :
+    Standard_Real R4 = R2 * R2;
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
+    D2Ndir.Add (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
+    D2Ndir.Multiply (theOffsetValue / R);
+
+    // V1 = P' (U) :
+    DNdir.Multiply(R);
+    DNdir.Subtract (Ndir.Multiplied (Dr/R));
+    DNdir.Multiply (theOffsetValue/R2);
+  }
+  else {
+    // Same computation as IICURV in EUCLID-IS because the stability is
+    // better.
+    // V2 = P" (U) :
+    D2Ndir.Multiply (theOffsetValue/R);
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * theOffsetValue * Dr / R3));
+    D2Ndir.Add (Ndir.Multiplied (theOffsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
+
+    // V1 = P' (U) :
+    DNdir.Multiply (theOffsetValue/R);
+    DNdir.Subtract (Ndir.Multiplied (theOffsetValue*Dr/R3));        
+  }
+
+  // P(u) :
+  D0(theBasePoint, theBaseD1, theOffsetDirection, theOffsetValue, theIsDirectionChange, theResPoint);
+  // P'(u) :
+  theResD1 = theBaseD1.Added(gp_Vec(DNdir));
+  // P"(u) :
+  if (theIsDirectionChange)
+    theResD2 = -theBaseD2;
+  else
+    theResD2 = theBaseD2;
+  theResD2.Add(gp_Vec(D2Ndir));
+}
+
+void CSLib_Offset::D3(const gp_Pnt&    theBasePoint,
+                      const gp_Vec&    theBaseD1,
+                      const gp_Vec&    theBaseD2,
+                      const gp_Vec&    theBaseD3,
+                      const gp_Vec&    theBaseD4,
+                      const gp_Dir&    theOffsetDirection,
+                      Standard_Real    theOffsetValue,
+                      Standard_Boolean theIsDirectionChange,
+                      gp_Pnt&          theResPoint,
+                      gp_Vec&          theResD1,
+                      gp_Vec&          theResD2,
+                      gp_Vec&          theResD3)
+{
+  // P(u) = p(u) + Offset * Ndir / R
+  // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
+
+  // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+  //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+  //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2) * D2Ndir -
+  //         (3.0 * D2r / R2) * DNdir + (3.0 * Dr * Dr / R4) * DNdir -
+  //         (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
+  //         (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
+
+  gp_XYZ Ndir   = (theBaseD1.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ DNdir  = (theBaseD2.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ D2Ndir = (theBaseD3.XYZ()).Crossed(theOffsetDirection.XYZ());
+  gp_XYZ D3Ndir = (theBaseD4.XYZ()).Crossed(theOffsetDirection.XYZ());
+  Standard_Real R2  = Ndir.SquareModulus();
+  Standard_Real R   = Sqrt (R2);
+  Standard_Real R3  = R2 * R;
+  Standard_Real R4  = R2 * R2;
+  Standard_Real R5  = R3 * R2;
+  Standard_Real R6  = R3 * R3;
+  Standard_Real R7  = R5 * R2;
+  Standard_Real Dr  = Ndir.Dot (DNdir);
+  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
+  Standard_Real D3r = Ndir.Dot (D3Ndir) + 3.0 * DNdir.Dot (D2Ndir);
+  if (R7 <= gp::Resolution()) {
+    if (R6 <= gp::Resolution())
+      Standard_NullValue::Raise("CSLib_Offset: Null derivative");
+    // V3 = P"' (U) :
+    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R2));
+    D3Ndir.Subtract (DNdir.Multiplied (3.0 * ((D2r/R2) + (Dr*Dr/R4))));
+    D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 - 15.0*Dr*Dr*Dr/R6 - D3r));
+    D3Ndir.Multiply (theOffsetValue/R);
+    // V2 = P" (U) :
+    Standard_Real R4 = R2 * R2;
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
+    D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R4) - (D2r / R2)));
+    D2Ndir.Multiply (theOffsetValue / R);
+    // V1 = P' (U) :
+    DNdir.Multiply(R);
+    DNdir.Subtract (Ndir.Multiplied (Dr/R));
+    DNdir.Multiply (theOffsetValue/R2);
+  }
+  else {
+    // V3 = P"' (U) :
+    D3Ndir.Divide (R);
+    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R3));
+    D3Ndir.Subtract (DNdir.Multiplied ((3.0 * ((D2r/R3) + (Dr*Dr)/R5))));
+    D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - 15.0*Dr*Dr*Dr/R7 - D3r));
+    D3Ndir.Multiply (theOffsetValue);
+    // V2 = P" (U) :
+    D2Ndir.Divide (R);
+    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R3));
+    D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R5) - (D2r / R3)));
+    D2Ndir.Multiply (theOffsetValue);
+    // V1 = P' (U) :
+    DNdir.Multiply (theOffsetValue/R);
+    DNdir.Subtract (Ndir.Multiplied (theOffsetValue*Dr/R3));
+  }
+
+  // P(u)
+  D0(theBasePoint, theBaseD1, theOffsetDirection, theOffsetValue, theIsDirectionChange, theResPoint);
+  // P'(u)
+  theResD1 = theBaseD1.Added(gp_Vec(DNdir));
+  // P"(u)
+  theResD2 = theBaseD2.Added(gp_Vec(D2Ndir));
+  // P"'(u)
+  if (theIsDirectionChange)
+    theResD3 = -theBaseD3;
+  else
+    theResD3 = theBaseD3;
+  theResD3.Add(gp_Vec(D2Ndir));
+}
+
diff --git a/src/CSLib/CSLib_Offset.hxx b/src/CSLib/CSLib_Offset.hxx
new file mode 100644 (file)
index 0000000..277dfdc
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright (c) 2015-... OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _CSLib_Offset_Headerfile
+#define _CSLib_Offset_Headerfile
+
+#include <gp_Dir.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Pnt2d.hxx>
+#include <gp_Vec.hxx>
+#include <gp_Vec2d.hxx>
+#include <Standard.hxx>
+
+/** \namespace CSLib_Offset
+ *  \brief Provides a number of static methods to calculate values and derivatives
+ *         of an offset curves and surfaces using values and derivatives of
+ *         a base curve/surface.
+ */
+namespace CSLib_Offset
+{
+  /** \brief Calculate value of offset curve in 2D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseDeriv         derivative on a base curve
+   *  \param[in]  theOffset            size of offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative (not used)
+   *  \param[out] theResPoint          point on offset curve
+   */
+  Standard_EXPORT void D0(const gp_Pnt2d&  theBasePoint,
+                          const gp_Vec2d&  theBaseDeriv,
+                          Standard_Real    theOffset,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt2d&        theResPoint);
+  /** \brief Calculate value of offset curve in 3D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseDeriv         derivative on a base curve
+   *  \param[in]  theOffsetDirection   direction of the offset
+   *  \param[in]  theOffsetValue       length of the offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative (not used)
+   *  \param[out] theResPoint          point on offset curve
+   */
+  Standard_EXPORT void D0(const gp_Pnt&    theBasePoint,
+                          const gp_Vec&    theBaseDeriv,
+                          const gp_Dir&    theOffsetDirection,
+                          Standard_Real    theOffsetValue,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt&          theResPoint);
+
+
+  /** \brief Calculate value and the first derivative of offset curve in 2D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseD1            first derivative on a base curve
+   *  \param[in]  theBaseD2            second derivative on a base curve
+   *  \param[in]  theOffset            size of offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative (not used)
+   *  \param[out] theResPoint          point on offset curve
+   *  \param[out] theResDeriv          derivative on offset curve
+   */
+  Standard_EXPORT void D1(const gp_Pnt2d&  theBasePoint,
+                          const gp_Vec2d&  theBaseD1,
+                          const gp_Vec2d&  theBaseD2,
+                          Standard_Real    theOffset,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt2d&        theResPoint,
+                          gp_Vec2d&        theResDeriv);
+  /** \brief Calculate value and the first derivative of offset curve in 3D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseD1            first derivative on a base curve
+   *  \param[in]  theBaseD2            second derivative on a base curve
+   *  \param[in]  theOffsetDirection   direction of the offset
+   *  \param[in]  theOffsetValue       length of the offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative (not used)
+   *  \param[out] theResPoint          point on offset curve
+   *  \param[out] theResDeriv          derivative on offset curve
+   */
+  Standard_EXPORT void D1(const gp_Pnt&    theBasePoint,
+                          const gp_Vec&    theBaseD1,
+                          const gp_Vec&    theBaseD2,
+                          const gp_Dir&    theOffsetDirection,
+                          Standard_Real    theOffsetValue,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt&          theResPoint,
+                          gp_Vec&          theResDeriv);
+
+
+  /** \brief Calculate value and two derivatives of offset curve in 2D
+   *  \param[in]  theBasePoint  point on a base curve
+   *  \param[in]  theBaseD1     first derivative on a base curve
+   *  \param[in]  theBaseD2     second derivative on a base curve
+   *  \param[in]  theBaseD3     third derivative on a base curve
+   *  \param[in]  theOffset     size of offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative
+   *  \param[out] theResPoint   point on offset curve
+   *  \param[out] theResD1      first derivative on offset curve
+   *  \param[out] theResD2      second derivative on offset curve
+   */
+  Standard_EXPORT void D2(const gp_Pnt2d&  theBasePoint,
+                          const gp_Vec2d&  theBaseD1,
+                          const gp_Vec2d&  theBaseD2,
+                          const gp_Vec2d&  theBaseD3,
+                          Standard_Real    theOffset,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt2d&        theResPoint,
+                          gp_Vec2d&        theResD1,
+                          gp_Vec2d&        theResD2);
+  /** \brief Calculate value and two derivatives of offset curve in 3D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseD1            first derivative on a base curve
+   *  \param[in]  theBaseD2            second derivative on a base curve
+   *  \param[in]  theBaseD3            third derivative on a base curve
+   *  \param[in]  theOffsetDirection   direction of the offset
+   *  \param[in]  theOffsetValue       length of the offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative
+   *  \param[out] theResPoint          point on offset curve
+   *  \param[out] theResD1             first derivative on offset curve
+   *  \param[out] theResD2             second derivative on offset curve
+   */
+  Standard_EXPORT void D2(const gp_Pnt&    theBasePoint,
+                          const gp_Vec&    theBaseD1,
+                          const gp_Vec&    theBaseD2,
+                          const gp_Vec&    theBaseD3,
+                          const gp_Dir&    theOffsetDirection,
+                          Standard_Real    theOffsetValue,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt&          theResPoint,
+                          gp_Vec&          theResD1,
+                          gp_Vec&          theResD2);
+
+  /** \brief Calculate value and three derivatives of offset curve in 2D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseD1            first derivative on a base curve
+   *  \param[in]  theBaseD2            second derivative on a base curve
+   *  \param[in]  theBaseD3            third derivative on a base curve
+   *  \param[in]  theBaseD4            fourth derivative on a base curve
+   *  \param[in]  theOffset            size of offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative
+   *  \param[out] theResPoint          point on offset curve
+   *  \param[out] theResD1             first derivative on offset curve
+   *  \param[out] theResD2             second derivative on offset curve
+   *  \param[out] theResD3             third derivative on offset curve
+   */
+  Standard_EXPORT void D3(const gp_Pnt2d&  theBasePoint,
+                          const gp_Vec2d&  theBaseD1,
+                          const gp_Vec2d&  theBaseD2,
+                          const gp_Vec2d&  theBaseD3,
+                          const gp_Vec2d&  theBaseD4,
+                          Standard_Real    theOffset,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt2d&        theResPoint,
+                          gp_Vec2d&        theResD1,
+                          gp_Vec2d&        theResD2,
+                          gp_Vec2d&        theResD3);
+  /** \brief Calculate value and three derivatives of offset curve in 3D
+   *  \param[in]  theBasePoint         point on a base curve
+   *  \param[in]  theBaseD1            first derivative on a base curve
+   *  \param[in]  theBaseD2            second derivative on a base curve
+   *  \param[in]  theBaseD3            third derivative on a base curve
+   *  \param[in]  theBaseD4            fourth derivative on a base curve
+   *  \param[in]  theOffsetDirection   direction of the offset
+   *  \param[in]  theOffsetValue       length of the offset
+   *  \param[in]  theIsDirectionChange shows that it is necessary to consider the direction of derivative
+   *  \param[out] theResPoint          point on offset curve
+   *  \param[out] theResD1             first derivative on offset curve
+   *  \param[out] theResD2             second derivative on offset curve
+   *  \param[out] theResD3             third derivative on offset curve
+   */
+  Standard_EXPORT void D3(const gp_Pnt&    theBasePoint,
+                          const gp_Vec&    theBaseD1,
+                          const gp_Vec&    theBaseD2,
+                          const gp_Vec&    theBaseD3,
+                          const gp_Vec&    theBaseD4,
+                          const gp_Dir&    theOffsetDirection,
+                          Standard_Real    theOffsetValue,
+                          Standard_Boolean theIsDirectionChange,
+                          gp_Pnt&          theResPoint,
+                          gp_Vec&          theResD1,
+                          gp_Vec&          theResD2,
+                          gp_Vec&          theResD3);
+}
+
+#endif // _CSLib_Offset_Headerfile
diff --git a/src/CSLib/FILES b/src/CSLib/FILES
new file mode 100644 (file)
index 0000000..c416510
--- /dev/null
@@ -0,0 +1,2 @@
+CSLib_Offset.hxx
+CSLib_Offset.cxx
index 5828922..5a0d0bf 100644 (file)
@@ -146,6 +146,34 @@ void Extrema_GExtPC::Perform(const ThePoint& P)
         IntExtIsDone = IntExtIsDone || mydone;
       }
       mydone = IntExtIsDone;
+
+      // Additional checking if the point is on the first or last point of the curve and does not added yet
+      if (mydist1 < Precision::SquareConfusion() || mydist2 < Precision::SquareConfusion())
+      {
+        Standard_Boolean isFirstAdded = Standard_False;
+        Standard_Boolean isLastAdded  = Standard_False;
+        Standard_Integer aNbPoints = mypoint.Length();
+        for (i = 1; i <= aNbPoints; i++)
+        {
+          U = mypoint.Value(i).Parameter();
+          if (Abs(U - myuinf) < mytolu)
+            isFirstAdded = Standard_True;
+          else if (Abs(myusup - U) < mytolu)
+            isLastAdded = Standard_True;
+        }
+        if (!isFirstAdded && mydist1 < Precision::SquareConfusion())
+        {
+          mySqDist.Prepend(mydist1);
+          myismin.Prepend(Standard_True);
+          mypoint.Prepend(ThePOnC(myuinf, Pf));
+        }
+        if (!isLastAdded && mydist2 < Precision::SquareConfusion())
+        {
+          mySqDist.Append(mydist2);
+          myismin.Append(Standard_True);
+          mypoint.Append(ThePOnC(myusup, Pl));
+        }
+      }
       return;
     }
   }
index 40ba005..e428bf8 100644 (file)
@@ -120,8 +120,7 @@ uses  Array1OfInteger      from TColStd,
       Vec                  from gp,
       BSplKnotDistribution from GeomAbs,
       Geometry             from Geom,
-      Shape                from GeomAbs,
-      Mutex                from Standard
+      Shape                from GeomAbs
 
 
 raises ConstructionError   from Standard,
@@ -590,17 +589,6 @@ is
         ---Purpose :
         --  Returns True if the weights are not identical.
         --  The tolerance criterion is Epsilon of the class Real.
-    
-  IsCacheValid(me;  Parameter : Real) returns Boolean
-  
-        ---Purpose :
-        --           Tells whether the Cache is valid for the
-        --           given parameter 
-        -- Warnings : the parameter must be normalized within
-        -- the period if the curve is periodic. Otherwise
-        -- the answer will be false
-        -- 
-        is static private;
   
   Continuity (me)  returns Shape from GeomAbs;
         ---Purpose :
@@ -789,6 +777,15 @@ is
      raises DimensionError;
         ---Purpose :
         --  Raised if the length of K is not equal to the number of knots.
+  Knots (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : returns the knot values of the B-spline curve; 
+       -- Warning
+       -- A knot with a multiplicity greater than 1 is not
+       -- repeated in the knot table. The Multiplicity function
+       -- can be used to obtain the multiplicity of each knot.
+        ---C++ : return const &
+  is static;
 
 
   KnotSequence (me; K : out Array1OfReal from TColStd)
@@ -845,6 +842,12 @@ is
        -- Standard_DimensionError if the array K is not of
        -- the appropriate length.Returns the knots sequence.
              raises DimensionError;
+  KnotSequence (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : returns the knots of the B-spline curve. 
+       -- Knots with multiplicit greater than 1 are repeated
+        ---C++ : return const &
+  is static;
        
 
 
@@ -910,6 +913,11 @@ is
      raises DimensionError;
         ---Purpose :
         --  Raised if the length of M is not equal to NbKnots.
+  Multiplicities (me)
+  returns Array1OfInteger from TColStd
+        ---Purpose : returns the multiplicity of the knots of the curve.
+        ---C++ : return const &
+  is static;
 
 
   NbKnots (me)  returns Integer;
@@ -933,6 +941,11 @@ is
      raises DimensionError;
         ---Purpose : 
         --  Raised if the length of P is not equal to the number of poles.
+  Poles (me)
+  returns Array1OfPnt from TColgp
+        ---Purpose : Returns the poles of the B-spline curve;
+        ---C++ : return const &
+  is static;
 
 
   StartPoint (me)  returns Pnt;
@@ -954,6 +967,11 @@ is
      raises DimensionError;
         ---Purpose :
         --  Raised if the length of W is not equal to NbPoles.
+  Weights (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : Returns the weights of the B-spline curve;
+        ---C++ : return const &
+  is static;
 
 
 
@@ -981,20 +999,10 @@ is
 
   Copy (me)  returns like me;
        ---Purpose: Creates a new object which is a copy of this BSpline curve.
-    
-  InvalidateCache(me : mutable)
-       ---Purpose : Invalidates the cache. This has to be private
-       -- this has to be private
-      is static private;
 
   UpdateKnots(me : mutable)
         ---Purpose : Recompute  the  flatknots,  the knotsdistribution, the continuity.
     is static private;
-  
-  ValidateCache(me : mutable ; Parameter : Real) 
-  
-    is static private;
-       ---Purpose : updates the cache and validates it
 
   IsEqual(me; theOther : BSplineCurve from Geom; 
   thePreci : Real from Standard  ) returns Boolean;
@@ -1015,34 +1023,7 @@ fields
   flatknots       : HArray1OfReal    from TColStd;
   knots           : HArray1OfReal    from TColStd;
   mults           : HArray1OfInteger from TColStd;
-  cachepoles      : HArray1OfPnt     from TColgp;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1] see below
-  cacheweights    : HArray1OfReal    from TColStd;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1] see below
-  validcache      : Integer;
-  -- = 1 the cache is valid 
-  -- = 0 the cache is invalid
-  parametercache    : Real;
-  -- Parameter at which the Taylor expension is stored in 
-  -- the cache
-  spanlenghtcache   : Real;
-  -- Since the Taylor expansion is normalized in the 
-  -- cache to evaluate the cache one has to use
-  -- (Parameter - parametercache) / nspanlenghtcache
-  spanindexcache : Integer;
-  -- the span for which the cache is valid if 
-  -- validcache is 1 
-
-  -- usefull to evaluate the parametric resolution
   maxderivinv   : Real from Standard;
   maxderivinvok : Boolean from Standard;
 
-  myMutex       : Mutex from Standard;
-  -- protected bspline-cache
 end;
index 01a3a06..876f373 100644 (file)
@@ -125,12 +125,11 @@ Geom_BSplineCurve::Geom_BSplineCurve
 {
   // check
   
-  CheckCurveData (Poles,
-                 Knots,
-                 Mults,
-                 Degree,
-                 Periodic);
-
+  CheckCurveData(Poles,
+                 Knots,
+                 Mults,
+                 Degree,
+                 Periodic);
 
   // copy arrays
 
@@ -145,11 +144,6 @@ Geom_BSplineCurve::Geom_BSplineCurve
   mults->ChangeArray1() = Mults;
 
   UpdateKnots();
-  cachepoles = new TColgp_HArray1OfPnt(1,Degree + 1);
-  parametercache = 0.0e0 ;
-  spanlenghtcache = 0.0e0 ;
-  spanindexcache = 0 ;
-
 }
 
 //=======================================================================
@@ -174,11 +168,11 @@ Geom_BSplineCurve::Geom_BSplineCurve
 
   // check
   
-  CheckCurveData (Poles,
-                 Knots,
-                 Mults,
-                 Degree,
-                 Periodic);
+  CheckCurveData(Poles,
+                 Knots,
+                 Mults,
+                 Degree,
+                 Periodic);
 
   if (Weights.Length() != Poles.Length())
     Standard_ConstructionError::Raise("Geom_BSplineCurve");
@@ -197,11 +191,9 @@ Geom_BSplineCurve::Geom_BSplineCurve
   
   poles =  new TColgp_HArray1OfPnt(1,Poles.Length());
   poles->ChangeArray1() = Poles;
-  cachepoles = new TColgp_HArray1OfPnt(1,Degree + 1);
   if (rational) {
     weights =  new TColStd_HArray1OfReal(1,Weights.Length());
     weights->ChangeArray1() = Weights;
-    cacheweights  = new TColStd_HArray1OfReal(1,Degree + 1);
   }
 
   knots = new TColStd_HArray1OfReal(1,Knots.Length());
@@ -211,9 +203,6 @@ Geom_BSplineCurve::Geom_BSplineCurve
   mults->ChangeArray1() = Mults;
 
   UpdateKnots();
-  parametercache = 0.0e0 ;
-  spanlenghtcache = 0.0e0 ;
-  spanindexcache = 0 ;
 }
 
 //=======================================================================
@@ -598,7 +587,7 @@ void Geom_BSplineCurve::Segment(const Standard_Real U1,
 
   BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
                            NewU2,periodic,FromU1,ToU2,index2,U);
-  if ( Abs(knots->Value(index2+1)-U) <= Eps)
+  if ( Abs(knots->Value(index2+1)-U) <= Eps || index2 == index1)
     index2++;
   
   Standard_Integer nbknots = index2 - index1 + 1;
@@ -974,7 +963,6 @@ void Geom_BSplineCurve::SetPole
   if (Index < 1 || Index > poles->Length()) Standard_OutOfRange::Raise();
   poles->SetValue (Index, P);
   maxderivinvok = 0;
-  InvalidateCache() ;
 }
 
 //=======================================================================
@@ -1023,7 +1011,6 @@ void Geom_BSplineCurve::SetWeight
     rational = !weights.IsNull();
   }
   maxderivinvok = 0;
-  InvalidateCache() ;
 }
 
 //=======================================================================
@@ -1032,11 +1019,11 @@ void Geom_BSplineCurve::SetWeight
 //=======================================================================
 
 void Geom_BSplineCurve::MovePoint(const Standard_Real U,
-                                 const gp_Pnt& P,
-                                 const Standard_Integer Index1,
-                                 const Standard_Integer Index2,
-                                 Standard_Integer& FirstModifiedPole,
-                                 Standard_Integer& LastmodifiedPole)
+                                  const gp_Pnt& P,
+                                  const Standard_Integer Index1,
+                                  const Standard_Integer Index2,
+                                  Standard_Integer& FirstModifiedPole,
+                                  Standard_Integer& LastmodifiedPole)
 {
   if (Index1 < 1 || Index1 > poles->Length() || 
       Index2 < 1 || Index2 > poles->Length() || Index1 > Index2) {
@@ -1047,12 +1034,11 @@ void Geom_BSplineCurve::MovePoint(const Standard_Real U,
   D0(U, P0);
   gp_Vec Displ(P0, P);
   BSplCLib::MovePoint(U, Displ, Index1, Index2, deg, rational, poles->Array1(), 
-                     weights->Array1(), flatknots->Array1(), 
-                     FirstModifiedPole, LastmodifiedPole, npoles);
+                      weights->Array1(), flatknots->Array1(), 
+                      FirstModifiedPole, LastmodifiedPole, npoles);
   if (FirstModifiedPole) {
     poles->ChangeArray1() = npoles;
     maxderivinvok = 0;
-    InvalidateCache() ;
   }
 }
 
@@ -1061,14 +1047,13 @@ void Geom_BSplineCurve::MovePoint(const Standard_Real U,
 //purpose  : 
 //=======================================================================
 
-void Geom_BSplineCurve::
-MovePointAndTangent(const Standard_Real U,
-                   const gp_Pnt&       P,
-                   const gp_Vec&       Tangent,
-                   const Standard_Real    Tolerance,
-                   const Standard_Integer StartingCondition,
-                   const Standard_Integer EndingCondition,
-                   Standard_Integer&      ErrorStatus) 
+void Geom_BSplineCurve::MovePointAndTangent(const Standard_Real    U,
+                                            const gp_Pnt&          P,
+                                            const gp_Vec&          Tangent,
+                                            const Standard_Real    Tolerance,
+                                            const Standard_Integer StartingCondition,
+                                            const Standard_Integer EndingCondition,
+                                            Standard_Integer&      ErrorStatus) 
 {
   Standard_Integer ii ;
   if (IsPeriodic()) {
@@ -1086,26 +1071,24 @@ MovePointAndTangent(const Standard_Real U,
      delta_derivative) ;
   gp_Vec delta(P0, P);
   for (ii = 1 ; ii <= 3 ; ii++) {
-    delta_derivative.SetCoord(ii, 
-                             Tangent.Coord(ii)- delta_derivative.Coord(ii)) ;
+    delta_derivative.SetCoord(ii, Tangent.Coord(ii)-delta_derivative.Coord(ii));
   }
   BSplCLib::MovePointAndTangent(U,
-                               delta,
-                               delta_derivative,
-                               Tolerance,
-                               deg,
-                               rational,
-                               StartingCondition,
-                               EndingCondition,
-                               poles->Array1(), 
-                               weights->Array1(), 
-                               flatknots->Array1(), 
-                               new_poles,
-                               ErrorStatus) ;
+                                delta,
+                                delta_derivative,
+                                Tolerance,
+                                deg,
+                                rational,
+                                StartingCondition,
+                                EndingCondition,
+                                poles->Array1(), 
+                                weights->Array1(), 
+                                flatknots->Array1(), 
+                                new_poles,
+                                ErrorStatus) ;
   if (!ErrorStatus) {
     poles->ChangeArray1() = new_poles;
     maxderivinvok = 0;
-    InvalidateCache() ;
   }
 }
 
@@ -1119,11 +1102,11 @@ void Geom_BSplineCurve::UpdateKnots()
   rational = !weights.IsNull();
 
   Standard_Integer MaxKnotMult = 0;
-  BSplCLib::KnotAnalysis (deg, 
-               periodic,
-               knots->Array1(), 
-               mults->Array1(), 
-               knotSet, MaxKnotMult);
+  BSplCLib::KnotAnalysis(deg, 
+                         periodic,
+                         knots->Array1(), 
+                         mults->Array1(), 
+                         knotSet, MaxKnotMult);
   
   if (knotSet == GeomAbs_Uniform && !periodic)  {
     flatknots = knots;
@@ -1132,10 +1115,10 @@ void Geom_BSplineCurve::UpdateKnots()
     flatknots = new TColStd_HArray1OfReal 
       (1, BSplCLib::KnotSequenceLength(mults->Array1(),deg,periodic));
 
-    BSplCLib::KnotSequence (knots->Array1(), 
-                           mults->Array1(),
-                           deg,periodic,
-                           flatknots->ChangeArray1());
+    BSplCLib::KnotSequence(knots->Array1(), 
+                           mults->Array1(),
+                           deg,periodic,
+                           flatknots->ChangeArray1());
   }
   
   if (MaxKnotMult == 0)  smooth = GeomAbs_CN;
@@ -1148,36 +1131,6 @@ void Geom_BSplineCurve::UpdateKnots()
       default :  smooth = GeomAbs_C3;   break;
     }
   }
-  InvalidateCache() ;
-}
-
-//=======================================================================
-//function : Invalidate the Cache
-//purpose  : as the name says
-//=======================================================================
-
-void Geom_BSplineCurve::InvalidateCache() 
-{
-  validcache = 0 ;
-}
-
-//=======================================================================
-//function : check if the Cache is valid
-//purpose  : as the name says
-//=======================================================================
-
-Standard_Boolean Geom_BSplineCurve::IsCacheValid
-(const Standard_Real  U)  const 
-{
-  //Roman Lygin 26.12.08, performance improvements
-  //1. avoided using NewParameter = (U - parametercache) / spanlenghtcache
-  //to check against [0, 1), as division is CPU consuming
-  //2. minimized use of if, as branching is also CPU consuming
-  Standard_Real aDelta = U - parametercache;
-
-  return ( validcache &&
-      (aDelta >= 0.0e0) &&
-      ((aDelta < spanlenghtcache) || (spanindexcache == flatknots->Upper() - deg)) );
 }
 
 //=======================================================================
@@ -1200,83 +1153,3 @@ void Geom_BSplineCurve::PeriodicNormalization(Standard_Real&  Parameter) const
   }
 }
 
-//=======================================================================
-//function : Validate the Cache
-//purpose  : that is compute the cache so that it is valid
-//=======================================================================
-
-void Geom_BSplineCurve::ValidateCache(const Standard_Real  Parameter) 
-{
-  Standard_Real NewParameter ;
-  Standard_Integer LocalIndex = 0 ;
-  //
-  // check if the degree did not change
-  //
-  if (cachepoles->Upper() < deg + 1)
-    cachepoles = new TColgp_HArray1OfPnt(1,deg + 1);
-  if (rational)
-  {
-    if (cacheweights.IsNull() || cacheweights->Upper() < deg + 1)
-     cacheweights  = new TColStd_HArray1OfReal(1,deg + 1);
-  }
-  else if (!cacheweights.IsNull())
-    cacheweights.Nullify();
-
-  BSplCLib::LocateParameter(deg,
-                           (flatknots->Array1()),
-                           (BSplCLib::NoMults()),
-                           Parameter,
-                           periodic,
-                           LocalIndex,
-                           NewParameter);
-  spanindexcache = LocalIndex ;
-  if (Parameter == flatknots->Value(LocalIndex + 1)) {
-    
-    LocalIndex += 1 ;
-    parametercache = flatknots->Value(LocalIndex) ;
-    if (LocalIndex == flatknots->Upper() - deg) {
-      //
-      // for the last span if the parameter is outside of 
-      // the domain of the curve than use the last knot
-      // and normalize with the last span Still set the
-      // spanindexcache to flatknots->Upper() - deg so that
-      // the IsCacheValid will know for sure we are extending
-      // the Bspline 
-      //
-      
-      spanlenghtcache = flatknots->Value(LocalIndex - 1) - parametercache ;
-    }
-    else {
-      spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
-    }
-  }
-  else {
-    parametercache = flatknots->Value(LocalIndex) ;
-    spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
-  }
-  
-  if  (rational) {
-    BSplCLib::BuildCache(parametercache,
-                        spanlenghtcache,
-                        periodic,
-                        deg,
-                        (flatknots->Array1()),
-                        poles->Array1(),
-                        weights->Array1(),
-                        cachepoles->ChangeArray1(),
-                        cacheweights->ChangeArray1()) ;
-  }
-  else {
-    BSplCLib::BuildCache(parametercache,
-                        spanlenghtcache,
-                        periodic,
-                        deg,
-                        (flatknots->Array1()),
-                        poles->Array1(),
-                        *((TColStd_Array1OfReal*) NULL),
-                        cachepoles->ChangeArray1(),
-                        *((TColStd_Array1OfReal*) NULL)) ;
-  }
-  validcache = 1 ;
-}
-
index ec08ce5..e36433e 100644 (file)
@@ -30,7 +30,6 @@
 #include <Standard_OutOfRange.hxx>
 #include <Standard_DomainError.hxx>
 #include <Standard_RangeError.hxx>
-#include <Standard_Mutex.hxx>
 #include <Precision.hxx>
 
 #define  POLES    (poles->Array1())
@@ -181,33 +180,24 @@ Standard_Integer Geom_BSplineCurve::Degree () const
 
 void Geom_BSplineCurve::D0(const Standard_Real U, gp_Pnt& P) const 
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if(!IsCacheValid(NewU)) 
-    MyCurve->ValidateCache(NewU);
-
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD0(NewU,
-      deg,
-      parametercache,
-      spanlenghtcache,
-      cachepoles->Array1(),
-      cacheweights->Array1(),
+    BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
       P);
   }
-  else
+  else 
   {
-    BSplCLib::CacheD0(NewU,
-      deg,
-      parametercache,
-      spanlenghtcache,
-      cachepoles->Array1(),
+    BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
       *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
       P);
   }
 }
@@ -221,36 +211,25 @@ void Geom_BSplineCurve::D1 (const Standard_Real U,
                                   gp_Pnt& P,
                                   gp_Vec& V1) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if(!IsCacheValid(NewU)) 
-    MyCurve->ValidateCache(NewU);
-
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD1(NewU,
-      deg,
-      parametercache,
-      spanlenghtcache,
-      cachepoles->Array1(),
-      cacheweights->Array1(),
-      P,
-      V1);
+    BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1);
   }
-  else
+  else 
   {
-    BSplCLib::CacheD1(NewU,
-      deg,
-      parametercache,
-      spanlenghtcache,
-      cachepoles->Array1(),
+    BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
       *((TColStd_Array1OfReal*) NULL),
-      P,
-      V1);
+      knots->Array1(), mults->Array1(),
+      P, V1);
   }
 }
 
@@ -264,37 +243,25 @@ void Geom_BSplineCurve::D2(const Standard_Real U,
                            gp_Vec& V1,
                            gp_Vec& V2) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if(!IsCacheValid(NewU)) 
-    MyCurve->ValidateCache(NewU);
-
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD2(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P,
-                     V1,
-                     V2);
+    BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2);
   }
-  else {
-    BSplCLib::CacheD2(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     *((TColStd_Array1OfReal*) NULL),
-                     P,
-                     V1,
-                     V2);
+  else 
+  {
+    BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2);
   }
 }
 
@@ -309,41 +276,25 @@ void Geom_BSplineCurve::D3(const Standard_Real U,
                            gp_Vec& V2,
                            gp_Vec& V3) const
 {
-  
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if(!IsCacheValid(NewU)) 
-    MyCurve->ValidateCache(NewU);
-
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD3(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P,
-                     V1,
-                     V2,
-                     V3) ;
+    BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2, V3);
   }
-  else
+  else 
   {
-    BSplCLib::CacheD3(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     cachepoles->Array1(),
-                     *((TColStd_Array1OfReal*) NULL),
-                     P,
-                     V1,
-                     V2,
-                     V3) ;
+    BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2, V3);
   }
 }
 
@@ -352,19 +303,19 @@ void Geom_BSplineCurve::D3(const Standard_Real U,
 //purpose  : 
 //=======================================================================
 
-gp_Vec Geom_BSplineCurve::DN  (const Standard_Real    U,
-                              const Standard_Integer N ) const
+gp_Vec Geom_BSplineCurve::DN(const Standard_Real    U,
+                             const Standard_Integer N) const
 {
   gp_Vec V;
   if (rational) {
     BSplCLib::DN(U,N,0,deg,periodic,POLES,
-                weights->Array1(),
-                FKNOTS,FMULTS,V);
+      weights->Array1(),
+      FKNOTS,FMULTS,V);
   }
   else {
     BSplCLib::DN(U,N,0,deg,periodic,POLES,
-                *((TColStd_Array1OfReal*) NULL),
-                FKNOTS,FMULTS,V);
+      *((TColStd_Array1OfReal*) NULL),
+      FKNOTS,FMULTS,V);
   }
   return V;
 }
@@ -437,6 +388,11 @@ void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
   K = knots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineCurve::Knots() const
+{
+  return knots->Array1();
+}
+
 //=======================================================================
 //function : KnotSequence
 //purpose  : 
@@ -449,6 +405,11 @@ void Geom_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
   K = flatknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineCurve::KnotSequence() const
+{
+  return flatknots->Array1();
+}
+
 //=======================================================================
 //function : LastUKnotIndex
 //purpose  : 
@@ -668,6 +629,11 @@ void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
   M = mults->Array1();
 }
 
+const TColStd_Array1OfInteger& Geom_BSplineCurve::Multiplicities() const
+{
+  return mults->Array1();
+}
+
 //=======================================================================
 //function : NbKnots
 //purpose  : 
@@ -708,6 +674,11 @@ void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
   P = poles->Array1();
 }
 
+const TColgp_Array1OfPnt& Geom_BSplineCurve::Poles() const
+{
+  return poles->Array1();
+}
+
 //=======================================================================
 //function : StartPoint
 //purpose  : 
@@ -757,6 +728,13 @@ void Geom_BSplineCurve::Weights
   }
 }
 
+const TColStd_Array1OfReal& Geom_BSplineCurve::Weights() const
+{
+  if (IsRational())
+    return weights->Array1();
+  return BSplCLib::NoWeights();
+}
+
 //=======================================================================
 //function : IsRational
 //purpose  : 
@@ -778,7 +756,6 @@ void Geom_BSplineCurve::Transform
   TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
   for (Standard_Integer I = 1; I <= CPoles.Length(); I++)  
     CPoles (I).Transform (T);
-  InvalidateCache() ;
   maxderivinvok = 0;
 }
 
index d1ddf3e..14f17e7 100644 (file)
@@ -147,8 +147,7 @@ uses  Array1OfInteger      from TColStd,
       BSplKnotDistribution from GeomAbs,
       Curve                from Geom,
       Geometry             from Geom,
-      Shape                from GeomAbs,
-      Mutex                from Standard
+      Shape                from GeomAbs
 
 raises ConstructionError   from Standard,
        DimensionError      from Standard,
@@ -919,16 +918,6 @@ is
         --                 |1.0, 2.0, 0.5|
         --   if Weights =  |1.0, 2.0, 0.5|   returns False
         --                 |1.0, 2.0, 0.5|
-
-  IsCacheValid(me;  UParameter, VParameter : Real) returns Boolean ;
-  
-        ---Purpose :
-        --           Tells whether the Cache is valid for the
-        --           given parameter 
-        -- Warnings : the parameter must be normalized within
-        -- the period if the curve is periodic. Otherwise
-        -- the answer will be false
-        -- 
         
   Bounds (me; U1, U2, V1, V2 : out Real);
         ---Purpose :
@@ -1017,6 +1006,11 @@ is
        ---Purpose :
        --  Raised if the length of P in the U and V direction
        --  is not equal to NbUpoles and NbVPoles.
+  Poles (me)
+  returns Array2OfPnt from TColgp
+       ---Purpose : Returns the poles of the B-spline surface.
+       ---C++ : return const &
+  is static;
 
 
   UDegree (me)  returns Integer;
@@ -1055,6 +1049,11 @@ is
                ---Purpose :
                --  Raised if the length of Ku is not equal to the number of knots
                --  in the U direction.
+  UKnots (me)
+  returns Array1OfReal from TColStd
+       ---Purpose : Returns the knots in the U direction.
+       ---C++ : return const &
+  is static;
 
 
   UKnotSequence (me; Ku : out Array1OfReal from TColStd)
@@ -1066,6 +1065,15 @@ is
      raises DimensionError;
         ---Purpose :
         --  Raised if the length of Ku is not equal to NbUPoles + UDegree + 1
+  UKnotSequence (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : Returns the uknots sequence.
+        --  In this sequence the knots with a multiplicity greater than 1
+        --  are repeated.
+        --- Example :
+        --  Ku = {k1, k1, k1, k2, k3, k3, k4, k4, k4}
+        ---C++ : return const &
+  is static;
 
 
   UMultiplicity (me; UIndex : Integer)   returns Integer
@@ -1083,6 +1091,11 @@ is
                ---Purpose :
                --  Raised if the length of Mu is not equal to the number of
                --  knots in the U direction.
+  UMultiplicities (me)
+  returns Array1OfInteger from TColStd
+       ---Purpose : Returns the multiplicities of the knots in the U direction.
+       ---C++ : return const &
+  is static;
 
 
   VDegree (me)  returns Integer;
@@ -1120,6 +1133,11 @@ is
        ---Purpose :
        --  Raised if the length of Kv is not equal to the number of 
        --  knots in the V direction.
+  VKnots (me)
+  returns Array1OfReal from TColStd
+       ---Purpose : Returns the knots in the V direction.
+       ---C++ : return const &
+  is static;
 
 
   VKnotSequence (me; Kv : out Array1OfReal from TColStd)
@@ -1131,6 +1149,15 @@ is
      raises DimensionError;
         ---Purpose :
         --  Raised if the length of Kv is not equal to NbVPoles + VDegree + 1
+  VKnotSequence (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : Returns the vknots sequence.
+        --  In this sequence the knots with a multiplicity greater than 1
+        --  are repeated.
+        --- Example :
+        --  Ku = {k1, k1, k1, k2, k3, k3, k4, k4, k4}
+        ---C++ : return const &
+  is static;
 
 
   VMultiplicity (me; VIndex : Integer)   returns Integer
@@ -1148,6 +1175,11 @@ is
        ---Purpose :
        --  Raised if the length of Mv is not equal to the number of 
        --  knots in the V direction.
+  VMultiplicities (me)
+  returns Array1OfInteger from TColStd
+       ---Purpose : Returns the multiplicities of the knots in the V direction.
+       ---C++ : return const &
+  is static;
 
 
   Weight (me; UIndex, VIndex : Integer)   returns Real
@@ -1164,6 +1196,11 @@ is
         ---Purpose :
         --  Raised if the length of W in the U and V direction is 
         --  not equal to NbUPoles and NbVPoles.
+  Weights (me)
+  returns Array2OfReal from TColStd
+        ---Purpose : Returns the weights of the B-spline surface.
+        ---C++ : return const &
+  is static;
 
 
 
@@ -1389,16 +1426,6 @@ is
   is static private;
 
   
-  InvalidateCache(me : mutable)
-       ---Purpose : Invalidates the cache. This has to be private this has to be private
-      is static private;
-      
-  ValidateCache(me : mutable ; UParameter : Real; 
-                              VParameter : Real) 
-  
-    is static private;
-       ---Purpose : updates the cache and validates it
-
   
 fields
             
@@ -1420,68 +1447,8 @@ fields
    vknots    : HArray1OfReal    from TColStd;
    umults    : HArray1OfInteger from TColStd;
    vmults    : HArray1OfInteger from TColStd;
-  -- Inplementation of the cache on surfaces
-   cachepoles : HArray2OfPnt     from TColgp;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1]x[0 1]. The Taylor expension of lower degree
-  -- is stored as consecutive Pnt in the array that is
-  -- if udeg <= vdeg than the array stores the following
-  -- 
-  --                                  (2,0)           (3,0) 
-  --               (1,0)             f     (u0,v0)   f     (u0,v0)
-  --  f  (u0,v0)  f     (u0,v0)      -------------   -----------
-  --                                      2             3!
-  --                                
-  --                                   (2,1)           (3,1) 
-  --   (0,1)          (1,1)         f     (u0,v0)   f     (u0,v0)
-  --  f     (u0,v0)  f     (u0,v0)  -------------   -----------
-  --                                     2              3!
-  --   
-  -- Otherwise it is stored in the following fashion
-  -- 
-  --  
-  --                                  (0,2)           (0,3) 
-  --               (0,1)             f     (u0,v0)   f     (u0,v0)
-  --  f  (u0,v0)  f     (u0,v0)      -------------   -----------
-  --                                      2             3!
-  --                                
-  --                                 (1,2)           (1,3) 
-  --   (1,0)          (1,1)         f     (u0,v0)   f     (u0,v0)
-  --  f     (u0,v0)  f     (u0,v0)  -------------   -----------
-  --                                     2              3!
-  --   
-  --   The size of the array is (1,Max degree) (1, Min degree) 
-  -- 
-    cacheweights   : HArray2OfReal    from TColStd;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1]x[0 1]. The Taylor expension of lower degree
-  -- is stored as consecutive Real in the array as explained above
-    ucacheparameter : Real ;
-    vcacheparameter : Real ;
-  -- Parameters at which the Taylor expension is stored in 
-  -- the cache  
-    ucachespanlenght : Real ;
-    vcachespanlenght : Real ;
-      -- Since the Taylor expansion is normalized in the 
-  -- cache to evaluate the cache one has to use
-  -- (UParameter - uparametercache) / ucachespanlenght
-  -- (VParameter - vparametercache) / vcachespanlenght
-    ucachespanindex : Integer ;
-    vcachespanindex : Integer ;
-  -- the span for which the cache is valid if 
-  -- validcache is 1 
-    validcache : Integer ;
-    
-  -- usefull to evaluate the parametric resolutions
-    umaxderivinv  : Real from Standard;
-    vmaxderivinv  : Real from Standard;
-    maxderivinvok : Boolean from Standard;
-
-    myMutex       : Mutex from Standard;
-    -- protected bsplinesurface-cache
-
+   umaxderivinv  : Real from Standard;
+   vmaxderivinv  : Real from Standard;
+   maxderivinvok : Boolean from Standard;
+   
 end;
index a24a6be..857e9c7 100644 (file)
@@ -165,8 +165,6 @@ Geom_BSplineSurface::Geom_BSplineSurface
  maxderivinvok(0)
 
 {
-  Standard_Integer MinDegree,
-  MaxDegree ;
 
   // check
   
@@ -196,19 +194,6 @@ Geom_BSplineSurface::Geom_BSplineSurface
 
   vmults  = new TColStd_HArray1OfInteger (1,VMults.Length());
   vmults->ChangeArray1() = VMults;
-  MinDegree = Min(udeg,vdeg) ;
-  MaxDegree = Max(udeg,vdeg) ;
-  cachepoles = new TColgp_HArray2OfPnt(1,MaxDegree + 1,
-                                       1,MinDegree + 1) ;
-  
-  cacheweights.Nullify() ;
-  ucacheparameter = 0.0e0 ;
-  vcacheparameter = 0.0e0 ;
-  ucachespanlenght = 1.0e0 ;
-  vcachespanlenght = 1.0e0 ;
-  ucachespanindex = 0 ;
-  vcachespanindex = 0 ;
-  validcache = 0 ;
 
   UpdateUKnots();
   UpdateVKnots();
@@ -238,8 +223,6 @@ Geom_BSplineSurface::Geom_BSplineSurface
  vdeg(VDegree),
  maxderivinvok(0)
 {
-  Standard_Integer MinDegree,
-  MaxDegree ;
   // check weights
 
   if (Weights.ColLength() != Poles.ColLength())
@@ -289,21 +272,6 @@ Geom_BSplineSurface::Geom_BSplineSurface
 
   vmults  = new TColStd_HArray1OfInteger (1,VMults.Length());
   vmults->ChangeArray1() = VMults;
-  MinDegree = Min(udeg,vdeg) ;
-  MaxDegree = Max(udeg,vdeg) ;
-  cachepoles = new TColgp_HArray2OfPnt(1,MaxDegree + 1,
-                                       1,MinDegree + 1) ;
-  if (urational || vrational) {
-    cacheweights = new TColStd_HArray2OfReal (1,MaxDegree + 1,
-                                             1,MinDegree + 1);
-  }
-  ucacheparameter = 0.0e0 ;
-  vcacheparameter = 0.0e0 ;
-  ucachespanlenght = 1.0e0 ;
-  vcachespanlenght = 1.0e0 ;
-  ucachespanindex = 0 ;
-  vcachespanindex = 0 ;
-  validcache = 0 ;
 
   UpdateUKnots();
   UpdateVKnots();
@@ -1258,8 +1226,6 @@ void Geom_BSplineSurface::UpdateUKnots()
       default :  Usmooth = GeomAbs_C3;   break;
     }
   }
-
-  InvalidateCache() ;
 }
 
 //=======================================================================
@@ -1298,18 +1264,8 @@ void Geom_BSplineSurface::UpdateVKnots()
       default :  Vsmooth = GeomAbs_C3;   break;
     }
   }
-  InvalidateCache() ;
 }
 
-//=======================================================================
-//function :  InvalidateCache
-//purpose  : Invalidates the Cache of the surface
-//=======================================================================
-
-void Geom_BSplineSurface::InvalidateCache()
-{
-  validcache = 0 ;
-}
 
 //=======================================================================
 //function : Normalizes the parameters if the curve is periodic
@@ -1363,177 +1319,6 @@ void Geom_BSplineSurface::PeriodicNormalization
 }
 
 //=======================================================================
-//function : ValidateCache
-//purpose  : function that validates the cache of the surface
-//=======================================================================
-
-void Geom_BSplineSurface::ValidateCache(const Standard_Real  Uparameter,
-                                       const Standard_Real  Vparameter) 
-{
-  Standard_Real NewParameter  ;
-  Standard_Integer LocalIndex = 0  ;
-  Standard_Integer MinDegree,
-  MaxDegree ;
-  //
-  // check if the degree did not change
-  //
-
-  MinDegree = Min(udeg,vdeg) ;
-  MaxDegree = Max(udeg,vdeg) ;
-  if (cachepoles->ColLength() < MaxDegree + 1 ||
-      cachepoles->RowLength() < MinDegree + 1) {
-    cachepoles = new TColgp_HArray2OfPnt(1,MaxDegree + 1,
-                                        1,MinDegree + 1);
-  }
-  //
-  // Verif + poussee pour les poids
-  //
-  if (urational || vrational) {
-    if (cacheweights.IsNull()) {
-      cacheweights  = new TColStd_HArray2OfReal(1,MaxDegree + 1,
-                                               1,MinDegree + 1);
-    }
-    else {
-      if (cacheweights->ColLength() < MaxDegree + 1 ||
-         cacheweights->RowLength() < MinDegree + 1) {
-       cacheweights  = new TColStd_HArray2OfReal(1,MaxDegree + 1,
-                                                 1,MinDegree + 1);
-      }
-    }
-  }
-  else if (!cacheweights.IsNull())
-    cacheweights.Nullify();
-
-  BSplCLib::LocateParameter(udeg,
-                           (ufknots->Array1()),
-                           (BSplCLib::NoMults()),
-                           Uparameter,
-                           uperiodic,
-                           LocalIndex,
-                           NewParameter);
-  ucachespanindex = LocalIndex ;
-  if (Uparameter == ufknots->Value(LocalIndex + 1)) {
-    
-    LocalIndex += 1 ;
-    ucacheparameter = ufknots->Value(LocalIndex) ;
-    if (LocalIndex == ufknots->Upper() - udeg) {
-      //
-      // for the last span if the parameter is outside of 
-      // the domain of the curve than use the last knot
-      // and normalize with the last span Still set the
-      // cachespanindex to flatknots->Upper() - deg so that
-      // the IsCacheValid will know for sure we are extending
-      // the Bspline 
-      //
-      
-      ucachespanlenght = ufknots->Value(LocalIndex - 1) - ucacheparameter ;
-    }
-    else {
-       ucachespanlenght = ufknots->Value(LocalIndex + 1) - ucacheparameter ;
-      }
-  }
-  else {
-      ucacheparameter = ufknots->Value(LocalIndex) ;
-      ucachespanlenght = ufknots->Value(LocalIndex + 1) - ucacheparameter ;
-    }
-
-  LocalIndex = 0 ;   
-  BSplCLib::LocateParameter(vdeg,
-                           (vfknots->Array1()),
-                           (BSplCLib::NoMults()),
-                           Vparameter,
-                           vperiodic,
-                           LocalIndex,
-                           NewParameter);
-  vcachespanindex = LocalIndex ;
-  if (Vparameter == vfknots->Value(LocalIndex + 1)) {
-    LocalIndex += 1 ;
-    vcacheparameter = vfknots->Value(LocalIndex) ;
-    if (LocalIndex == vfknots->Upper() - vdeg) {
-      //
-      // for the last span if the parameter is outside of 
-      // the domain of the curve than use the last knot
-      // and normalize with the last span Still set the
-      // cachespanindex to flatknots->Upper() - deg so that
-      // the IsCacheValid will know for sure we are extending
-      // the Bspline 
-      //
-      
-      vcachespanlenght = vfknots->Value(LocalIndex - 1) - vcacheparameter ;
-    }
-    else {
-      vcachespanlenght = vfknots->Value(LocalIndex + 1) - vcacheparameter ;
-    }
-  }
-  else {
-    vcacheparameter = vfknots->Value(LocalIndex) ;
-    vcachespanlenght = vfknots->Value(LocalIndex + 1) - vcacheparameter ;
-  }
-  
-  Standard_Real uparameter_11 = (2*ucacheparameter + ucachespanlenght)/2,
-                uspanlenght_11 = ucachespanlenght/2,
-                vparameter_11 = (2*vcacheparameter + vcachespanlenght)/2,
-                vspanlenght_11 = vcachespanlenght/2 ;
-  if (urational || vrational) {
-    BSplSLib::BuildCache(uparameter_11,
-                        vparameter_11,
-                        uspanlenght_11,
-                        vspanlenght_11,
-                        uperiodic,
-                        vperiodic,
-                        udeg,
-                        vdeg,
-                        ucachespanindex,
-                        vcachespanindex,
-                        (ufknots->Array1()),
-                        (vfknots->Array1()),
-                        poles->Array2(),
-                        weights->Array2(),
-                        cachepoles->ChangeArray2(),
-                        cacheweights->ChangeArray2()) ;
-  }
-  else {
-    BSplSLib::BuildCache(uparameter_11,
-                        vparameter_11,
-                        uspanlenght_11,
-                        vspanlenght_11,
-                        uperiodic,
-                        vperiodic,
-                        udeg,
-                        vdeg,
-                        ucachespanindex,
-                        vcachespanindex,
-                        (ufknots->Array1()),
-                        (vfknots->Array1()),
-                        poles->Array2(),
-                        *((TColStd_Array2OfReal*) NULL),
-                        cachepoles->ChangeArray2(),
-                        *((TColStd_Array2OfReal*) NULL)) ;
-  }
-  validcache = 1 ;
-}
-
-//=======================================================================
-//function : IsCacheValid
-//purpose  : function that checks for the validity of the cache of the
-//           surface
-//=======================================================================
-Standard_Boolean Geom_BSplineSurface::IsCacheValid
-(const Standard_Real  U,
- const Standard_Real  V)  const 
-{
-  //Roman Lygin 26.12.08, see comments in Geom_BSplineCurve::IsCacheValid()
-  Standard_Real aDeltaU = U - ucacheparameter;
-  Standard_Real aDeltaV = V - vcacheparameter;
-
-  return ( validcache &&
-      (aDeltaU >= 0.0e0) &&
-      ((aDeltaU < ucachespanlenght) || (ucachespanindex == ufknots->Upper() - udeg)) &&
-      (aDeltaV >= 0.0e0) &&
-      ((aDeltaV < vcachespanlenght) || (vcachespanindex == vfknots->Upper() - vdeg)) );
-}
-
-//=======================================================================
 //function : SetWeight
 //purpose  : 
 //=======================================================================
@@ -1550,7 +1335,6 @@ void Geom_BSplineSurface::SetWeight (const Standard_Integer UIndex,
   }
   Weights (UIndex+Weights.LowerRow()-1, VIndex+Weights.LowerCol()-1) = Weight;
   Rational(Weights, urational, vrational);
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1583,8 +1367,6 @@ void Geom_BSplineSurface::SetWeightCol
   }
   // Verifie si c'est rationnel
   Rational(Weights, urational, vrational);
-
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1619,6 +1401,5 @@ void Geom_BSplineSurface::SetWeightRow
   }
   // Verifie si c'est rationnel
   Rational(Weights, urational, vrational);
-  InvalidateCache();
 }
 
index 20ea22e..0a63095 100644 (file)
@@ -109,48 +109,15 @@ Standard_Boolean Geom_BSplineSurface::IsCNv
 
 void Geom_BSplineSurface::D0(const Standard_Real U,
                              const Standard_Real V,
-                             gp_Pnt& P) const 
-{
-  Standard_Real  new_u(U), new_v(V);
-  PeriodicNormalization(new_u, new_v);
-
-  Geom_BSplineSurface* MySurface = (Geom_BSplineSurface *) this;
-  Standard_Mutex::Sentry aSentry(MySurface->myMutex);
-
-  if(!IsCacheValid(new_u, new_v))
-     MySurface->ValidateCache(new_u, new_v);
-
- Standard_Real uparameter_11 = (2*ucacheparameter + ucachespanlenght)/2,
-               uspanlenght_11 = ucachespanlenght/2,
-               vparameter_11 = (2*vcacheparameter + vcachespanlenght)/2,
-               vspanlenght_11 = vcachespanlenght/2 ; 
- if (cacheweights.IsNull()) {
-      
-   BSplSLib::CacheD0(new_u,
-                    new_v,
-                    udeg,
-                    vdeg,
-                    uparameter_11,
-                    vparameter_11,
-                    uspanlenght_11,
-                    vspanlenght_11,
-                    cachepoles->Array2(),
-                    *((TColStd_Array2OfReal*) NULL),
-                    P) ;
- }
- else {
-   BSplSLib::CacheD0(new_u,
-                    new_v,
-                    udeg,
-                    vdeg,
-                    uparameter_11,
-                    vparameter_11,
-                    uspanlenght_11,
-                    vspanlenght_11,
-                    cachepoles->Array2(),
-                    cacheweights->Array2(),
-                    P) ;
- }
+                                   gp_Pnt&       P) const 
+{
+  Standard_Real aNewU = U;
+  Standard_Real aNewV = V;
+  PeriodicNormalization(aNewU, aNewV);
+
+  BSplSLib::D0(aNewU,aNewV,0,0,POLES,WEIGHTS,UFKNOTS,VFKNOTS,FMULTS,FMULTS,
+       udeg,vdeg,urational,vrational,uperiodic,vperiodic,
+       P);
 }
 
 //=======================================================================
@@ -160,56 +127,25 @@ void Geom_BSplineSurface::D0(const Standard_Real U,
 
 void Geom_BSplineSurface::D1(const Standard_Real U,
                              const Standard_Real V,
-                             gp_Pnt& P,
-                             gp_Vec& D1U,
-                             gp_Vec& D1V) const
+                                   gp_Pnt&       P,
+                                   gp_Vec&       D1U,
+                                   gp_Vec&       D1V) const
 {
-  Standard_Real  new_u(U), new_v(V);
-  PeriodicNormalization(new_u, new_v);
+  Standard_Real aNewU = U;
+  Standard_Real aNewV = V;
+  PeriodicNormalization(aNewU, aNewV);
 
-  Geom_BSplineSurface* MySurface = (Geom_BSplineSurface *) this;
-  Standard_Mutex::Sentry aSentry(MySurface->myMutex);
+  Standard_Integer uindex = 0, vindex = 0;
 
-  if(!IsCacheValid(new_u, new_v))
-     MySurface->ValidateCache(new_u, new_v);
+  BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), U, uperiodic, uindex, aNewU);
+  uindex = BSplCLib::FlatIndex(udeg, uindex, umults->Array1(), uperiodic);
 
-  Standard_Real uparameter_11 = (2*ucacheparameter + ucachespanlenght)/2,
-                uspanlenght_11 = ucachespanlenght/2,
-                vparameter_11 = (2*vcacheparameter + vcachespanlenght)/2,
-                vspanlenght_11 = vcachespanlenght/2 ;
+  BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), V, vperiodic, vindex, aNewV);
+  vindex = BSplCLib::FlatIndex(vdeg, vindex, vmults->Array1(), vperiodic);
 
-  if (cacheweights.IsNull()) {
-    
-    BSplSLib::CacheD1(new_u,
-                     new_v,
-                     udeg,
-                     vdeg,
-                     uparameter_11,
-                     vparameter_11,
-                     uspanlenght_11,
-                     vspanlenght_11,
-                     cachepoles->Array2(),
-                     *((TColStd_Array2OfReal*) NULL),
-                     P,
-                     D1U,
-                     D1V) ;
-  }
-  else {
-    
-    BSplSLib::CacheD1(new_u,
-                     new_v,
-                     udeg,
-                     vdeg,
-                     uparameter_11,
-                     vparameter_11,
-                     uspanlenght_11,
-                     vspanlenght_11,
-                     cachepoles->Array2(),
-                     cacheweights->Array2(),
-                     P,
-                     D1U,
-                     D1V) ;
-  }
+  BSplSLib::D1(aNewU,aNewV,uindex,vindex,POLES,WEIGHTS,UFKNOTS,VFKNOTS,FMULTS,FMULTS,
+       udeg,vdeg,urational,vrational,uperiodic,vperiodic,
+       P, D1U, D1V);
 }
 
 //=======================================================================
@@ -218,64 +154,30 @@ void Geom_BSplineSurface::D1(const Standard_Real U,
 //=======================================================================
 
 void Geom_BSplineSurface::D2 (const Standard_Real U, 
-                             const Standard_Real V,
-                                   gp_Pnt&       P,
-                                   gp_Vec&       D1U,
-                                   gp_Vec&       D1V,
-                                   gp_Vec&       D2U,
-                                   gp_Vec&       D2V,
-                                   gp_Vec&       D2UV) const
-{
-  Standard_Real  new_u(U), new_v(V);
-  PeriodicNormalization(new_u, new_v);
-
-  Geom_BSplineSurface* MySurface = (Geom_BSplineSurface *) this;
-  Standard_Mutex::Sentry aSentry(MySurface->myMutex);
-
-  if(!IsCacheValid(new_u, new_v))
-     MySurface->ValidateCache(new_u, new_v);
-
-  Standard_Real uparameter_11 = (2*ucacheparameter + ucachespanlenght)/2,
-                uspanlenght_11 = ucachespanlenght/2,
-                vparameter_11 = (2*vcacheparameter + vcachespanlenght)/2,
-                vspanlenght_11 = vcachespanlenght/2 ;
-  if (cacheweights.IsNull()) {
-      BSplSLib::CacheD2(new_u,
-                       new_v,
-                       udeg,
-                       vdeg,
-                       uparameter_11,
-                       vparameter_11,
-                       uspanlenght_11,
-                       vspanlenght_11,
-                       cachepoles->Array2(),
-                       *((TColStd_Array2OfReal*) NULL),
-                       P,
-                       D1U,
-                       D1V,
-                       D2U,
-                       D2UV,
-                       D2V); 
-    }
-    else {
-      BSplSLib::CacheD2(new_u,
-                       new_v,
-                       udeg,
-                       vdeg,
-                       uparameter_11,
-                       vparameter_11,
-                       uspanlenght_11,
-                       vspanlenght_11,
-                       cachepoles->Array2(),
-                       cacheweights->Array2(),
-                       P,
-                       D1U,
-                       D1V,
-                       D2U,
-                       D2UV,
-                       D2V); 
-    }
-  }
+                              const Standard_Real V,
+                                    gp_Pnt&       P,
+                                    gp_Vec&       D1U,
+                                    gp_Vec&       D1V,
+                                    gp_Vec&       D2U,
+                                    gp_Vec&       D2V,
+                                    gp_Vec&       D2UV) const
+{
+  Standard_Real aNewU = U;
+  Standard_Real aNewV = V;
+  PeriodicNormalization(aNewU, aNewV);
+
+  Standard_Integer uindex = 0, vindex = 0;
+
+  BSplCLib::LocateParameter(udeg, uknots->Array1(), umults->Array1(), U, uperiodic, uindex, aNewU);
+  uindex = BSplCLib::FlatIndex(udeg, uindex, umults->Array1(), uperiodic);
+
+  BSplCLib::LocateParameter(vdeg, vknots->Array1(), vmults->Array1(), V, vperiodic, vindex, aNewV);
+  vindex = BSplCLib::FlatIndex(vdeg, vindex, vmults->Array1(), vperiodic);
+
+  BSplSLib::D2(aNewU,aNewV,uindex,vindex,POLES,WEIGHTS,UFKNOTS,VFKNOTS,FMULTS,FMULTS,
+       udeg,vdeg,urational,vrational,uperiodic,vperiodic,
+       P, D1U, D1V, D2U, D2V, D2UV);
+}
 
 //=======================================================================
 //function : D3
@@ -542,6 +444,11 @@ void Geom_BSplineSurface::Poles (TColgp_Array2OfPnt& P) const
   P = poles->Array2();
 }
 
+const TColgp_Array2OfPnt& Geom_BSplineSurface::Poles() const
+{
+  return poles->Array2();
+}
+
 //=======================================================================
 //function : UIso
 //purpose  : 
@@ -645,6 +552,11 @@ void Geom_BSplineSurface::UKnots (TColStd_Array1OfReal& Ku) const
   Ku = uknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineSurface::UKnots() const
+{
+  return uknots->Array1();
+}
+
 //=======================================================================
 //function : VKnots
 //purpose  : 
@@ -656,6 +568,11 @@ void Geom_BSplineSurface::VKnots (TColStd_Array1OfReal& Kv) const
   Kv = vknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineSurface::VKnots() const
+{
+  return vknots->Array1();
+}
+
 //=======================================================================
 //function : UKnotSequence
 //purpose  : 
@@ -667,6 +584,11 @@ void Geom_BSplineSurface::UKnotSequence (TColStd_Array1OfReal& Ku) const
   Ku = ufknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineSurface::UKnotSequence() const
+{
+  return ufknots->Array1();
+}
+
 //=======================================================================
 //function : VKnotSequence
 //purpose  : 
@@ -678,6 +600,11 @@ void Geom_BSplineSurface::VKnotSequence (TColStd_Array1OfReal& Kv) const
   Kv = vfknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom_BSplineSurface::VKnotSequence() const
+{
+  return vfknots->Array1();
+}
+
 //=======================================================================
 //function : UMultiplicity
 //purpose  : 
@@ -701,6 +628,11 @@ void Geom_BSplineSurface::UMultiplicities (TColStd_Array1OfInteger& Mu) const
   Mu = umults->Array1();
 }
 
+const TColStd_Array1OfInteger& Geom_BSplineSurface::UMultiplicities() const
+{
+  return umults->Array1();
+}
+
 //=======================================================================
 //function : VIso
 //purpose  : 
@@ -798,6 +730,11 @@ void Geom_BSplineSurface::VMultiplicities (TColStd_Array1OfInteger& Mv) const
   Mv = vmults->Array1();
 }
 
+const TColStd_Array1OfInteger& Geom_BSplineSurface::VMultiplicities() const
+{
+  return vmults->Array1();
+}
+
 //=======================================================================
 //function : Weight
 //purpose  : 
@@ -826,6 +763,13 @@ void Geom_BSplineSurface::Weights (TColStd_Array2OfReal& W) const
   W = weights->Array2();
 }
 
+const TColStd_Array2OfReal& Geom_BSplineSurface::Weights() const
+{
+  if (urational || vrational)
+    return weights->Array2();
+  return BSplSLib::NoWeights();
+}
+
 //=======================================================================
 //function : Transform
 //purpose  : 
@@ -839,8 +783,6 @@ void Geom_BSplineSurface::Transform (const gp_Trsf& T)
       VPoles (i, j).Transform (T);
     }
   }
-
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1555,8 +1497,6 @@ void Geom_BSplineSurface::SetPoleCol (const Standard_Integer      VIndex,
   for (Standard_Integer I = CPoles.Lower(); I <= CPoles.Upper(); I++) {
     Poles (I+Poles.LowerRow()-1, VIndex+Poles.LowerCol()-1) = CPoles(I);
   }
-
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1593,8 +1533,6 @@ void Geom_BSplineSurface::SetPoleRow (const Standard_Integer    UIndex,
   for (Standard_Integer I = CPoles.Lower(); I <= CPoles.Upper(); I++) {
     Poles (UIndex+Poles.LowerRow()-1, I+Poles.LowerCol()-1) = CPoles (I);
   }
-
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1620,7 +1558,6 @@ void Geom_BSplineSurface::SetPole (const Standard_Integer UIndex,
                                   const gp_Pnt&          P)
 {
   poles->SetValue (UIndex+poles->LowerRow()-1, VIndex+poles->LowerCol()-1, P);
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1676,7 +1613,6 @@ void Geom_BSplineSurface::MovePoint(const Standard_Real U,
     poles->ChangeArray2() = npoles;
   }
   maxderivinvok = 0;
-  InvalidateCache() ;
 }
 
 //=======================================================================
index c273f9e..a4a996c 100644 (file)
@@ -39,6 +39,7 @@
 #include <Standard_ConstructionError.hxx>
 #include <Standard_RangeError.hxx>
 #include <Standard_NotImplemented.hxx>
+#include <CSLib_Offset.hxx>
 
 typedef Geom_OffsetCurve         OffsetCurve;
 typedef Handle(Geom_OffsetCurve) Handle(OffsetCurve);
@@ -62,6 +63,13 @@ static const Standard_Real MinStep   = 1e-7;
 static const Standard_Real MyAngularToleranceForG1 = Precision::Angular();
 
 
+static gp_Vec dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
+// Recalculate derivatives in the singular point
+// Returns true if the direction of derivatives is changed
+static Standard_Boolean AdjustDerivative(
+    const Handle(Geom_Curve)& theCurve, Standard_Integer theMaxDerivative, Standard_Real theU, gp_Vec& theD1,
+    gp_Vec& theD2 = dummyDerivative, gp_Vec& theD3 = dummyDerivative, gp_Vec& theD4 = dummyDerivative);
+
 
 
 //=======================================================================
@@ -319,10 +327,8 @@ void Geom_OffsetCurve::D2 (const Standard_Real U, Pnt& P, Vec& V1, Vec& V2) cons
 //purpose  : 
 //=======================================================================
 
-void Geom_OffsetCurve::D3 (const Standard_Real theU, Pnt& P, Vec& theV1, Vec& V2, Vec& V3) 
-const {
-
-
+void Geom_OffsetCurve::D3 (const Standard_Real theU, Pnt& theP, Vec& theV1, Vec& theV2, Vec& theV3) const
+{
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
 
@@ -336,137 +342,15 @@ const {
    //         (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
    //         (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
 
-  const Standard_Real aTol = gp::Resolution();
-
   Standard_Boolean IsDirectionChange = Standard_False;
 
-  basisCurve->D3 (theU, P, theV1, V2, V3);
-  Vec V4 = basisCurve->DN (theU, 4);
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = -basisCurve->DN (theU, anIndex + 1);
-      V3 = -basisCurve->DN (theU, anIndex + 2);
-      V4 = -basisCurve->DN (theU, anIndex + 3);
+  basisCurve->D3 (theU, theP, theV1, theV2, theV3);
+  Vec aV4 = basisCurve->DN (theU, 4);
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 4, theU, theV1, theV2, theV3, aV4);
 
-      IsDirectionChange = Standard_True;
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex + 1);
-      V3 = basisCurve->DN (theU, anIndex + 2);
-      V4 = basisCurve->DN (theU, anIndex + 3);
-      }
-    }//if(V1.Magnitude() <= aTol)
-
-
-  XYZ OffsetDir = direction.XYZ();
-  XYZ Ndir      = (theV1.XYZ()).Crossed (OffsetDir);
-  XYZ DNdir     = (V2.XYZ()).Crossed (OffsetDir);
-  XYZ D2Ndir    = (V3.XYZ()).Crossed (OffsetDir);
-  XYZ D3Ndir    = (V4.XYZ()).Crossed (OffsetDir);
-  Standard_Real R2  = Ndir.SquareModulus();
-  Standard_Real R   = Sqrt (R2);
-  Standard_Real R3  = R2 * R;
-  Standard_Real R4  = R2 * R2;
-  Standard_Real R5  = R3 * R2;
-  Standard_Real R6  = R3 * R3;
-  Standard_Real R7  = R5 * R2;
-  Standard_Real Dr  = Ndir.Dot (DNdir);
-  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
-  Standard_Real D3r = Ndir.Dot (D3Ndir) + 3.0 * DNdir.Dot (D2Ndir);
-  if (R7 <= gp::Resolution()) {
-    if (R6 <= gp::Resolution())  Geom_UndefinedDerivative::Raise();
-    // V3 = P"' (U) :
-    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R2));
-    D3Ndir.Subtract (DNdir.Multiplied (3.0 * ((D2r/R2) + (Dr*Dr/R4))));
-    D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 -
-                                 15.0*Dr*Dr*Dr/R6 - D3r));
-    D3Ndir.Multiply (offsetValue/R);
-
-    if(IsDirectionChange)
-      V3=-V3;
-
-    V3.Add (Vec(D3Ndir));
-
-    // V2 = P" (U) :
-    Standard_Real R4 = R2 * R2;
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
-    D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R4) - (D2r / R2)));
-    D2Ndir.Multiply (offsetValue / R);
-    V2.Add (Vec(D2Ndir));
-    // V1 = P' (U) :
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec(DNdir));
-  }
-  else {
-    // V3 = P"' (U) :
-    D3Ndir.Divide (R);
-    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R3));
-    D3Ndir.Subtract (DNdir.Multiplied ((3.0 * ((D2r/R3) + (Dr*Dr)/R5))));
-    D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - 
-                15.0*Dr*Dr*Dr/R7 - D3r));
-    D3Ndir.Multiply (offsetValue);
-    
-    if(IsDirectionChange)
-      V3=-V3;
-
-    V3.Add (Vec(D3Ndir));
-    
-    // V2 = P" (U) :
-    D2Ndir.Divide (R);
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R3));
-    D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R5) - (D2r / R3)));
-    D2Ndir.Multiply (offsetValue);
-    V2.Add (Vec(D2Ndir));
-    // V1 = P' (U) :
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-    theV1.Add (Vec(DNdir));
-  }
-  //P (U) :
-  D0(theU,P);
+  CSLib_Offset::D3(theP, theV1, theV2, theV3, aV4, direction, offsetValue,
+                   IsDirectionChange, theP, theV1, theV2, theV3);
 }
 
 
@@ -508,68 +392,13 @@ Vec Geom_OffsetCurve::DN (const Standard_Real U, const Standard_Integer N) const
 
 void  Geom_OffsetCurve::D0(const Standard_Real theU, gp_Pnt& theP,
                            gp_Pnt& thePbasis, gp_Vec& theV1basis)const 
-  {
-  const Standard_Real aTol = gp::Resolution();
+{
+  basisCurve->D1(theU, thePbasis, theV1basis);
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1basis.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 1, theU, theV1basis);
 
-  basisCurve->D1 (theU, thePbasis, theV1basis);
-  Standard_Real Ndu = theV1basis.Magnitude();
-  
-  if(Ndu <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    gp_Vec V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      Ndu = V.Magnitude();
-      }
-    while((Ndu <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    gp_Pnt P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    gp_Vec V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      theV1basis = -V;
-    else
-      theV1basis = V;
-
-    Ndu = theV1basis.Magnitude();
-    }//if(Ndu <= aTol)
-  
-  XYZ Ndir = (theV1basis.XYZ()).Crossed (direction.XYZ());
-  Standard_Real R = Ndir.Modulus();
-  if (R <= gp::Resolution())
-    Geom_UndefinedValue::Raise("Exception: Undefined normal vector "
-          "because tangent vector has zero-magnitude!");
-
-  Ndir.Multiply (offsetValue/R);
-  Ndir.Add (thePbasis.XYZ());
-  theP.SetXYZ(Ndir);
+  CSLib_Offset::D0(thePbasis, theV1basis, direction, offsetValue, IsDirectionChange, theP);
 }
 
 //=======================================================================
@@ -578,96 +407,21 @@ void  Geom_OffsetCurve::D0(const Standard_Real theU, gp_Pnt& theP,
 //=======================================================================
 
 void Geom_OffsetCurve::D1 ( const Standard_Real theU, 
-                            Pnt& P , Pnt& PBasis ,
-                            Vec& theV1, Vec& V1basis, Vec& V2basis) const {
+                            Pnt& theP , Pnt& thePBasis ,
+                            Vec& theV1, Vec& theV1basis, Vec& theV2basis) const {
 
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
 
    // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
 
-  const Standard_Real aTol = gp::Resolution();
+  basisCurve->D2 (theU, thePBasis, theV1basis, theV2basis);
 
-  basisCurve->D2 (theU, PBasis, V1basis, V2basis);
-  theV1 = V1basis;
-  Vec V2 = V2basis;
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1basis.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 2, theU, theV1basis, theV2basis);
 
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = - basisCurve->DN (theU, anIndex+1);
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex+1);
-      }
-    
-    V2basis = V2;
-    V1basis = theV1;
-    }//if(theV1.Magnitude() <= aTol)
-
-  XYZ OffsetDir = direction.XYZ();
-  XYZ Ndir  = (theV1.XYZ()).Crossed (OffsetDir);
-  XYZ DNdir = (V2.XYZ()).Crossed (OffsetDir);
-  Standard_Real R2 = Ndir.SquareModulus();
-  Standard_Real R  = Sqrt (R2);
-  Standard_Real R3 = R * R2;
-  Standard_Real Dr = Ndir.Dot (DNdir);
-  if (R3 <= gp::Resolution()) {
-    //We try another computation but the stability is not very good.
-    if (R2 <= gp::Resolution()) Geom_UndefinedDerivative::Raise();
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec(DNdir));
-  }
-  else {
-    // Same computation as IICURV in EUCLID-IS because the stability is
-    // better
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue * Dr/R3));        
-    theV1.Add (Vec(DNdir));
-  }
-  D0(theU,P);
+  CSLib_Offset::D1(thePBasis, theV1basis, theV2basis, direction, offsetValue, IsDirectionChange, theP, theV1);
 }
 
 
@@ -676,11 +430,11 @@ void Geom_OffsetCurve::D1 ( const Standard_Real theU,
 //purpose  : 
 //=======================================================================
 
-void Geom_OffsetCurve::D2 (const Standard_Real theU, 
-                           Pnt& P      , Pnt& PBasis ,
-                           Vec& theV1     , Vec& V2     , 
-                           Vec& V1basis, Vec& V2basis, Vec& V3basis) const {
-
+void Geom_OffsetCurve::D2 (const Standard_Real theU,
+                           Pnt& theP, Pnt& thePBasis,
+                           Vec& theV1, Vec& theV2,
+                           Vec& theV1basis, Vec& theV2basis, Vec& theV3basis) const
+{
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction)
 
@@ -689,129 +443,15 @@ void Geom_OffsetCurve::D2 (const Standard_Real theU,
    // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
    //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
 
-  const Standard_Real aTol = gp::Resolution();
-
   Standard_Boolean IsDirectionChange = Standard_False;
 
-  basisCurve->D3 (theU, PBasis, V1basis, V2basis, V3basis);
+  basisCurve->D3 (theU, thePBasis, theV1basis, theV2basis, theV3basis);
 
-  theV1  = V1basis;
-  V2     = V2basis;
-  Vec V3 = V3basis;
-  
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = -basisCurve->DN (theU, anIndex+1);
-      V3 = -basisCurve->DN (theU, anIndex + 2);
+  if(theV1basis.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 3, theU, theV1basis, theV2basis, theV3basis);
 
-      IsDirectionChange = Standard_True;
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex+1);
-      V3 = basisCurve->DN (theU, anIndex + 2);
-      }
-    
-    V2basis = V2;
-    V1basis = theV1;
-    }//if(V1.Magnitude() <= aTol)
-  
-  XYZ OffsetDir = direction.XYZ();
-  XYZ Ndir   = (theV1.XYZ()).Crossed (OffsetDir);
-  XYZ DNdir  = (V2.XYZ()).Crossed (OffsetDir);
-  XYZ D2Ndir = (V3.XYZ()).Crossed (OffsetDir);
-  Standard_Real R2    = Ndir.SquareModulus();
-  Standard_Real R     = Sqrt (R2);
-  Standard_Real R3    = R2 * R;
-  Standard_Real R4    = R2 * R2;
-  Standard_Real R5    = R3 * R2;
-  Standard_Real Dr    = Ndir.Dot (DNdir);
-  Standard_Real D2r   = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
-  
-  if (R5 <= gp::Resolution()) {
-    //We try another computation but the stability is not very good
-    //dixit ISG.
-    if (R4 <= gp::Resolution())  Geom_UndefinedDerivative::Raise();
-    // V2 = P" (U) :
-    Standard_Real R4 = R2 * R2;
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
-    D2Ndir.Add (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
-    D2Ndir.Multiply (offsetValue / R);
-    
-    if(IsDirectionChange)
-      V2=-V2;
-
-    V2.Add (Vec(D2Ndir));
-        
-    // V1 = P' (U) :
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec(DNdir));
-  }
-  else {
-    // Same computation as IICURV in EUCLID-IS because the stability is
-    // better.
-    // V2 = P" (U) :
-    D2Ndir.Multiply (offsetValue/R);
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
-    D2Ndir.Add (Ndir.Multiplied (
-                     offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))
-                                     )
-                    );
-    
-    if(IsDirectionChange)
-      V2=-V2;
-
-    V2.Add (Vec(D2Ndir));
-    
-    // V1 = P' (U) :
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-    theV1.Add (Vec(DNdir));
-  }
-  //P (U) :
-  D0(theU,P);
+  CSLib_Offset::D2(thePBasis, theV1basis, theV2basis, theV3basis, direction, offsetValue,
+                   IsDirectionChange, theP, theV1, theV2);
 }
 
 
@@ -929,3 +569,57 @@ GeomAbs_Shape Geom_OffsetCurve::GetBasisCurveContinuity() const
 {
   return myBasisCurveContinuity;
 }
+
+
+// ============= Auxiliary functions ===================
+Standard_Boolean AdjustDerivative(const Handle(Geom_Curve)& theCurve, Standard_Integer theMaxDerivative,
+                                  Standard_Real theU, gp_Vec& theD1, gp_Vec& theD2,
+                                  gp_Vec& theD3, gp_Vec& theD4)
+{
+  static const Standard_Real aTol = gp::Resolution();
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  const Standard_Real anUinfium   = theCurve->FirstParameter();
+  const Standard_Real anUsupremum = theCurve->LastParameter();
+
+  const Standard_Real DivisionFactor = 1.e-3;
+  Standard_Real du;
+  if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
+    du = 0.0;
+  else
+    du = anUsupremum - anUinfium;
+
+  const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
+
+  //Derivative is approximated by Taylor-series
+  Standard_Integer anIndex = 1; //Derivative order
+  gp_Vec V;
+
+  do
+  {
+    V =  theCurve->DN(theU, ++anIndex);
+  }
+  while((V.SquareMagnitude() <= aTol) && anIndex < maxDerivOrder);
+
+  Standard_Real u;
+
+  if(theU-anUinfium < aDelta)
+    u = theU+aDelta;
+  else
+    u = theU-aDelta;
+
+  gp_Pnt P1, P2;
+  theCurve->D0(Min(theU, u), P1);
+  theCurve->D0(Max(theU, u), P2);
+
+  gp_Vec V1(P1, P2);
+  IsDirectionChange = V.Dot(V1) < 0.0;
+  Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
+
+  theD1 = V * aSign;
+  gp_Vec* aDeriv[3] = {&theD2, &theD3, &theD4};
+  for (Standard_Integer i = 1; i < theMaxDerivative; i++)
+    *(aDeriv[i-1]) = theCurve->DN(theU, anIndex + i) * aSign;
+
+  return IsDirectionChange;
+}
index 2f28155..b2fc9ba 100644 (file)
@@ -397,6 +397,10 @@ void Geom_SurfaceOfRevolution::D1
       XYZ Vdir = direction.XYZ();                        //Vdir
       Q.Subtract(C);                                     //CQ
       XYZ VcrossCQ  = Vdir.Crossed (Q);                  //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
       XYZ VcrossDQv = Vdir.Crossed (DQv);                //(Vdir^Q')
       XYZ VdotCQ    = Vdir.Multiplied (Vdir.Dot(Q));     //(Vdir.CQ)Vdir
       XYZ VdotDQv   = Vdir.Multiplied (Vdir.Dot(DQv));   //(Vdir.Q')Vdir
@@ -463,6 +467,10 @@ void Geom_SurfaceOfRevolution::D2
       XYZ Vdir  = direction.XYZ();                          //Vdir
       Q.Subtract(C);                                        //CQ
       XYZ VcrossCQ   = Vdir.Crossed (Q);                    //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
       XYZ VcrossD1Qv = Vdir.Crossed (D1Qv);                 //(Vdir^Q')
       XYZ VcrossD2Qv = Vdir.Crossed (D2Qv);                 //(Vdir^Q")
       XYZ VdotCQ     = Vdir.Multiplied (Vdir.Dot(Q));       //(Vdir.CQ)Vdir
@@ -558,6 +566,10 @@ void Geom_SurfaceOfRevolution::D3
       XYZ Vdir  = direction.XYZ();                          //Vdir
       Q.Subtract(C);                                        //CQ
       XYZ VcrossCQ   = Vdir.Crossed (Q);                    //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
       XYZ VcrossD1Qv = Vdir.Crossed (D1Qv);                 //(Vdir^Q')
       XYZ VcrossD2Qv = Vdir.Crossed (D2Qv);                 //(Vdir^Q")
       XYZ VcrossD3Qv = Vdir.Crossed (D3Qv);                 //(Vdir^Q''')
@@ -763,6 +775,11 @@ void Geom_SurfaceOfRevolution::LocalD1 (const Standard_Real    U,
         XYZ Vdir = direction.XYZ();                        //Vdir
         Q.Subtract(C);                                     //CQ
         XYZ VcrossCQ  = Vdir.Crossed (Q);                  //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
+
         XYZ VcrossDQv = Vdir.Crossed (DQv);                //(Vdir^Q')
         XYZ VdotCQ    = Vdir.Multiplied (Vdir.Dot(Q));     //(Vdir.CQ)Vdir
         XYZ VdotDQv   = Vdir.Multiplied (Vdir.Dot(DQv));   //(Vdir.Q')Vdir
@@ -818,6 +835,11 @@ void Geom_SurfaceOfRevolution::LocalD2 (const Standard_Real    U,
          XYZ Vdir  = direction.XYZ();                           //Vdir
          Q.Subtract(C);                                         //CQ
          XYZ VcrossCQ   = Vdir.Crossed (Q);                     //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
+
          XYZ VcrossD1Qv = Vdir.Crossed (D1Qv);                  //(Vdir^Q')
          XYZ VcrossD2Qv = Vdir.Crossed (D2Qv);                  //(Vdir^Q")
          XYZ VdotCQ     = Vdir.Multiplied (Vdir.Dot(Q));        //(Vdir.CQ)Vdir
@@ -896,6 +918,11 @@ void Geom_SurfaceOfRevolution::LocalD3 (const Standard_Real    U,
          XYZ Vdir  = direction.XYZ();                          //Vdir
          Q.Subtract(C);                                        //CQ
          XYZ VcrossCQ   = Vdir.Crossed (Q);                    //Vdir^CQ
+      // If the point is placed on the axis of revolution then derivatives on U are undefined.
+      // Manually set them to zero.
+      if (VcrossCQ.SquareModulus() < Precision::SquareConfusion())
+        VcrossCQ.SetCoord(0.0, 0.0, 0.0);
+
          XYZ VcrossD1Qv = Vdir.Crossed (D1Qv);                 //(Vdir^Q')
          XYZ VcrossD2Qv = Vdir.Crossed (D2Qv);                 //(Vdir^Q")
          XYZ VcrossD3Qv = Vdir.Crossed (D3Qv);                 //(Vdir^Q''')
index 0196187..319ee5b 100644 (file)
@@ -124,8 +124,7 @@ uses  Array1OfInteger      from TColStd,
       Vec2d                from gp,
       BSplKnotDistribution from GeomAbs,
       Geometry             from Geom2d,
-      Shape                from GeomAbs,
-      Mutex                from Standard
+      Shape                from GeomAbs
 
 raises ConstructionError   from Standard,
        DimensionError      from Standard,
@@ -642,17 +641,6 @@ is
         --  Returns True if the weights are not identical.
         --  The tolerance criterion is Epsilon of the class Real.
     
-  IsCacheValid(me;  Parameter : Real) returns Boolean
-  
-        ---Purpose :
-        --           Tells whether the Cache is valid for the
-        --           given parameter 
-        -- Warnings : the parameter must be normalized within
-        -- the period if the curve is periodic. Otherwise
-        -- the answer will be false
-        -- 
-        is static private;
-  
   Continuity (me)  returns Shape from GeomAbs;
         --- Purpose :
         --  Returns the global continuity of the curve :
@@ -843,6 +831,11 @@ is
      raises DimensionError;
         --- Purpose :
         --  Raised if the length of K is not equal to the number of knots.
+  Knots (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : returns the knot values of the B-spline curve;
+        ---C++ : return const &
+  is static;
 
 
   KnotSequence (me; K : out Array1OfReal from TColStd)
@@ -854,6 +847,15 @@ is
      raises DimensionError;
         --- Purpose :
         --  Raised if the length of K is not equal to NbPoles + Degree + 1
+  KnotSequence (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : Returns the knots sequence.
+        --  In this sequence the knots with a multiplicity greater than 1
+        --  are repeated. 
+        -- Example :
+        --  K = {k1, k1, k1, k2, k3, k3, k4, k4, k4}
+        ---C++ : return const &
+  is static;
 
 
 
@@ -919,6 +921,11 @@ is
      raises DimensionError;
         --- Purpose :
         --  Raised if the length of M is not equal to NbKnots.
+  Multiplicities (me)
+  returns Array1OfInteger from TColStd
+        ---Purpose : returns the multiplicity of the knots of the curve.
+        ---C++ : return const &
+  is static;
 
 
   NbKnots (me)  returns Integer;
@@ -942,6 +949,11 @@ is
      raises DimensionError;
         --- Purpose : 
         --  Raised if the length of P is not equal to the number of poles.
+  Poles (me)
+  returns Array1OfPnt2d from TColgp
+        ---Purpose : Returns the poles of the B-spline curve;
+        ---C++ : return const &
+  is static;
 
 
   StartPoint (me)  returns Pnt2d;
@@ -963,6 +975,11 @@ is
      raises DimensionError;
         --- Purpose :
         --  Raised if the length of W is not equal to NbPoles.
+  Weights (me)
+  returns Array1OfReal from TColStd
+        ---Purpose : Returns the weights of the B-spline curve;
+        ---C++ : return const &
+  is static;
 
 
 
@@ -996,17 +1013,8 @@ is
   UpdateKnots(me : mutable)
        ---Purpose: Recompute  the  flatknots,  the knotsdistribution, the continuity.
   is static private;
-  
-  InvalidateCache(me : mutable)
-       ---Purpose : Invalidates the cache. This has to be private this has to be private
-      is static private;
 
   
-  ValidateCache(me : mutable ; Parameter : Real) 
-  
-    is static private;
-       ---Purpose : updates the cache and validates it
-             
 fields
 
   rational  : Boolean;
@@ -1019,35 +1027,7 @@ fields
   flatknots : HArray1OfReal from TColStd;
   knots     : HArray1OfReal from TColStd;
   mults     : HArray1OfInteger from TColStd;
-  cachepoles      : HArray1OfPnt2d     from TColgp;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1] see below
-  cacheweights    : HArray1OfReal    from TColStd;
-  -- Taylor expansion of the poles function, in homogeneous
-  -- form if the curve is rational. The taylor expansion
-  -- is normalized so that the span corresponds to
-  -- [0 1] see below
-  validcache      : Integer;
-  -- = 1 the cache is valid 
-  -- = 0 the cache is invalid
-  parametercache    : Real;
-  -- Parameter at which the Taylor expension is stored in 
-  -- the cache
-  spanlenghtcache   : Real;
-  -- Since the Taylor expansion is normalized in the 
-  -- cache to evaluate the cache one has to use
-  -- (Parameter - refcache) * normcache 
-  spanindexcache : Integer;
-  -- the span for which the cache is valid if 
-  -- validcache is 1 
-
-  -- usefull to evaluate the parametric resolution
   maxderivinv   : Real from Standard;
   maxderivinvok : Boolean from Standard;
 
-  myMutex       : Mutex from Standard;
-  -- protected bspline-cache
-
 end;
index a9594ed..fa3ace8 100644 (file)
@@ -123,12 +123,11 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve
 {
   // check
   
-  CheckCurveData (Poles,
-                 Knots,
-                 Mults,
-                 Degree,
-                 Periodic);
-
+  CheckCurveData(Poles,
+                 Knots,
+                 Mults,
+                 Degree,
+                 Periodic);
 
   // copy arrays
 
@@ -142,10 +141,6 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve
   mults->ChangeArray1() = Mults;
 
   UpdateKnots();
-  cachepoles = new TColgp_HArray1OfPnt2d(1,Degree + 1);
-  parametercache = 0.0e0 ;
-  spanlenghtcache = 0.0e0 ;
-  spanindexcache = 0 ;
 }
 
 //=======================================================================
@@ -169,11 +164,11 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve
 
   // check
   
-  CheckCurveData (Poles,
-                 Knots,
-                 Mults,
-                 Degree,
-                 Periodic);
+  CheckCurveData(Poles,
+                 Knots,
+                 Mults,
+                 Degree,
+                 Periodic);
 
   if (Weights.Length() != Poles.Length())
     Standard_ConstructionError::Raise("Geom2d_BSplineCurve :Weights and Poles array size mismatch");
@@ -192,11 +187,9 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve
   
   poles =  new TColgp_HArray1OfPnt2d(1,Poles.Length());
   poles->ChangeArray1() = Poles;
-  cachepoles = new TColgp_HArray1OfPnt2d(1,Degree + 1);
   if (rational) {
     weights =  new TColStd_HArray1OfReal(1,Weights.Length());
     weights->ChangeArray1() = Weights;
-    cacheweights  = new TColStd_HArray1OfReal(1,Degree + 1);
   }
 
   knots = new TColStd_HArray1OfReal(1,Knots.Length());
@@ -206,10 +199,6 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve
   mults->ChangeArray1() = Mults;
 
   UpdateKnots();
-
-  parametercache = 0.0e0 ;
-  spanlenghtcache = 0.0e0 ;
-  spanindexcache = 0 ;
 }
 
 //=======================================================================
@@ -1090,7 +1079,6 @@ void Geom2d_BSplineCurve::SetPole
   if (Index < 1 || Index > poles->Length()) Standard_OutOfRange::Raise("BSpline curve : SetPole : index and #pole mismatch");
   poles->SetValue (Index, P);
   maxderivinvok = 0;
-  InvalidateCache();
 }
 
 //=======================================================================
@@ -1140,7 +1128,6 @@ void Geom2d_BSplineCurve::SetWeight
   }
   
   maxderivinvok = 0;
-  InvalidateCache() ;
 }
 
 //=======================================================================
@@ -1149,11 +1136,11 @@ void Geom2d_BSplineCurve::SetWeight
 //=======================================================================
 
 void Geom2d_BSplineCurve::MovePoint(const Standard_Real U,
-                                   const gp_Pnt2d& P,
-                                   const Standard_Integer Index1,
-                                   const Standard_Integer Index2,
-                                   Standard_Integer& FirstModifiedPole,
-                                   Standard_Integer& LastmodifiedPole)
+                                    const gp_Pnt2d& P,
+                                    const Standard_Integer Index1,
+                                    const Standard_Integer Index2,
+                                    Standard_Integer& FirstModifiedPole,
+                                    Standard_Integer& LastmodifiedPole)
 {
   if (Index1 < 1 || Index1 > poles->Length() || 
       Index2 < 1 || Index2 > poles->Length() || Index1 > Index2) {
@@ -1164,12 +1151,11 @@ void Geom2d_BSplineCurve::MovePoint(const Standard_Real U,
   D0(U, P0);
   gp_Vec2d Displ(P0, P);
   BSplCLib::MovePoint(U, Displ, Index1, Index2, deg, rational, poles->Array1(), 
-                     weights->Array1(), flatknots->Array1(), 
-                     FirstModifiedPole, LastmodifiedPole, npoles);
+                      weights->Array1(), flatknots->Array1(), 
+                      FirstModifiedPole, LastmodifiedPole, npoles);
   if (FirstModifiedPole) {
     poles->ChangeArray1() = npoles;
     maxderivinvok = 0;
-    InvalidateCache() ;
   }
 }
 
@@ -1222,7 +1208,6 @@ MovePointAndTangent(const Standard_Real    U,
   if (!ErrorStatus) {
     poles->ChangeArray1() = new_poles;
     maxderivinvok = 0;
-    InvalidateCache() ;
   }
 }
 
@@ -1266,33 +1251,6 @@ void Geom2d_BSplineCurve::UpdateKnots()
       default :  smooth = GeomAbs_C3;   break;
     }
   }
-  InvalidateCache() ;
-}
-
-//=======================================================================
-//function : Invalidate the Cache
-//purpose  : as the name says
-//=======================================================================
-
-void Geom2d_BSplineCurve::InvalidateCache() 
-{
-  validcache = 0 ;
-}
-
-//=======================================================================
-//function : check if the Cache is valid
-//purpose  : as the name says
-//=======================================================================
-
-Standard_Boolean Geom2d_BSplineCurve::IsCacheValid
-(const Standard_Real  U)  const 
-{
-  //Roman Lygin 26.12.08, see comments in Geom_BSplineCurve::IsCacheValid()
-  Standard_Real aDelta = U - parametercache;
-
-  return ( validcache &&
-      (aDelta >= 0.0e0) &&
-      ((aDelta < spanlenghtcache) || (spanindexcache == flatknots->Upper() - deg)) );
 }
 
 //=======================================================================
@@ -1315,83 +1273,3 @@ void Geom2d_BSplineCurve::PeriodicNormalization(Standard_Real&  Parameter) const
   }
 }
 
-//=======================================================================
-//function : Validate the Cache
-//purpose  : that is compute the cache so that it is valid
-//=======================================================================
-
-void Geom2d_BSplineCurve::ValidateCache(const Standard_Real  Parameter) 
-{
-  Standard_Real NewParameter ;
-  Standard_Integer LocalIndex = 0 ;
-  //
-  // check if the degree did not change
-  //
-  if (cachepoles->Upper() < deg + 1)
-    cachepoles = new TColgp_HArray1OfPnt2d(1,deg + 1);
-  if (rational)
-  {
-    if (cacheweights.IsNull() || cacheweights->Upper() < deg + 1)
-     cacheweights  = new TColStd_HArray1OfReal(1,deg + 1);
-  }
-  else if (!cacheweights.IsNull())
-    cacheweights.Nullify();
-
-  BSplCLib::LocateParameter(deg,
-                           (flatknots->Array1()),
-                           (BSplCLib::NoMults()),
-                           Parameter,
-                           periodic,
-                           LocalIndex,
-                           NewParameter);
-  spanindexcache = LocalIndex ;
-  if (Parameter == flatknots->Value(LocalIndex + 1)) {
-    
-    LocalIndex += 1 ;
-    parametercache = flatknots->Value(LocalIndex) ;
-    if (LocalIndex == flatknots->Upper() - deg) {
-      //
-      // for the last span if the parameter is outside of 
-      // the domain of the curve than use the last knot
-      // and normalize with the last span Still set the
-      // spanindexcache to flatknots->Upper() - deg so that
-      // the IsCacheValid will know for sure we are extending
-      // the Bspline 
-      //
-      
-      spanlenghtcache = flatknots->Value(LocalIndex - 1) - parametercache ;
-    }
-    else {
-      spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
-    }
-  }
-  else {
-    parametercache = flatknots->Value(LocalIndex) ;
-    spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
-  }
-  
-  if  (rational) {
-    BSplCLib::BuildCache(parametercache,
-                        spanlenghtcache,
-                        periodic,
-                        deg,
-                        (flatknots->Array1()),
-                        poles->Array1(),
-                        weights->Array1(),
-                        cachepoles->ChangeArray1(),
-                        cacheweights->ChangeArray1()) ;
-  }
-  else {
-    BSplCLib::BuildCache(parametercache,
-                        spanlenghtcache,
-                        periodic,
-                        deg,
-                        (flatknots->Array1()),
-                        poles->Array1(),
-                        *((TColStd_Array1OfReal*) NULL),
-                        cachepoles->ChangeArray1(),
-                        *((TColStd_Array1OfReal*) NULL)) ;
-  }
-  validcache = 1 ;
-}
-
index b80b415..0a5d6aa 100644 (file)
@@ -30,7 +30,7 @@
 #include <Standard_OutOfRange.hxx>
 #include <Standard_DomainError.hxx>
 #include <Standard_RangeError.hxx>
-#include <Standard_Mutex.hxx>
+#include <Precision.hxx>
 
 #define  POLES    (poles->Array1())
 #define  KNOTS    (knots->Array1())
@@ -183,36 +183,28 @@ Standard_Integer Geom2d_BSplineCurve::Degree () const
 //purpose  : 
 //=======================================================================
 
-void Geom2d_BSplineCurve::D0 ( const Standard_Real U, 
-                             gp_Pnt2d& P) const
+void Geom2d_BSplineCurve::D0(const Standard_Real U, 
+                                   gp_Pnt2d&     P) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom2d_BSplineCurve* MyCurve = (Geom2d_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if (!IsCacheValid(NewU))
-    MyCurve->ValidateCache(NewU);
-  
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD0(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P) ;
+    BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P);
   }
-  else {
-    BSplCLib::CacheD0(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     BSplCLib::NoWeights(),
-                     P) ;
+  else 
+  {
+    BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P);
   }
 }
 
@@ -222,39 +214,29 @@ void Geom2d_BSplineCurve::D0 ( const Standard_Real U,
 //purpose  : 
 //=======================================================================
 
-void Geom2d_BSplineCurve::D1 (const Standard_Real U,
-                             gp_Pnt2d& P,
-                             gp_Vec2d& V1) const
+void Geom2d_BSplineCurve::D1(const Standard_Real U,
+                                   gp_Pnt2d&     P,
+                                   gp_Vec2d&     V1) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom2d_BSplineCurve* MyCurve = (Geom2d_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if (!IsCacheValid(NewU))
-    MyCurve->ValidateCache(NewU);
-  
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD1(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P,
-                     V1) ;
+    BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1);
   }
-  else {
-    BSplCLib::CacheD1(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     BSplCLib::NoWeights(),
-                     P,
-                     V1) ;
+  else 
+  {
+    BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P, V1);
   }
 }
 
@@ -263,42 +245,30 @@ void Geom2d_BSplineCurve::D1 (const Standard_Real U,
 //purpose  : 
 //=======================================================================
 
-void Geom2d_BSplineCurve::D2 (const Standard_Real U ,
-                             gp_Pnt2d& P ,
-                             gp_Vec2d& V1,
-                             gp_Vec2d& V2 ) const
+void Geom2d_BSplineCurve::D2(const Standard_Real U,
+                                   gp_Pnt2d&     P,
+                                   gp_Vec2d&     V1,
+                                   gp_Vec2d&     V2) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom2d_BSplineCurve* MyCurve = (Geom2d_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if (!IsCacheValid(NewU))
-    MyCurve->ValidateCache(NewU);
-  
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD2(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P,
-                     V1,
-                     V2) ;
+    BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2);
   }
-  else {
-    BSplCLib::CacheD2(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     BSplCLib::NoWeights(),
-                     P,
-                     V1,
-                     V2) ;
+  else 
+  {
+    BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2);
   }
 }
 
@@ -307,45 +277,31 @@ void Geom2d_BSplineCurve::D2 (const Standard_Real U ,
 //purpose  : 
 //=======================================================================
 
-void Geom2d_BSplineCurve::D3  (const Standard_Real U ,
-                              gp_Pnt2d& P ,
-                              gp_Vec2d& V1,
-                              gp_Vec2d& V2,
-                              gp_Vec2d& V3 ) const
+void Geom2d_BSplineCurve::D3(const Standard_Real U,
+                                   gp_Pnt2d&     P,
+                                   gp_Vec2d&     V1,
+                                   gp_Vec2d&     V2,
+                                   gp_Vec2d&     V3) const
 {
-  Standard_Real NewU(U);
-  PeriodicNormalization(NewU);
-
-  Geom2d_BSplineCurve* MyCurve = (Geom2d_BSplineCurve *) this;
-  Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
-
-  if (!IsCacheValid(NewU))
-    MyCurve->ValidateCache(NewU);
-  
-  if(rational)
+  Standard_Integer aSpanIndex = 0;
+  Standard_Real aNewU(U);
+  PeriodicNormalization(aNewU);
+  BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
+  if (aNewU < knots->Value(aSpanIndex))
+    aSpanIndex--;
+  if (rational) 
   {
-    BSplCLib::CacheD3(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     cacheweights->Array1(),
-                     P,
-                     V1,
-                     V2,
-                     V3) ;
+    BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
+      weights->Array1(),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2, V3);
   }
-  else {
-    BSplCLib::CacheD3(NewU,
-                     deg,
-                     parametercache,
-                     spanlenghtcache,
-                     (cachepoles->Array1()),
-                     BSplCLib::NoWeights(),
-                     P,
-                     V1,
-                     V2,
-                     V3) ;
+  else 
+  {
+    BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
+      *((TColStd_Array1OfReal*) NULL),
+      knots->Array1(), mults->Array1(),
+      P, V1, V2, V3);
   }
 }
 
@@ -354,20 +310,20 @@ void Geom2d_BSplineCurve::D3  (const Standard_Real U ,
 //purpose  : 
 //=======================================================================
 
-gp_Vec2d Geom2d_BSplineCurve::DN  (const Standard_Real    U,
-                                  const Standard_Integer N ) const
+gp_Vec2d Geom2d_BSplineCurve::DN(const Standard_Real    U,
+                                 const Standard_Integer N) const
 {
   gp_Vec2d V;
 
   if ( rational ) {
     BSplCLib::DN(U,N,0,deg,periodic,POLES,
-                weights->Array1(),
-                FKNOTS,FMULTS,V);
+      weights->Array1(),
+      FKNOTS,FMULTS,V);
   }
-  else {  
+  else {
     BSplCLib::DN(U,N,0,deg,periodic,POLES,
-                *((TColStd_Array1OfReal*) NULL),
-                FKNOTS,FMULTS,V);
+      *((TColStd_Array1OfReal*) NULL),
+      FKNOTS,FMULTS,V);
   }
   return V;
 }
@@ -440,6 +396,11 @@ void Geom2d_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
   K = knots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom2d_BSplineCurve::Knots() const
+{
+  return knots->Array1();
+}
+
 //=======================================================================
 //function : KnotSequence
 //purpose  : 
@@ -452,6 +413,11 @@ void Geom2d_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
   K = flatknots->Array1();
 }
 
+const TColStd_Array1OfReal& Geom2d_BSplineCurve::KnotSequence() const
+{
+  return flatknots->Array1();
+}
+
 //=======================================================================
 //function : LastUKnotIndex
 //purpose  : 
@@ -676,6 +642,11 @@ void Geom2d_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
   M = mults->Array1();
 }
 
+const TColStd_Array1OfInteger& Geom2d_BSplineCurve::Multiplicities() const
+{
+  return mults->Array1();
+}
+
 //=======================================================================
 //function : NbKnots
 //purpose  : 
@@ -716,6 +687,11 @@ void Geom2d_BSplineCurve::Poles (TColgp_Array1OfPnt2d& P) const
   P = poles->Array1();
 }
 
+const TColgp_Array1OfPnt2d& Geom2d_BSplineCurve::Poles() const
+{
+  return poles->Array1();
+}
+
 //=======================================================================
 //function : StartPoint
 //purpose  : 
@@ -764,6 +740,13 @@ void Geom2d_BSplineCurve::Weights
   }
 }
 
+const TColStd_Array1OfReal& Geom2d_BSplineCurve::Weights() const
+{
+  if (IsRational())
+    return weights->Array1();
+  return BSplCLib::NoWeights();
+}
+
 //=======================================================================
 //function : IsRational
 //purpose  : 
@@ -786,7 +769,6 @@ void Geom2d_BSplineCurve::Transform
   for (Standard_Integer I = 1; I <= CPoles.Length(); I++)  
     CPoles (I).Transform (T);
 
-  InvalidateCache();
   //  maxderivinvok = 0;
 }
 
index 07126a7..79d86ba 100644 (file)
@@ -23,6 +23,7 @@
 #include <Standard_ConstructionError.hxx>
 #include <Standard_RangeError.hxx>
 #include <Standard_NotImplemented.hxx>
+#include <CSLib_Offset.hxx>
 #include <Geom2d_UndefinedDerivative.hxx>
 #include <Geom2d_UndefinedValue.hxx>
 #include <Geom2d_Line.hxx>
@@ -54,6 +55,14 @@ static const int maxDerivOrder = 3;
 static const Standard_Real MinStep   = 1e-7;
 static const Standard_Real MyAngularToleranceForG1 = Precision::Angular();
 
+static gp_Vec2d dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
+
+// Recalculate derivatives in the singular point
+// Returns true if the direction of derivatives is changed
+static Standard_Boolean AdjustDerivative(const Handle(Geom2d_Curve)& theCurve, Standard_Integer theMaxDerivative,
+                                         Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2 = dummyDerivative,
+                                         gp_Vec2d& theD3 = dummyDerivative, gp_Vec2d& theD4 = dummyDerivative);
+
 //=======================================================================
 //function : Copy
 //purpose  : 
@@ -211,163 +220,38 @@ GeomAbs_Shape Geom2d_OffsetCurve::Continuity () const
 //purpose  : 
 //=======================================================================
 
-void Geom2d_OffsetCurve::D0 (const Standard_Real   theU,
-                                  Pnt2d& theP ) const 
+void Geom2d_OffsetCurve::D0 (const Standard_Real theU,
+                                   Pnt2d&        theP) const
   {
-  const Standard_Real aTol = gp::Resolution();
-
   Vec2d vD1;
-
   basisCurve->D1 (theU, theP, vD1);
-  Standard_Real Ndu = vD1.Magnitude();
 
-  if(Ndu <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec2d V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      Ndu = V.Magnitude();
-      }
-    while((Ndu <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt2d P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec2d V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      vD1 = -V;
-    else
-      vD1 = V;
-
-    Ndu = vD1.Magnitude();
-    }//if(Ndu <= aTol)
-
-  if (Ndu <= aTol)
-    Geom2d_UndefinedValue::Raise("Exception: Undefined normal vector "
-          "because tangent vector has zero-magnitude!");
-  
-  Standard_Real A = vD1.Y();
-  Standard_Real B = - vD1.X();
-  A = A * offsetValue/Ndu;
-  B = B * offsetValue/Ndu;
-  theP.SetCoord(theP.X() + A, theP.Y() + B);
-  }
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(vD1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 1, theU, vD1);
+
+  CSLib_Offset::D0(theP, vD1, offsetValue, IsDirectionChange, theP);
+}
 
 //=======================================================================
 //function : D1
 //purpose  : 
 //=======================================================================
-void Geom2d_OffsetCurve::D1 (const Standard_Real theU, Pnt2d& P, Vec2d& theV1) const
-  {
+void Geom2d_OffsetCurve::D1 (const Standard_Real theU, Pnt2d& theP, Vec2d& theV1) const
+{
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ Z|| and Ndir = P' ^ Z
 
    // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
 
-  const Standard_Real aTol = gp::Resolution();
-
   Vec2d V2;
-  basisCurve->D2 (theU, P, theV1, V2);
-  
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec2d V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt2d P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec2d V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = - basisCurve->DN (theU, anIndex+1);
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex+1);
-      }
-    }//if(theV1.Magnitude() <= aTol)
-
-  XY Ndir  (theV1.Y(), -theV1.X());
-  XY DNdir (V2.Y(), -V2.X());
-  Standard_Real R2 = Ndir.SquareModulus();
-  Standard_Real R  = Sqrt (R2);
-  Standard_Real R3 = R * R2;
-  Standard_Real Dr = Ndir.Dot (DNdir);
-  if (R3 <= gp::Resolution()) {
-    //We try another computation but the stability is not very good.
-    if (R2 <= gp::Resolution()) Geom2d_UndefinedDerivative::Raise();
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec2d(DNdir));
-  }
-  else {
-    // Same computation as IICURV in EUCLID-IS because the stability is
-    // better
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-    theV1.Add (Vec2d(DNdir));
-  }
+  basisCurve->D2 (theU, theP, theV1, V2);
 
-  D0(theU, P);
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 2, theU, theV1, V2);
+
+  CSLib_Offset::D1(theP, theV1, V2, offsetValue, IsDirectionChange, theP, theV1);
 }
 
 //=======================================================================
@@ -376,8 +260,8 @@ void Geom2d_OffsetCurve::D1 (const Standard_Real theU, Pnt2d& P, Vec2d& theV1) c
 //=======================================================================
 
 void Geom2d_OffsetCurve::D2 (const Standard_Real theU, 
-                                  Pnt2d& P, 
-                                  Vec2d& theV1, Vec2d& V2) const 
+                                   Pnt2d& theP, 
+                                   Vec2d& theV1, Vec2d& theV2) const 
 {
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ Z|| and Ndir = P' ^ Z
@@ -388,124 +272,13 @@ void Geom2d_OffsetCurve::D2 (const Standard_Real theU,
    //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
 
   Vec2d V3;
-  basisCurve->D3 (theU, P, theV1, V2, V3);
-
-  const Standard_Real aTol = gp::Resolution();
+  basisCurve->D3 (theU, theP, theV1, theV2, V3);
 
   Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 3, theU, theV1, theV2, V3);
 
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec2d V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt2d P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec2d V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = -basisCurve->DN (theU, anIndex+1);
-      V3 = -basisCurve->DN (theU, anIndex + 2);
-
-      IsDirectionChange = Standard_True;
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex+1);
-      V3 = basisCurve->DN (theU, anIndex + 2);
-      }
-    }//if(V1.Magnitude() <= aTol)
-
-  XY Ndir (theV1.Y(), -theV1.X());
-  XY DNdir (V2.Y(), -V2.X());
-  XY D2Ndir (V3.Y(), -V3.X());
-  Standard_Real R2  = Ndir.SquareModulus();
-  Standard_Real R   = Sqrt (R2);
-  Standard_Real R3  = R2 * R;
-  Standard_Real R4  = R2 * R2;
-  Standard_Real R5  = R3 * R2;
-  Standard_Real Dr  = Ndir.Dot (DNdir);
-  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
-  if (R5 <= gp::Resolution())
-    {
-    //We try another computation but the stability is not very good
-    //dixit ISG.
-    if (R4 <= gp::Resolution())
-      {
-      Geom2d_UndefinedDerivative::Raise();
-      }
-    // V2 = P" (U) :
-    Standard_Real R4 = R2 * R2;
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
-    D2Ndir.Add (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
-    D2Ndir.Multiply (offsetValue / R);
-
-    if(IsDirectionChange)
-      V2=-V2;
-
-    V2.Add (Vec2d(D2Ndir));
-
-    // V1 = P' (U) :
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec2d(DNdir));
-    }
-  else
-    {
-    // Same computation as IICURV in EUCLID-IS because the stability is
-    // better.
-    // V2 = P" (U) :
-    D2Ndir.Multiply (offsetValue/R);
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
-    D2Ndir.Add (Ndir.Multiplied 
-                    (offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
-
-    if(IsDirectionChange)
-      V2=-V2;
-
-    V2.Add (Vec2d(D2Ndir));
-
-    // V1 = P' (U) 
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-    theV1.Add (Vec2d(DNdir));
-    }
-
-  //P (U) :
-  D0(theU, P);
+  CSLib_Offset::D2(theP, theV1, theV2, V3, offsetValue, IsDirectionChange, theP, theV1, theV2);
 }
 
 
@@ -515,9 +288,9 @@ void Geom2d_OffsetCurve::D2 (const Standard_Real theU,
 //=======================================================================
 
 void Geom2d_OffsetCurve::D3 (const Standard_Real theU, 
-                                   Pnt2d& P, 
-                                   Vec2d& theV1, Vec2d& V2, Vec2d& V3) const {
-
+                                   Pnt2d& theP, 
+                                   Vec2d& theV1, Vec2d& theV2, Vec2d& theV3) const
+{
 
    // P(u) = p(u) + Offset * Ndir / R
    // with R = || p' ^ Z|| and Ndir = P' ^ Z
@@ -532,149 +305,16 @@ void Geom2d_OffsetCurve::D3 (const Standard_Real theU,
    //         (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
    //         (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
 
-  const Standard_Real aTol = gp::Resolution();
+  basisCurve->D3 (theU, theP, theV1, theV2, theV3);
+  Vec2d V4 = basisCurve->DN (theU, 4);
 
   Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(basisCurve, 4, theU, theV1, theV2, theV3, V4);
 
-  basisCurve->D3 (theU, P, theV1, V2, V3);
-  Vec2d V4 = basisCurve->DN (theU, 4);
-
-  if(theV1.Magnitude() <= aTol)
-    {
-    const Standard_Real anUinfium   = basisCurve->FirstParameter();
-    const Standard_Real anUsupremum = basisCurve->LastParameter();
-
-    const Standard_Real DivisionFactor = 1.e-3;
-    Standard_Real du;
-    if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
-      du = 0.0;
-    else
-      du = anUsupremum-anUinfium;
-      
-    const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
-//Derivative is approximated by Taylor-series
-    
-    Standard_Integer anIndex = 1; //Derivative order
-    Vec2d V;
-    
-    do
-      {
-      V =  basisCurve->DN(theU,++anIndex);
-      }
-    while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
-    
-    Standard_Real u;
-    
-    if(theU-anUinfium < aDelta)
-      u = theU+aDelta;
-    else
-      u = theU-aDelta;
-    
-    Pnt2d P1, P2;
-    basisCurve->D0(Min(theU, u),P1);
-    basisCurve->D0(Max(theU, u),P2);
-    
-    Vec2d V1(P1,P2);
-    Standard_Real aDirFactor = V.Dot(V1);
-    
-    if(aDirFactor < 0.0)
-      {
-      theV1 = -V;
-      V2 = -basisCurve->DN (theU, anIndex + 1);
-      V3 = -basisCurve->DN (theU, anIndex + 2);
-      V4 = -basisCurve->DN (theU, anIndex + 3);
-
-      IsDirectionChange = Standard_True;
-      }
-    else
-      {
-      theV1 = V;
-      V2 = basisCurve->DN (theU, anIndex + 1);
-      V3 = basisCurve->DN (theU, anIndex + 2);
-      V4 = basisCurve->DN (theU, anIndex + 3);
-      }
-    }//if(V1.Magnitude() <= aTol)
-
-  XY Ndir   (theV1.Y(), -theV1.X());
-  XY DNdir  (V2.Y(), -V2.X());
-  XY D2Ndir (V3.Y(), -V3.X());
-  XY D3Ndir (V4.Y(), -V4.X());
-  Standard_Real R2  = Ndir.SquareModulus();
-  Standard_Real R   = Sqrt (R2);
-  Standard_Real R3  = R2 * R;
-  Standard_Real R4  = R2 * R2;
-  Standard_Real R5  = R3 * R2;
-  Standard_Real R6  = R3 * R3;
-  Standard_Real R7  = R5 * R2;
-  Standard_Real Dr  = Ndir.Dot (DNdir);
-  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
-  Standard_Real D3r = Ndir.Dot (D3Ndir) + 3.0 * DNdir.Dot (D2Ndir);
-
-  if (R7 <= gp::Resolution()) 
-    {
-    //We try another computation but the stability is not very good
-    //dixit ISG.
-
-    if (R6 <= gp::Resolution())
-      Geom2d_UndefinedDerivative::Raise();
-
-    // V3 = P"' (U) :
-    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * offsetValue * Dr / R2));
-    D3Ndir.Subtract (
-      (DNdir.Multiplied ((3.0 * offsetValue) * ((D2r/R2) + (Dr*Dr)/R4))));
-    D3Ndir.Add (Ndir.Multiplied (
-      (offsetValue * (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 - 15.0*Dr*Dr*Dr/R6 - D3r))));
-    D3Ndir.Multiply (offsetValue/R);
-
-    if(IsDirectionChange)
-      V3=-V3;
-
-    V3.Add (Vec2d(D3Ndir));
-
-
-    // V2 = P" (U) :
-    Standard_Real R4 = R2 * R2;
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
-    D2Ndir.Subtract (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
-    D2Ndir.Multiply (offsetValue / R);
-    V2.Add (Vec2d(D2Ndir));
-    // V1 = P' (U) :
-    DNdir.Multiply(R);
-    DNdir.Subtract (Ndir.Multiplied (Dr/R));
-    DNdir.Multiply (offsetValue/R2);
-    theV1.Add (Vec2d(DNdir));
-    }
-  else
-    {
-    // Same computation as IICURV in EUCLID-IS because the stability is
-    // better.
-    // V3 = P"' (U) :
-    D3Ndir.Multiply (offsetValue/R);
-    D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * offsetValue * Dr / R3));
-    D3Ndir.Subtract (DNdir.Multiplied (
-      ((3.0 * offsetValue) * ((D2r/R3) + (Dr*Dr)/R5))) );
-    D3Ndir.Add (Ndir.Multiplied (
-      (offsetValue * (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - 15.0*Dr*Dr*Dr/R7 - D3r))));
-
-    if(IsDirectionChange)
-      V3=-V3;
-
-    V3.Add (Vec2d(D3Ndir));
-
-    // V2 = P" (U) :
-    D2Ndir.Multiply (offsetValue/R);
-    D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
-    D2Ndir.Subtract (Ndir.Multiplied (
-      offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
-    V2.Add (Vec2d(D2Ndir));
-    // V1 = P' (U) :
-    DNdir.Multiply (offsetValue/R);
-    DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-    theV1.Add (Vec2d(DNdir));
-    }
-  //P (U) :
-  D0(theU, P);
-  }
+  CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, offsetValue, IsDirectionChange,
+                   theP, theV1, theV2, theV3);
+}
 
 //=======================================================================
 //function : DN
@@ -709,10 +349,10 @@ Standard_RangeError_Raise_if (N < 1, "Exception: Geom2d_OffsetCurve::DN(). N<1."
 void Geom2d_OffsetCurve::Value (const Standard_Real theU, 
                                 Pnt2d& theP, Pnt2d& thePbasis,
                                 Vec2d& theV1basis ) const 
-  {
+{
   basisCurve->D1(theU, thePbasis, theV1basis);
   D0(theU,theP);
-  }
+}
 
 
 //=======================================================================
@@ -741,30 +381,8 @@ void Geom2d_OffsetCurve::D1 (const Standard_Real U,
    if (Index != 2) {
      V2 = basisCurve->DN (U, Index);
    }
-   XY Ndir (V1.Y(), -V1.X());
-   XY DNdir (V2.Y(), -V2.X());
-   Standard_Real R2 = Ndir.SquareModulus();
-   Standard_Real R = Sqrt (R2);
-   Standard_Real R3 = R * R2;
-   Standard_Real Dr = Ndir.Dot (DNdir);
-   if (R3 <= gp::Resolution()) {
-      //We try another computation but the stability is not very good.
-      if (R2 <= gp::Resolution()) { Geom2d_UndefinedDerivative::Raise(); }
-      DNdir.Multiply(R);
-      DNdir.Subtract (Ndir.Multiplied (Dr/R));
-      DNdir.Multiply (offsetValue / R2);
-      V1.Add (Vec2d(DNdir));
-   }
-   else {
-      // Same computation as IICURV in EUCLID-IS because the stability is
-      // better
-      DNdir.Multiply (offsetValue/R);
-      DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-      V1.Add (Vec2d(DNdir));
-   }
-   Ndir.Multiply (offsetValue/R);
-   Ndir.Add (Pbasis.XY());
-   P.SetXY (Ndir);
+
+   CSLib_Offset::D1(P, V1, V2, offsetValue, Standard_False, P, V1);
 }
 
 
@@ -800,52 +418,8 @@ void Geom2d_OffsetCurve::D2 (const Standard_Real U,
     V2 = basisCurve->DN (U, Index);
     V3 = basisCurve->DN (U, Index + 1);
   }
-  XY Ndir (V1.Y(), -V1.X());
-  XY DNdir (V2.Y(), -V2.X());
-  XY D2Ndir (V3.Y(), -V3.X());
-  Standard_Real R2  = Ndir.SquareModulus();
-  Standard_Real R   = Sqrt (R2);
-  Standard_Real R3  = R2 * R;
-  Standard_Real R4  = R2 * R2;
-  Standard_Real R5  = R3 * R2;
-  Standard_Real Dr  = Ndir.Dot (DNdir);
-  Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
-  if (R5 <= gp::Resolution()) {
-     //We try another computation but the stability is not very good
-     //dixit ISG.
-     if (R4 <= gp::Resolution()) { Geom2d_UndefinedDerivative::Raise(); }
-     // V2 = P" (U) :
-     Standard_Real R4 = R2 * R2;
-     D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
-     D2Ndir.Subtract (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
-     D2Ndir.Multiply (offsetValue / R);
-     V2.Add (Vec2d(D2Ndir));
-     // V1 = P' (U) :
-     DNdir.Multiply(R);
-     DNdir.Subtract (Ndir.Multiplied (Dr/R));
-     DNdir.Multiply (offsetValue/R2);
-     V1.Add (Vec2d(DNdir));
-  }
-  else {
-     // Same computation as IICURV in EUCLID-IS because the stability is
-     // better.
-     // V2 = P" (U) :
-     D2Ndir.Multiply (offsetValue/R);
-     D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
-     D2Ndir.Subtract (Ndir.Multiplied (
-                      offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))
-                                      )
-                     );
-     V2.Add (Vec2d(D2Ndir));
-     // V1 = P' (U) :
-     DNdir.Multiply (offsetValue/R);
-     DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));        
-     V1.Add (Vec2d(DNdir));
-  }
-  //P (U) :
-  Ndir.Multiply (offsetValue/R);
-  Ndir.Add (Pbasis.XY());
-  P.SetXY (Ndir);
+
+  CSLib_Offset::D2(P, V1, V2, V3, offsetValue, Standard_False, P, V1, V2);
 }
 
 //=======================================================================
@@ -961,3 +535,57 @@ GeomAbs_Shape Geom2d_OffsetCurve::GetBasisCurveContinuity() const
 {
   return myBasisCurveContinuity;
 }
+
+
+// ============= Auxiliary functions ===================
+Standard_Boolean AdjustDerivative(const Handle(Geom2d_Curve)& theCurve, Standard_Integer theMaxDerivative,
+                                  Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2,
+                                  gp_Vec2d& theD3, gp_Vec2d& theD4)
+{
+  static const Standard_Real aTol = gp::Resolution();
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  const Standard_Real anUinfium   = theCurve->FirstParameter();
+  const Standard_Real anUsupremum = theCurve->LastParameter();
+
+  const Standard_Real DivisionFactor = 1.e-3;
+  Standard_Real du;
+  if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
+    du = 0.0;
+  else
+    du = anUsupremum - anUinfium;
+
+  const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
+
+  //Derivative is approximated by Taylor-series
+  Standard_Integer anIndex = 1; //Derivative order
+  Vec2d V;
+
+  do
+  {
+    V =  theCurve->DN(theU, ++anIndex);
+  }
+  while((V.SquareMagnitude() <= aTol) && anIndex < maxDerivOrder);
+
+  Standard_Real u;
+
+  if(theU-anUinfium < aDelta)
+    u = theU+aDelta;
+  else
+    u = theU-aDelta;
+
+  Pnt2d P1, P2;
+  theCurve->D0(Min(theU, u),P1);
+  theCurve->D0(Max(theU, u),P2);
+
+  Vec2d V1(P1,P2);
+  IsDirectionChange = V.Dot(V1) < 0.0;
+  Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
+
+  theD1 = V * aSign;
+  gp_Vec2d* aDeriv[3] = {&theD2, &theD3, &theD4};
+  for (Standard_Integer i = 1; i < theMaxDerivative; i++)
+    *(aDeriv[i-1]) = theCurve->DN(theU, anIndex + i) * aSign;
+
+  return IsDirectionChange;
+}
index d4f7ff5..f01e1c9 100644 (file)
@@ -27,7 +27,8 @@ uses
     gp,
     Standard,
     TColStd,
-    TColgp
+    TColgp,
+    BSplCLib
 
 is
 
index b53c131..7609c04 100644 (file)
@@ -33,7 +33,8 @@ uses Vec2d                  from gp,
      BSplineCurve           from Geom2d,
      CurveType              from GeomAbs,
      Shape                  from GeomAbs,
-     HCurve2d               from Adaptor2d
+     HCurve2d               from Adaptor2d,
+     Cache                  from BSplCLib
      
      
 raises NoSuchObject from Standard,
@@ -123,19 +124,44 @@ is
         --- Purpose : Computes the point of parameter U on the curve 
     is redefined static;
 
+    ValueBSpline(me; U: Real) returns Pnt2d from gp
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+    is private;
+
+    ValueOffset(me; U: Real) returns Pnt2d from gp
+        --- Purpose : Computes the point of parameter U on the offset curve
+    is private;
+
     D0 (me; U : Real; P : out Pnt2d from gp)
         --- Purpose : Computes the point of parameter U.
     is redefined static;
 
+    D0BSpline(me; theU : Real; theP : out Pnt2d from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+    is private;
+
+    D0Offset(me; theU : Real; theP : out Pnt2d from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+    is private;
+
     D1 (me; U : Real; P : out Pnt2d from gp ; V : out Vec2d from gp)
         --- Purpose : Computes the point of parameter U on the curve with its
         --  first derivative.
-
     raises 
        DomainError from Standard
         --- Purpose : Raised if the continuity of the current interval
         --  is not C1.
     is redefined static;
+
+    D1BSpline(me; theU : Real; theP : out Pnt2d from gp ; theV : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its derivative
+    is private;
+
+    D1Offset(me; theU : Real; theP : out Pnt2d from gp ; theV : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its derivative
+    is private;
     
     D2 (me; U : Real; P : out Pnt2d from gp; V1, V2 : out Vec2d from gp)
         --- Purpose :
@@ -147,6 +173,16 @@ is
         --  is not C2.
     is redefined static;
 
+    D2BSpline(me; theU : Real; theP : out Pnt2d from gp; theV1, theV2 : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its first and second derivatives
+    is private;
+
+    D2Offset(me; theU : Real; theP : out Pnt2d from gp; theV1, theV2 : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its first and second derivatives
+    is private;
+
     D3 (me; U : Real; P : out Pnt2d from gp; V1, V2, V3 : out Vec2d from gp)
         --- Purpose :
         --  Returns the point P of parameter U, the first, the second 
@@ -156,6 +192,16 @@ is
         --- Purpose : Raised if the continuity of the current interval
         --  is not C3.
     is redefined static;
+
+    D3BSpline(me; theU : Real; theP : out Pnt2d from gp; theV1, theV2, theV3 : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its first, second and third derivatives
+    is private;
+
+    D3Offset(me; theU : Real; theP : out Pnt2d from gp; theV1, theV2, theV3 : out Vec2d from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its first, second and third derivatives
+    is private;
         
     DN (me; U : Real; N : Integer)   returns Vec2d from gp
         --- Purpose :
@@ -169,6 +215,18 @@ is
         --- Purpose : Raised if N < 1.            
     is redefined static;
 
+    DNBSpline(me; theU : Real; N : Integer) returns Vec2d from gp
+        --- Purpose :
+        --  The returned vector gives the value of the derivative for the 
+        --  order of derivation N.
+    is private;
+
+    DNOffset(me; theU : Real; N : Integer) returns Vec2d from gp
+        --- Purpose :
+        --  The returned vector gives the value of the derivative for the 
+        --  order of derivation N.
+    is private;
+
 
     Resolution(me; Ruv :Real) returns Real
         ---Purpose : returns the parametric resolution
@@ -243,6 +301,11 @@ is
 
     load(me : in out; C : Curve from Geom2d; UFirst,ULast : Real)
     is private;
+    
+    RebuildCache(me; theParameter : Real)
+    ---Purpose: Rebuilds B-spline cache
+    -- \param theParameter the value on the knot axis which identifies the caching span
+    is static private;
    
 fields 
 
@@ -250,6 +313,8 @@ fields
   myTypeCurve         : CurveType        from GeomAbs ;
   myFirst             : Real             from Standard ;
   myLast              : Real             from Standard;
+  myCurveCache        : Cache            from BSplCLib;
+  myOffsetBaseCurveAdaptor : HCurve2d    from Adaptor2d;
   
 end Curve;
 
index 4241b19..e1869eb 100644 (file)
@@ -26,6 +26,7 @@
 #include <Geom2dAdaptor_HCurve.hxx>
 #include <Adaptor2d_HCurve2d.hxx>
 #include <BSplCLib.hxx>
+#include <BSplCLib_Cache.hxx>
 #include <GeomAbs_Shape.hxx>
 #include <TColgp_Array1OfPnt2d.hxx>
 #include <TColStd_Array1OfReal.hxx>
@@ -42,6 +43,9 @@
 #include <Geom2d_Ellipse.hxx>
 #include <Geom2d_Parabola.hxx>
 #include <Geom2d_Hyperbola.hxx>
+#include <Geom2d_UndefinedValue.hxx>
+#include <Geom2d_UndefinedDerivative.hxx>
+#include <CSLib_Offset.hxx>
 //#include <Geom2dConvert_BSplineCurveKnotSplitting.hxx>
 
 #include <Standard_OutOfRange.hxx>
 #define myBspl (*((Handle(Geom2d_BSplineCurve)*)&myCurve))
 #define PosTol Precision::PConfusion()/2
 
+static const int maxDerivOrder = 3;
+static const Standard_Real MinStep   = 1e-7;
+
+static gp_Vec2d dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
+
+// Recalculate derivatives in the singular point
+// Returns true is the direction of derivatives is changed
+static Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
+                                         Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2 = dummyDerivative,
+                                         gp_Vec2d& theD3 = dummyDerivative, gp_Vec2d& theD4 = dummyDerivative);
+
 //=======================================================================
 //function : LocalContinuity
 //purpose  : Computes the Continuity of a BSplineCurve 
@@ -197,6 +212,16 @@ void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
     }
     else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
       myTypeCurve = GeomAbs_BSplineCurve;
+      // Create cache for B-spline
+      myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(), 
+        myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
+    }
+    else if ( TheType == STANDARD_TYPE(Geom2d_OffsetCurve))
+    {
+      myTypeCurve = GeomAbs_OtherCurve;
+      // Create nested adaptor for base curve
+      Handle(Geom2d_Curve) aBase = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve();
+      myOffsetBaseCurveAdaptor = new Geom2dAdaptor_HCurve(aBase);
     }
     else {
       myTypeCurve = GeomAbs_OtherCurve;
@@ -218,7 +243,7 @@ GeomAbs_Shape Geom2dAdaptor_Curve::Continuity() const
   if (myTypeCurve == GeomAbs_BSplineCurve) {
     return LocalContinuity(myFirst, myLast);
   }
-  else if (myCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))){
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
     GeomAbs_Shape S = 
       (*((Handle(Geom2d_OffsetCurve)*)&myCurve))->GetBasisCurveContinuity(); 
     switch(S){
@@ -330,7 +355,7 @@ Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
       }
     }
   }
-  else if (myCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))){
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
     GeomAbs_Shape BaseS=GeomAbs_C0;
     switch(S){
     case GeomAbs_G1:
@@ -342,9 +367,7 @@ Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
     default: BaseS = GeomAbs_CN;
     }
-    Geom2dAdaptor_Curve C
-      ((*((Handle(Geom2d_OffsetCurve)*)&myCurve))->BasisCurve());
-    myNbIntervals = C.NbIntervals(BaseS);
+    myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
   }
 
   return myNbIntervals;
@@ -447,7 +470,7 @@ void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
       }
     }
   }
-  else if (myCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))){
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
     GeomAbs_Shape BaseS=GeomAbs_C0;
     switch(S){
     case GeomAbs_G1:
@@ -459,10 +482,8 @@ void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
     default: BaseS = GeomAbs_CN;
     }
-    Geom2dAdaptor_Curve C
-      ((*((Handle(Geom2d_OffsetCurve)*)&myCurve))->BasisCurve());
-    myNbIntervals = C.NbIntervals(BaseS);
-    C.Intervals(T, BaseS);
+    myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
+    myOffsetBaseCurveAdaptor->Intervals(T, BaseS);
   }
 
   T( T.Lower() ) = myFirst;
@@ -526,30 +547,82 @@ Standard_Real Geom2dAdaptor_Curve::Period() const
 }
 
 //=======================================================================
+//function : RebuildCache
+//purpose  : 
+//=======================================================================
+void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
+{
+  myCurveCache->BuildCache(theParameter, myBspl->Degree(), 
+    myBspl->IsPeriodic(), myBspl->KnotSequence(), 
+    myBspl->Poles(), myBspl->Weights());
+}
+
+//=======================================================================
 //function : Value
 //purpose  : 
 //=======================================================================
 
 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    return ValueBSpline(U);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+    return ValueOffset(U);
+
+  return myCurve->Value(U);
+}
+
+//=======================================================================
+//function : ValueBSpline
+//purpose  : Computes the point of parameter U on the B-spline curve
+//=======================================================================
+gp_Pnt2d Geom2dAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst)
+    {
       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast)
+    {
       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    return myBspl->LocalValue(U, Ideb, Ifin);
+    return myBspl->LocalValue(theU, Ideb, Ifin);
   }
-  else {
-    return myCurve->Value( U);
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    gp_Pnt2d aRes;
+    myCurveCache->D0(theU, aRes);
+    return aRes;
   }
+  return myCurve->Value(theU);
+}
+
+//=======================================================================
+//function : ValueOffset
+//purpose  : Computes the point of parameter U on the offset curve
+//=======================================================================
+gp_Pnt2d Geom2dAdaptor_Curve::ValueOffset(const Standard_Real theU) const
+{
+  gp_Pnt2d aP;
+  gp_Vec2d aD1;
+  myOffsetBaseCurveAdaptor->D1(theU, aP, aD1);
+  Standard_Boolean isDirectionChange = Standard_False;
+  const Standard_Real aTol = gp::Resolution();
+  if(aD1.SquareMagnitude() <= aTol)
+    isDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aD1);
+
+  Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
+  CSLib_Offset::D0(aP, aD1, anOffset, isDirectionChange, aP);
+  return aP;
 }
 
 //=======================================================================
@@ -559,24 +632,59 @@ gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const
 
 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+  {
+    D0BSpline(U, P);
+    return;
+  }
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+  {
+    D0Offset(U, P);
+    return;
+  }
+
+  myCurve->D0(U, P);
+}
+
+//=======================================================================
+//function : D0BSpline
+//purpose  : Computes the point of parameter theU on the B-spline curve
+//=======================================================================
+void Geom2dAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt2d& theP) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst) {
       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast) {
       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    myBspl->LocalD0( U, Ideb, Ifin, P);
+    myBspl->LocalD0(theU, Ideb, Ifin, theP);
+    return;
   }
-  else {
-    myCurve->D0(U, P);
-  } 
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    myCurveCache->D0(theU, theP);
+    return;
+  }
+  myCurve->D0(theU, theP);
+}
+
+//=======================================================================
+//function : D0Offset
+//purpose  : Computes the point of parameter theU on the offset curve
+//=======================================================================
+void Geom2dAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt2d& theP) const
+{
+  theP = ValueOffset(theU);
 }
 
 //=======================================================================
@@ -584,27 +692,75 @@ void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
 //purpose  : 
 //=======================================================================
 
-void Geom2dAdaptor_Curve::D1(const Standard_Real U,
-                            gp_Pnt2d& P, gp_Vec2d& V) const 
+void Geom2dAdaptor_Curve::D1(const Standard_Real U, 
+                             gp_Pnt2d& P, gp_Vec2d& V) const 
+{
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+  {
+    D1BSpline(U, P, V);
+    return;
+  }
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+  {
+    D1Offset(U, P, V);
+    return;
+  }
+
+  myCurve->D1(U, P, V);
+}
+
+//=======================================================================
+//function : D1BSpline
+//purpose  : Computes the point of parameter theU on the B-spline curve and its derivative
+//=======================================================================
+void Geom2dAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst) {
       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast) {
       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    myBspl->LocalD1( U, Ideb, Ifin, P, V); 
-  } 
-  else {
-    myCurve->D1( U, P, V);
+    myBspl->LocalD1(theU, Ideb, Ifin, theP, theV); 
+    return;
   }
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    myCurveCache->D1(theU, theP, theV);
+    return;
+  }
+  myCurve->D1(theU, theP, theV);
+}
+
+//=======================================================================
+//function : D1Offset
+//purpose  : Computes the point of parameter theU on the offset curve and its derivative
+//=======================================================================
+void Geom2dAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
+{
+   // P(u) = p(u) + Offset * Ndir / R
+   // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+   // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+  gp_Vec2d V2;
+  myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, V2);
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, V2);
+
+  Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
+  CSLib_Offset::D1(theP, theV, V2, anOffset, IsDirectionChange, theP, theV);
 }
 
 //=======================================================================
@@ -613,26 +769,78 @@ void Geom2dAdaptor_Curve::D1(const Standard_Real U,
 //=======================================================================
 
 void Geom2dAdaptor_Curve::D2(const Standard_Real U, 
-                            gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
+                             gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+  {
+    D2BSpline(U, P, V1, V2);
+    return;
+  }
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+  {
+    D2Offset(U, P, V1, V2);
+    return;
+  }
+
+  myCurve->D2(U, P, V1, V2);
+}
+
+//=======================================================================
+//function : D2BSpline
+//purpose  : Computes the point of parameter theU on the B-spline curve and its first and second derivatives
+//=======================================================================
+void Geom2dAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt2d& theP,
+                                    gp_Vec2d& theV1, gp_Vec2d& theV2) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst) {
       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast) {
       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    myBspl->LocalD2( U, Ideb, Ifin, P, V1, V2);
+    myBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
+    return;
   }
-  else {
-    myCurve->D2( U, P, V1, V2);
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    myCurveCache->D2(theU, theP, theV1, theV2);
+    return;
   }
+  myCurve->D2(theU, theP, theV1, theV2);
+}
+//=======================================================================
+//function : D2Offset
+//purpose  : Computes the point of parameter theU on the offset curve and its first and second derivatives
+//=======================================================================
+void Geom2dAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt2d& theP,
+                                    gp_Vec2d& theV1, gp_Vec2d& theV2) const
+{
+   // P(u) = p(u) + Offset * Ndir / R
+   // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+   // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+   // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+   //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+  gp_Vec2d V3;
+  myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
+
+  Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
+  CSLib_Offset::D2(theP, theV1, theV2, V3, anOffset, IsDirectionChange, theP, theV1, theV2);
 }
 
 //=======================================================================
@@ -641,27 +849,86 @@ void Geom2dAdaptor_Curve::D2(const Standard_Real U,
 //=======================================================================
 
 void Geom2dAdaptor_Curve::D3(const Standard_Real U, 
-                            gp_Pnt2d& P,  gp_Vec2d& V1, 
-                            gp_Vec2d& V2, gp_Vec2d& V3) const 
+                             gp_Pnt2d& P,  gp_Vec2d& V1, 
+                             gp_Vec2d& V2, gp_Vec2d& V3) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve) &&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+  {
+    D3BSpline(U, P, V1, V2, V3);
+    return;
+  }
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+  {
+    D3Offset(U, P, V1, V2, V3);
+    return;
+  }
+
+  myCurve->D3(U, P, V1, V2, V3);
+}
+
+//=======================================================================
+//function : D3BSpline
+//purpose  : Computes the point of parameter theU on the B-spline curve and its 1st - 3rd derivatives
+//=======================================================================
+void Geom2dAdaptor_Curve::D3BSpline(const Standard_Real theU, gp_Pnt2d& theP,
+                                    gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst) {
       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast) {
       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    myBspl->LocalD3( U, Ideb, Ifin, P, V1, V2, V3);  
+    myBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
+    return;
   }
-  else {
-    myCurve->D3( U, P, V1, V2, V3);
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    myCurveCache->D3(theU, theP, theV1, theV2, theV3);
+    return;
   }
+  myCurve->D3(theU, theP, theV1, theV2, theV3);
+}
+//=======================================================================
+//function : D3Offset
+//purpose  : Computes the point of parameter theU on the offset curve and its 1st - 3rd derivatives
+//=======================================================================
+void Geom2dAdaptor_Curve::D3Offset(const Standard_Real theU, gp_Pnt2d& theP,
+                                    gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
+{
+   // P(u) = p(u) + Offset * Ndir / R
+   // with R = || p' ^ Z|| and Ndir = P' ^ Z
+
+   // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
+
+   // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
+   //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
+
+   //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
+   //         (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
+   //         (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
+   //         (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+
+  myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
+  gp_Vec2d V4 = myOffsetBaseCurveAdaptor->DN (theU, 4);
+
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
+
+  Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
+  CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffset, IsDirectionChange,
+                   theP, theV1, theV2, theV3);
 }
 
 //=======================================================================
@@ -670,10 +937,21 @@ void Geom2dAdaptor_Curve::D3(const Standard_Real U,
 //=======================================================================
 
 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U, 
-                                const Standard_Integer N) const 
+                                 const Standard_Integer N) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve) &&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    return DNBSpline(U, N);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
+    return DNOffset(U, N);
+
+  return myCurve->DN(U, N);
+}
+
+gp_Vec2d Geom2dAdaptor_Curve::DNBSpline(const Standard_Real U, 
+                                        const Standard_Integer N) const 
+{
+  if (U==myFirst || U==myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
     if (U==myFirst) {
       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
@@ -686,10 +964,32 @@ gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U,
       if (Ideb>=Ifin) Ideb = Ifin-1;
     } 
     return myBspl->LocalDN( U, Ideb, Ifin, N);
-  }  
-  else {
-    return myCurve->DN( U, N);
   }
+
+  return myCurve->DN( U, N);
+}
+
+gp_Vec2d Geom2dAdaptor_Curve::DNOffset(const Standard_Real    U,
+                                       const Standard_Integer N) const
+{
+  gp_Pnt2d aPnt;
+  gp_Vec2d aVec, aVN;
+
+  switch (N)
+  {
+  case 1:
+    D1Offset(U, aPnt, aVN);
+    break;
+  case 2:
+    D2Offset(U, aPnt, aVec, aVN);
+    break;
+  case 3:
+    D3Offset(U, aPnt, aVec, aVec, aVN);
+    break;
+  default:
+    aVN = myCurve->DN(U, N);
+  }
+  return aVN;
 }
 
 //=======================================================================
@@ -906,3 +1206,57 @@ Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
 {
   return  nbPoints(myCurve);
 }
+
+
+// ============= Auxiliary functions ===================
+Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
+                                  Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2,
+                                  gp_Vec2d& theD3, gp_Vec2d& theD4)
+{
+  static const Standard_Real aTol = gp::Resolution();
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  const Standard_Real anUinfium   = theAdaptor->FirstParameter();
+  const Standard_Real anUsupremum = theAdaptor->LastParameter();
+
+  const Standard_Real DivisionFactor = 1.e-3;
+  Standard_Real du;
+  if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
+    du = 0.0;
+  else
+    du = anUsupremum - anUinfium;
+
+  const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
+
+  //Derivative is approximated by Taylor-series
+  Standard_Integer anIndex = 1; //Derivative order
+  gp_Vec2d V;
+
+  do
+  {
+    V =  theAdaptor->DN(theU, ++anIndex);
+  }
+  while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
+
+  Standard_Real u;
+
+  if(theU-anUinfium < aDelta)
+    u = theU+aDelta;
+  else
+    u = theU-aDelta;
+
+  gp_Pnt2d P1, P2;
+  theAdaptor->D0(Min(theU, u),P1);
+  theAdaptor->D0(Max(theU, u),P2);
+
+  gp_Vec2d V1(P1, P2);
+  IsDirectionChange = V.Dot(V1) < 0.0;
+  Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
+
+  theD1 = V * aSign;
+  gp_Vec2d* aDeriv[3] = {&theD2, &theD3, &theD4};
+  for (Standard_Integer i = 1; i < theMaxDerivative; i++)
+    *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
+
+  return IsDirectionChange;
+}
index 55008f5..bda2d10 100644 (file)
@@ -28,7 +28,9 @@ uses
     TColStd,
     Geom2dAdaptor,
     TColgp,
-    Precision
+    Precision,
+    BSplCLib,
+    BSplSLib
 
 is
       class Curve; 
index c286374..626669d 100644 (file)
@@ -33,7 +33,8 @@ uses Vec                  from gp,
      BSplineCurve         from Geom,
      CurveType            from GeomAbs,
      Shape                from GeomAbs,
-     HCurve               from Adaptor3d
+     HCurve               from Adaptor3d,
+     Cache                from BSplCLib
      
 raises NoSuchObject from Standard,
        ConstructionError from Standard,
@@ -129,10 +130,26 @@ is
         --- Purpose : Computes the point of parameter U on the curve 
    is redefined static;
 
+   ValueBSpline(me; U: Real) returns Pnt from gp
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+   is private;
+
+   ValueOffset(me; U: Real) returns Pnt from gp
+        --- Purpose : Computes the point of parameter U on the offset curve
+   is private;
+
    D0 (me; U : Real; P : out Pnt from gp)
         --- Purpose : Computes the point of parameter U.
    is redefined static;
 
+   D0BSpline(me; theU : Real; theP : out Pnt from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+   is private;
+
+   D0Offset(me; theU : Real; theP : out Pnt from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+   is private;
+
    D1 (me; U : Real; P : out Pnt from gp ; V : out Vec from gp)
         --- Purpose : Computes the point of parameter U on the curve 
         --  with its first derivative.
@@ -142,6 +159,16 @@ is
        --  derivatives are computed on the current interval.
        --  else the derivatives are computed on the basis curve.
    is redefined static;
+
+   D1BSpline(me; theU : Real; theP : out Pnt from gp ; theV : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its derivative
+   is private;
+
+   D1Offset(me; theU : Real; theP : out Pnt from gp ; theV : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its derivative
+   is private;
     
    D2 (me; U : Real; P : out Pnt from gp; V1, V2 : out Vec from gp)
         --- Purpose :
@@ -154,6 +181,16 @@ is
        --  else the derivatives are computed on the basis curve.
    is redefined static;
 
+   D2BSpline(me; theU : Real; theP : out Pnt from gp; theV1, theV2 : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its first and second derivatives
+   is private;
+
+   D2Offset(me; theU : Real; theP : out Pnt from gp; theV1, theV2 : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its first and second derivatives
+   is private;
+
    D3 (me; U : Real; P : out Pnt from gp; V1, V2, V3 : out Vec from gp)
         --- Purpose :
         --  Returns the point P of parameter U, the first, the second 
@@ -164,6 +201,16 @@ is
        --  derivatives are computed on the current interval.
        --  else the derivatives are computed on the basis curve.
    is redefined static;
+
+   D3BSpline(me; theU : Real; theP : out Pnt from gp; theV1, theV2, theV3 : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the B-spline curve
+        --  and its first, second and third derivatives
+   is private;
+
+   D3Offset(me; theU : Real; theP : out Pnt from gp; theV1, theV2, theV3 : out Vec from gp)
+        --- Purpose : Computes the point of parameter U on the offset curve
+        --  and its first, second and third derivatives
+   is private;
         
    DN (me; U : Real; N : Integer)   returns Vec from gp
         --- Purpose :
@@ -179,6 +226,19 @@ is
    is redefined static;
 
 
+   DNBSpline(me; theU : Real; N : Integer)   returns Vec from gp
+        --- Purpose :
+        --  The returned vector gives the value of the derivative for the 
+        --  order of derivation N.
+   is private;
+
+   DNOffset(me; theU : Real; N : Integer)   returns Vec from gp
+        --- Purpose :
+        --  The returned vector gives the value of the derivative for the 
+        --  order of derivation N.
+   is private;
+
+
    Resolution(me; R3d :Real) returns Real
         ---Purpose : returns the parametric resolution
    is redefined static;   
@@ -279,6 +339,11 @@ is
 
    load(me : in out; C : Curve from Geom; UFirst,ULast : Real)
    is private;
+    
+    RebuildCache(me; theParameter : Real)
+    ---Purpose: Rebuilds B-spline cache
+    -- \param theParameter the value on the knot axis which identifies the caching span
+    is static private;
    
 fields 
 
@@ -286,6 +351,8 @@ fields
   myTypeCurve         : CurveType        from GeomAbs ;
   myFirst             : Real             from Standard ;
   myLast              : Real             from Standard;
+  myCurveCache        : Cache            from BSplCLib;
+  myOffsetBaseCurveAdaptor : HCurve      from Adaptor3d;
   
 friends
     class Surface from GeomAdaptor
index 05c471f..5f9ea8d 100644 (file)
@@ -26,6 +26,7 @@
 #include <GeomAdaptor_HCurve.hxx>
 #include <Adaptor3d_HCurve.hxx>
 #include <BSplCLib.hxx>
+#include <BSplCLib_Cache.hxx>
 #include <GeomAbs_Shape.hxx>
 #include <TColgp_Array1OfPnt.hxx>
 #include <TColStd_Array1OfReal.hxx>
 #include <Standard_NullObject.hxx>
 #include <Standard_NotImplemented.hxx>
 #include <Geom_OffsetCurve.hxx>
+#include <CSLib_Offset.hxx>
 
 #define myBspl (*((Handle(Geom_BSplineCurve)*)&myCurve))
 #define PosTol Precision::PConfusion()/2
 
+static const int maxDerivOrder = 3;
+static const Standard_Real MinStep   = 1e-7;
+
+static gp_Vec dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
+// Recalculate derivatives in the singular point
+// Returns true if the direction of derivatives is changed
+static Standard_Boolean AdjustDerivative(
+    const Handle(Adaptor3d_HCurve)& theAdaptor, Standard_Integer theMaxDerivative, Standard_Real theU, gp_Vec& theD1,
+    gp_Vec& theD2 = dummyDerivative, gp_Vec& theD3 = dummyDerivative, gp_Vec& theD4 = dummyDerivative);
+
+
 //=======================================================================
 //function : LocalContinuity
 //purpose  : Computes the Continuity of a BSplineCurve 
@@ -155,6 +168,15 @@ void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
     }
     else if ( TheType == STANDARD_TYPE(Geom_BSplineCurve)) {
       myTypeCurve = GeomAbs_BSplineCurve;
+      // Create cache for B-spline
+      myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(), 
+        myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
+    }
+    else if ( TheType == STANDARD_TYPE(Geom_OffsetCurve)) {
+      myTypeCurve = GeomAbs_OtherCurve;
+      // Create nested adaptor for base curve
+      Handle(Geom_Curve) aBase = Handle(Geom_OffsetCurve)::DownCast(myCurve)->BasisCurve();
+      myOffsetBaseCurveAdaptor = new GeomAdaptor_HCurve(aBase);
     }
     else {
       myTypeCurve = GeomAbs_OtherCurve;
@@ -511,28 +533,81 @@ Standard_Real GeomAdaptor_Curve::Period() const
 }
 
 //=======================================================================
+//function : RebuildCache
+//purpose  : 
+//=======================================================================
+void GeomAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
+{
+  myCurveCache->BuildCache(theParameter, myBspl->Degree(), 
+    myBspl->IsPeriodic(), myBspl->KnotSequence(), 
+    myBspl->Poles(), myBspl->Weights());
+}
+
+//=======================================================================
 //function : Value
 //purpose  : 
 //=======================================================================
 
 gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    return ValueBSpline(U);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    return ValueOffset(U);
+  return myCurve->Value(U);
+}
+
+//=======================================================================
+//function : ValueBSpline
+//purpose  : 
+//=======================================================================
+gp_Pnt GeomAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
     Standard_Integer Ideb = 0, Ifin = 0;
-    if (U==myFirst) {
+    if (theU == myFirst) {
       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
       if (Ideb>=Ifin) Ifin = Ideb+1;
     }
-    if (U==myLast) {
+    if (theU == myLast) {
       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
       if (Ideb>=Ifin) Ideb = Ifin-1;
     }
-    return myBspl->LocalValue(U, Ideb, Ifin);
+    return myBspl->LocalValue(theU, Ideb, Ifin);
   }
-  return myCurve->Value(U);
+  else if (!myCurveCache.IsNull()) // use cached B-spline data
+  {
+    if (!myCurveCache->IsCacheValid(theU))
+      RebuildCache(theU);
+    gp_Pnt aRes;
+    myCurveCache->D0(theU, aRes);
+    return aRes;
+  }
+  return myCurve->Value(theU);
+}
+
+//=======================================================================
+//function : ValueOffset
+//purpose  : 
+//=======================================================================
+gp_Pnt GeomAdaptor_Curve::ValueOffset(const Standard_Real theU) const
+{
+  gp_Pnt aP;
+  gp_Vec aV;
+  myOffsetBaseCurveAdaptor->D1(theU, aP, aV);
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(aV.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aV);
+
+  Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
+  Standard_Real anOffsetVal = anOffC->Offset();
+  const gp_Dir& anOffsetDir = anOffC->Direction();
+
+  CSLib_Offset::D0(aP, aV, anOffsetDir, anOffsetVal, IsDirectionChange, aP);
+  return aP;
 }
 
 //=======================================================================
@@ -542,24 +617,53 @@ gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
 
 void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    D0BSpline(U, P);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    D0Offset(U, P);
+  else
+    myCurve->D0(U, P);
+}
+
+//=======================================================================
+//function : D0BSpline
+//purpose  : 
+//=======================================================================
+void GeomAdaptor_Curve::D0BSpline(co