0024023: Revamp the OCCT Handle -- downcast (automatic)
[occt.git] / src / GeomAdaptor / GeomAdaptor_Curve.cxx
old mode 100755 (executable)
new mode 100644 (file)
index b4f4a76..9757ac9
@@ -1,23 +1,18 @@
 // Created on: 1993-04-29
 // Created by: Bruno DUMORTIER
 // Copyright (c) 1993-1999 Matra Datavision
-// Copyright (c) 1999-2012 OPEN CASCADE SAS
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
 //
-// The content of this file is subject to the Open CASCADE Technology Public
-// License Version 6.5 (the "License"). You may not use the content of this file
-// except in compliance with the License. Please obtain a copy of the License
-// at http://www.opencascade.org and read it completely before using this file.
+// This file is part of Open CASCADE Technology software library.
 //
-// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
-// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+// 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.
 //
-// The Original Code and all software distributed under the License is
-// distributed on an "AS IS" basis, without warranty of any kind, and the
-// Initial Developer hereby disclaims all such warranties, including without
-// limitation, any warranties of merchantability, fitness for a particular
-// purpose or non-infringement. Please see the License for the specific terms
-// and conditions governing the rights and limitations under the License.
-
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
 
 // 20/02/97 : PMN -> Positionement local sur BSpline (PRO6902)
 // 10/07/97 : PMN -> Pas de calcul de resolution dans Nb(Intervals)(PRO9248)
@@ -31,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 myBspl Handle(Geom_BSplineCurve)::DownCast (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 
@@ -138,7 +146,7 @@ void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
     
     const Handle(Standard_Type)& TheType = C->DynamicType();
     if ( TheType == STANDARD_TYPE(Geom_TrimmedCurve)) {
-      Load((*((Handle(Geom_TrimmedCurve)*)&C))->BasisCurve(),UFirst,ULast);
+      Load(Handle(Geom_TrimmedCurve)::DownCast (C)->BasisCurve(),UFirst,ULast);
     }
     else if ( TheType ==  STANDARD_TYPE(Geom_Circle)) {
       myTypeCurve = GeomAbs_Circle;
@@ -160,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;
@@ -184,15 +201,17 @@ GeomAbs_Shape GeomAdaptor_Curve::Continuity() const
   if (myCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
   {
     const GeomAbs_Shape S =
-      (*((Handle(Geom_OffsetCurve)*)&myCurve))->BasisCurve()->Continuity();
+      Handle(Geom_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity();
     switch(S)
     {
       case GeomAbs_CN: return GeomAbs_CN;
       case GeomAbs_C3: return GeomAbs_C2;
       case GeomAbs_C2: return GeomAbs_C1;
-      case GeomAbs_C1: return GeomAbs_C0;  
+      case GeomAbs_C1: return GeomAbs_C0; 
+      case GeomAbs_G1: return GeomAbs_G1;
+      case GeomAbs_G2: return GeomAbs_G2;
       default:
-      Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Continuity");
+        Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Continuity");
     }
   }
   else if (myTypeCurve == GeomAbs_OtherCurve) {
@@ -207,7 +226,7 @@ GeomAbs_Shape GeomAdaptor_Curve::Continuity() const
 //purpose  : 
 //=======================================================================
 
-Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) 
+Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
 {
   Standard_Integer myNbIntervals = 1;
   Standard_Integer NbSplit;
@@ -303,7 +322,7 @@ Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S)
     default: BaseS = GeomAbs_CN;
     }
     GeomAdaptor_Curve C
-      ((*((Handle(Geom_OffsetCurve)*)&myCurve))->BasisCurve());
+      (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
     //                    the number of intervals obtained from the basis to
     //              vvv   reflect parameter bounds
@@ -327,7 +346,7 @@ Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S)
 //=======================================================================
 
 void GeomAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
-                                 const GeomAbs_Shape S   )  
+                                  const GeomAbs_Shape S   ) const
 {
   Standard_Integer myNbIntervals = 1;
   Standard_Integer NbSplit;
@@ -441,7 +460,7 @@ void GeomAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
     default: BaseS = GeomAbs_CN;
     }
     GeomAdaptor_Curve C
-      ((*((Handle(Geom_OffsetCurve)*)&myCurve))->BasisCurve());
+      (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
     //                    the array of intervals obtained from the basis to
     //              vvv   reflect parameter bounds
@@ -513,6 +532,17 @@ Standard_Real GeomAdaptor_Curve::Period() const
   return myCurve->LastParameter() - myCurve->FirstParameter();
 }
 
+//=======================================================================
+//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  : 
@@ -520,22 +550,64 @@ Standard_Real GeomAdaptor_Curve::Period() const
 
 gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
-    Standard_Integer Ideb, Ifin;
-    if (U==myFirst) {
+  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 (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;
 }
 
 //=======================================================================
@@ -545,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) ) {
-    Standard_Integer Ideb, Ifin;
-    if (U==myFirst) {
+  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(const Standard_Real theU, gp_Pnt& theP) const
+{
+  if (theU == myFirst || theU == myLast) 
+  {
+    Standard_Integer Ideb = 0, Ifin = 0;
+    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  : 
+//=======================================================================
+void GeomAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt& theP) const
+{
+  theP = ValueOffset(theU);
 }
 
 //=======================================================================
@@ -572,52 +673,133 @@ void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const
 
 void GeomAdaptor_Curve::D1(const Standard_Real U, gp_Pnt& P, gp_Vec& V) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
-    Standard_Integer Ideb, Ifin;
-    if (U==myFirst) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    D1BSpline(U, P, V);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    D1Offset(U, P, V);
+  else
+    myCurve->D1(U, P, V);
+}
+
+//=======================================================================
+//function : D1BSpline
+//purpose  : 
+//=======================================================================
+void GeomAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
+{
+  if (theU == myFirst || theU == myLast) 
+  {
+    Standard_Integer Ideb = 0, Ifin = 0;
+    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  : 
+//=======================================================================
+void GeomAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
+{
+  gp_Vec aV2;
+  myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, aV2);
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, aV2);
+
+  Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
+  Standard_Real anOffsetVal = anOffC->Offset();
+  const gp_Dir& anOffsetDir = anOffC->Direction();
+  CSLib_Offset::D1(theP, theV, aV2, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV);
 }
 
+
 //=======================================================================
 //function : D2
 //purpose  : 
 //=======================================================================
 
 void GeomAdaptor_Curve::D2(const Standard_Real U, 
-                          gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const 
+                           gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve)&&
-      (U==myFirst || U==myLast) ) {
-    Standard_Integer Ideb, Ifin;
-    if (U==myFirst) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    D2BSpline(U, P, V1, V2);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    D2Offset(U, P, V1, V2);
+  else
+    myCurve->D2(U, P, V1, V2);
+}
+
+//=======================================================================
+//function : D2BSpline
+//purpose  : 
+//=======================================================================
+void GeomAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt& theP,
+                                  gp_Vec& theV1, gp_Vec& theV2) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
+    Standard_Integer Ideb = 0, Ifin = 0;
+    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  : 
+//=======================================================================
+void GeomAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt& theP,
+                                  gp_Vec& theV1, gp_Vec& theV2) const
+{
+  gp_Vec 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);
+
+  Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
+  Standard_Real anOffsetVal = anOffC->Offset();
+  const gp_Dir& anOffsetDir = anOffC->Direction();
+  CSLib_Offset::D2(theP, theV1, theV2, V3, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV1, theV2);
 }
 
 //=======================================================================
@@ -626,27 +808,71 @@ void GeomAdaptor_Curve::D2(const Standard_Real U,
 //=======================================================================
 
 void GeomAdaptor_Curve::D3(const Standard_Real U, 
-                          gp_Pnt& P, gp_Vec& V1, 
-                          gp_Vec& V2, gp_Vec& V3) const 
+                           gp_Pnt& P, gp_Vec& V1, 
+                           gp_Vec& V2, gp_Vec& V3) const 
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve) &&
-      (U==myFirst || U==myLast) ) {
-    Standard_Integer Ideb, Ifin;
-    if (U==myFirst) {
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    D3BSpline(U, P, V1, V2, V3);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    D3Offset(U, P, V1, V2, V3);
+  else
+    myCurve->D3(U, P, V1, V2, V3);
+}
+
+//=======================================================================
+//function : D3BSpline
+//purpose  : 
+//=======================================================================
+void GeomAdaptor_Curve::D3BSpline(const Standard_Real theU,
+                                  gp_Pnt& theP, gp_Vec& theV1,
+                                  gp_Vec& theV2, gp_Vec& theV3) const
+{
+  if (theU == myFirst || theU == myLast)
+  {
+    Standard_Integer Ideb = 0, Ifin = 0;
+    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  : 
+//=======================================================================
+void GeomAdaptor_Curve::D3Offset(const Standard_Real theU,
+                                 gp_Pnt& theP, gp_Vec& theV1,
+                                 gp_Vec& theV2, gp_Vec& theV3) const
+{
+  myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
+  gp_Vec V4 = myOffsetBaseCurveAdaptor->DN(theU, 4);
+
+  Standard_Boolean IsDirectionChange = Standard_False;
+  if(theV1.SquareMagnitude() <= gp::Resolution())
+    IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
+
+  Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
+  Standard_Real anOffsetVal = anOffC->Offset();
+  const gp_Dir& anOffsetDir = anOffC->Direction();
+  CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffsetDir, anOffsetVal, IsDirectionChange,
+                   theP, theV1, theV2, theV3);
 }
 
 //=======================================================================
@@ -655,11 +881,22 @@ void GeomAdaptor_Curve::D3(const Standard_Real U,
 //=======================================================================
 
 gp_Vec GeomAdaptor_Curve::DN(const Standard_Real    U, 
-                            const Standard_Integer N) const 
+                             const Standard_Integer N) const 
+{
+  if (myTypeCurve == GeomAbs_BSplineCurve)
+    return DNBSpline(U, N);
+  else if (myCurve->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve))
+    return DNOffset(U, N);
+
+  return myCurve->DN(U, N);
+}
+
+gp_Vec GeomAdaptor_Curve::DNBSpline(const Standard_Real    U,
+                                    const Standard_Integer N) const
 {
-  if ( (myTypeCurve == GeomAbs_BSplineCurve) &&
-      (U==myFirst || U==myLast) ) {
-    Standard_Integer Ideb, Ifin;
+  if ((U==myFirst || U==myLast))
+  {
+    Standard_Integer Ideb = 0, Ifin = 0;
     if (U==myFirst) {
       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
       if (Ideb<1) Ideb=1;
@@ -671,10 +908,31 @@ gp_Vec GeomAdaptor_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_Vec GeomAdaptor_Curve::DNOffset(const Standard_Real    U,
+                                   const Standard_Integer N) const
+{
+  gp_Pnt aPnt;
+  gp_Vec 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;
 }
 
 //=======================================================================
@@ -688,23 +946,23 @@ Standard_Real GeomAdaptor_Curve::Resolution(const Standard_Real R3D) const
   case GeomAbs_Line :
     return R3D;
   case GeomAbs_Circle: {
-    Standard_Real R = (*((Handle(Geom_Circle)*)&myCurve))->Circ().Radius();
+    Standard_Real R = Handle(Geom_Circle)::DownCast (myCurve)->Circ().Radius();
     if ( R > R3D/2. )
       return 2*ASin(R3D/(2*R));
     else
       return 2*M_PI;
   }
   case GeomAbs_Ellipse: {
-    return R3D / (*((Handle(Geom_Ellipse)*)&myCurve))->MajorRadius();
+    return R3D / Handle(Geom_Ellipse)::DownCast (myCurve)->MajorRadius();
   }
   case GeomAbs_BezierCurve: {
     Standard_Real res;
-    (*((Handle(Geom_BezierCurve)*)&myCurve))->Resolution(R3D,res);
+    Handle(Geom_BezierCurve)::DownCast (myCurve)->Resolution(R3D,res);
     return res;
   }
   case GeomAbs_BSplineCurve: {
     Standard_Real res;
-    (*((Handle(Geom_BSplineCurve)*)&myCurve))->Resolution(R3D,res);
+    Handle(Geom_BSplineCurve)::DownCast (myCurve)->Resolution(R3D,res);
     return res;
   }
   default:
@@ -726,7 +984,7 @@ Standard_Real GeomAdaptor_Curve::Resolution(const Standard_Real R3D) const
 gp_Lin GeomAdaptor_Curve::Line() const 
 {
   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
-  return (*((Handle(Geom_Line)*)&myCurve))->Lin();  
+  return Handle(Geom_Line)::DownCast (myCurve)->Lin();  
 }
 
 //=======================================================================
@@ -737,7 +995,7 @@ gp_Lin GeomAdaptor_Curve::Line() const
 gp_Circ  GeomAdaptor_Curve::Circle() const 
 {
   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
-  return (*((Handle(Geom_Circle)*)&myCurve))->Circ();
+  return Handle(Geom_Circle)::DownCast (myCurve)->Circ();
 }
 
 //=======================================================================
@@ -748,7 +1006,7 @@ gp_Circ  GeomAdaptor_Curve::Circle() const
 gp_Elips GeomAdaptor_Curve::Ellipse() const 
 {
   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
-  return (*((Handle(Geom_Ellipse)*)&myCurve))->Elips();
+  return Handle(Geom_Ellipse)::DownCast (myCurve)->Elips();
 }
 
 //=======================================================================
@@ -759,7 +1017,7 @@ gp_Elips GeomAdaptor_Curve::Ellipse() const
 gp_Hypr GeomAdaptor_Curve::Hyperbola() const 
 {
   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
-  return (*((Handle(Geom_Hyperbola)*)&myCurve))->Hypr();  
+  return Handle(Geom_Hyperbola)::DownCast (myCurve)->Hypr();  
 }
 
 //=======================================================================
@@ -770,7 +1028,7 @@ gp_Hypr GeomAdaptor_Curve::Hyperbola() const
 gp_Parab GeomAdaptor_Curve::Parabola() const 
 {
   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
-  return (*((Handle(Geom_Parabola)*)&myCurve))->Parab();
+  return Handle(Geom_Parabola)::DownCast (myCurve)->Parab();
 }
 
 //=======================================================================
@@ -781,9 +1039,9 @@ gp_Parab GeomAdaptor_Curve::Parabola() const
 Standard_Integer GeomAdaptor_Curve::Degree() const
 {
   if (myTypeCurve == GeomAbs_BezierCurve)
-    return (*((Handle(Geom_BezierCurve)*)&myCurve))->Degree();
+    return Handle(Geom_BezierCurve)::DownCast (myCurve)->Degree();
   else if (myTypeCurve == GeomAbs_BSplineCurve)
-    return (*((Handle(Geom_BSplineCurve)*)&myCurve))->Degree();
+    return Handle(Geom_BSplineCurve)::DownCast (myCurve)->Degree();
   else
     Standard_NoSuchObject::Raise();
   // portage WNT 
@@ -798,9 +1056,9 @@ Standard_Integer GeomAdaptor_Curve::Degree() const
 Standard_Boolean GeomAdaptor_Curve::IsRational() const {
   switch( myTypeCurve) {
   case GeomAbs_BSplineCurve:
-    return (*((Handle(Geom_BSplineCurve)*)&myCurve))->IsRational();
+    return Handle(Geom_BSplineCurve)::DownCast (myCurve)->IsRational();
   case GeomAbs_BezierCurve:
-    return (*((Handle(Geom_BezierCurve)*)&myCurve))->IsRational();
+    return Handle(Geom_BezierCurve)::DownCast (myCurve)->IsRational();
   default:
     return Standard_False;
   }
@@ -814,9 +1072,9 @@ Standard_Boolean GeomAdaptor_Curve::IsRational() const {
 Standard_Integer GeomAdaptor_Curve::NbPoles() const
 {
   if (myTypeCurve == GeomAbs_BezierCurve)
-    return (*((Handle(Geom_BezierCurve)*)&myCurve))->NbPoles();
+    return Handle(Geom_BezierCurve)::DownCast (myCurve)->NbPoles();
   else if (myTypeCurve == GeomAbs_BSplineCurve)
-    return (*((Handle(Geom_BSplineCurve)*)&myCurve))->NbPoles();
+    return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbPoles();
   else
     Standard_NoSuchObject::Raise();
   // portage WNT
@@ -832,7 +1090,7 @@ Standard_Integer GeomAdaptor_Curve::NbKnots() const
 {
   if ( myTypeCurve != GeomAbs_BSplineCurve)
     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::NbKnots");
-  return (*((Handle(Geom_BSplineCurve)*)&myCurve))->NbKnots();
+  return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbKnots();
 }
 
 //=======================================================================
@@ -844,7 +1102,7 @@ Handle(Geom_BezierCurve) GeomAdaptor_Curve::Bezier() const
 {
  if ( myTypeCurve != GeomAbs_BezierCurve)
     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Bezier");
-  return *((Handle(Geom_BezierCurve)*)&myCurve);
+  return Handle(Geom_BezierCurve)::DownCast (myCurve);
 }
 
 //=======================================================================
@@ -857,6 +1115,59 @@ Handle(Geom_BSplineCurve) GeomAdaptor_Curve::BSpline() const
  if ( myTypeCurve != GeomAbs_BSplineCurve)
     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::BSpline");
 
-  return *((Handle(Geom_BSplineCurve)*)&myCurve);
+  return Handle(Geom_BSplineCurve)::DownCast (myCurve);
 }
 
+
+// ============= Auxiliary functions ===================
+Standard_Boolean AdjustDerivative(const Handle(Adaptor3d_HCurve)& theAdaptor, 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   = 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_Vec V;
+
+  do
+  {
+    V =  theAdaptor->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;
+  theAdaptor->D0(Min(theU, u), P1);
+  theAdaptor->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]) = theAdaptor->DN(theU, anIndex + i) * aSign;
+
+  return IsDirectionChange;
+}