
// File:	GeomAdaptor_Surface.cxx
// Created:	Fri May 14 16:30:25 1993
// Author:	Bruno DUMORTIER
//		<dub@phylox>
// Modified:	Thu Nov 26 16:37:18 1998
// Author:	Joelle CHAUVET
//		correction in NbUIntervals for SurfaceOfLinearExtrusion 
//		(PRO16346)

#define No_Standard_RangeError
#define No_Standard_OutOfRange
#define PosTol Precision::PConfusion()/2
#include <GeomAdaptor_Surface.ixx>
#include <GeomAdaptor_HSurface.hxx>
#include <GeomAdaptor_HCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Adaptor3d_HSurface.hxx>
#include <Standard_OutOfRange.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_BSplineSurface.hxx> 
#include <Geom_BezierSurface.hxx> 
#include <Geom_OffsetSurface.hxx>
//#include <GeomConvert_BSplineSurfaceKnotSplitting.hxx>
#include <Standard_OutOfRange.hxx>
#include <TColStd_HArray1OfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Plane.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_ToroidalSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_SurfaceOfRevolution.hxx>
#include <Geom_SurfaceOfLinearExtrusion.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Circle.hxx>
#include <gp_Circ.hxx>
#include <gp_Lin.hxx>
#include <gp_Trsf.hxx>
#include <BSplCLib.hxx>
#include <Precision.hxx>
#include <Standard_NoSuchObject.hxx>

#define myBspl (*((Handle(Geom_BSplineSurface)*)&mySurface))
#define myExtSurf (*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))
#define myRevSurf (*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))
#define myOffSurf (*((Handle(Geom_OffsetSurface)*)&mySurface))

//=======================================================================
//function : LocalContinuity
//purpose  : 
//=======================================================================

GeomAbs_Shape LocalContinuity(Standard_Integer         Degree,
                              Standard_Integer         Nb,
                              TColStd_Array1OfReal&    TK,
                              TColStd_Array1OfInteger& TM,
                              Standard_Real            PFirst,
                              Standard_Real            PLast,
                              Standard_Boolean         IsPeriodic) 
{
  Standard_DomainError_Raise_if
    ( (TK.Length()!=Nb || TM.Length()!=Nb )," ");
  Standard_Integer Index1 = 0;
  Standard_Integer Index2 = 0;
  Standard_Real newFirst, newLast;
  BSplCLib::LocateParameter
    (Degree,TK,TM,PFirst,IsPeriodic,1,Nb,Index1,newFirst);
  BSplCLib::LocateParameter
    (Degree,TK,TM,PLast, IsPeriodic,1,Nb,Index2,newLast );
  Standard_Real EpsKnot = Precision::PConfusion();
  if (Abs(newFirst-TK(Index1+1))< EpsKnot) Index1++;
  if (Abs(newLast -TK(Index2  ))< EpsKnot) Index2--;
  Standard_Integer Multmax;
  // attention aux courbes peridiques.
  if ( (IsPeriodic) && (Index1 == Nb) )
    Index1 = 1;

  if ( Index2==Index1)
    Multmax = 4;
  else {
    Multmax = TM(Index1+1);
    for (Standard_Integer i = Index1+1; i<=Index2; i++) {
      if ( TM(i)>Multmax) Multmax=TM(i);
    }
    Multmax = Degree - Multmax;
  }
  if ( Multmax <= 0)
    return GeomAbs_C0;
  else if (Multmax == 1)
    return GeomAbs_C1;
  else if (Multmax == 2)
    return GeomAbs_C2;
  else if (Multmax == 3)
    return GeomAbs_C3;
  else
    return GeomAbs_CN;
}

//=======================================================================
//function : GeomAdaptor_Surface
//purpose  : 
//=======================================================================

GeomAdaptor_Surface::GeomAdaptor_Surface(): myTolU(0.), myTolV(0.)
{} 

//=======================================================================
//function : GeomAdaptor_Surface
//purpose  : 
//=======================================================================

GeomAdaptor_Surface::GeomAdaptor_Surface(const Handle(Geom_Surface)& S)  
                     : myTolU(0.), myTolV(0.)
{
  Standard_Real U1,U2,V1,V2;
  S->Bounds(U1,U2,V1,V2);
  Load(S,U1,U2,V1,V2);
}

//=======================================================================
//function : GeomAdaptor_Surface
//purpose  : 
//=======================================================================

GeomAdaptor_Surface::GeomAdaptor_Surface(const Handle(Geom_Surface)& S,
                                         const Standard_Real UFirst,
                                         const Standard_Real ULast,
                                         const Standard_Real VFirst,
                                         const Standard_Real VLast,
					 const Standard_Real TolU,
                                         const Standard_Real TolV)
{
  if(UFirst>ULast || VFirst>VLast) Standard_ConstructionError::Raise();
  Load(S,UFirst,ULast,VFirst,VLast,TolU, TolV);
}

//=======================================================================
//function : Load
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::Load(const Handle(Geom_Surface)& S)
{
  Standard_Real U1,U2,V1,V2;
  S->Bounds(U1,U2,V1,V2);
  Load(S,U1,U2,V1,V2);
}

//=======================================================================
//function : Load
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::Load(const Handle(Geom_Surface)& S,
                               const Standard_Real UFirst,
                               const Standard_Real ULast,
                               const Standard_Real VFirst,
                               const Standard_Real VLast,
			       const Standard_Real TolU,
			       const Standard_Real TolV)
{
  if(UFirst>ULast || VFirst>VLast) Standard_ConstructionError::Raise();

  myTolU =  TolU;
  myTolV =  TolV;  
  myUFirst = UFirst;
  myULast  = ULast;
  myVFirst = VFirst;
  myVLast  = VLast;

  if ( mySurface != S) {
    mySurface = S;
    
    Handle(Standard_Type) TheType = S->DynamicType();
    if ( TheType == STANDARD_TYPE(Geom_BezierSurface))
      mySurfaceType = GeomAbs_BezierSurface;
    else if (TheType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
      Load((*((Handle(Geom_RectangularTrimmedSurface)*)&S))->BasisSurface(),
	   UFirst,ULast,VFirst,VLast);
    }
    else if ( TheType == STANDARD_TYPE(Geom_Plane))
      mySurfaceType = GeomAbs_Plane;
    else if ( TheType == STANDARD_TYPE(Geom_CylindricalSurface))
      mySurfaceType = GeomAbs_Cylinder;
    else if ( TheType == STANDARD_TYPE(Geom_ConicalSurface))
      mySurfaceType = GeomAbs_Cone;
    else if ( TheType == STANDARD_TYPE(Geom_SphericalSurface))
      mySurfaceType = GeomAbs_Sphere;
    else if ( TheType == STANDARD_TYPE(Geom_ToroidalSurface))
      mySurfaceType = GeomAbs_Torus;
    else if ( TheType == STANDARD_TYPE(Geom_SurfaceOfRevolution)) {
      mySurfaceType = GeomAbs_SurfaceOfRevolution;
    }
    else if ( TheType == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)) {
      mySurfaceType = GeomAbs_SurfaceOfExtrusion;
    }
    else if ( TheType == STANDARD_TYPE(Geom_BSplineSurface)) {
      mySurfaceType = GeomAbs_BSplineSurface;
      myBspl        = 	*((Handle(Geom_BSplineSurface)*)&S);
    }
    else if ( TheType == STANDARD_TYPE(Geom_OffsetSurface)) {
      mySurfaceType = GeomAbs_OffsetSurface;
    }
    else
      mySurfaceType = GeomAbs_OtherSurface;
  }
}

//    --
//    --     Global methods - Apply to the whole Surface.
//    --     


//=======================================================================
//function : UContinuity
//purpose  : 
//=======================================================================

GeomAbs_Shape GeomAdaptor_Surface::UContinuity() const 
{
  if (mySurfaceType == GeomAbs_BSplineSurface) {
    Standard_Integer N = myBspl->NbUKnots();
    TColStd_Array1OfReal TK(1,N);
    TColStd_Array1OfInteger TM(1,N);
    myBspl->UKnots(TK);
    myBspl->UMultiplicities(TM);
    return LocalContinuity(myBspl->UDegree(), myBspl->NbUKnots(), TK, TM,
                           myUFirst, myULast, IsUPeriodic());
  }
  else if ( mySurfaceType == GeomAbs_OtherSurface) {
    Standard_NoSuchObject::Raise("GeomAdaptor_Surface");
  }
  else if ( mySurfaceType == GeomAbs_OffsetSurface) {
#ifndef DEB
    switch(BasisSurface()->UContinuity()){
#else
    GeomAbs_Shape cont = BasisSurface()->UContinuity();
    switch(cont){
#endif
    case GeomAbs_CN : 
       return GeomAbs_CN; 
    case GeomAbs_C2 : 
       return GeomAbs_C1; 
    case GeomAbs_C1 : 
       return GeomAbs_C0; 
      default : Standard_NoSuchObject::Raise("GeomAdaptor_Surface::UContinuity");
      
     }
  }
  else if ( mySurfaceType == GeomAbs_SurfaceOfExtrusion) {
    GeomAdaptor_Curve GC
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return GC.Continuity();
  }
  else {
    return GeomAbs_CN;
  }

  // portage WNT
  return GeomAbs_CN;
}

//=======================================================================
//function : VContinuity
//purpose  : 
//=======================================================================

GeomAbs_Shape GeomAdaptor_Surface::VContinuity() const 
{
  if (mySurfaceType == GeomAbs_BSplineSurface) {
    Standard_Integer N = myBspl->NbVKnots();
    TColStd_Array1OfReal TK(1,N);
    TColStd_Array1OfInteger TM(1,N);
    myBspl->VKnots(TK);
    myBspl->VMultiplicities(TM);
    return LocalContinuity(myBspl->VDegree(), myBspl->NbVKnots(), TK, TM,
                           myVFirst, myVLast, IsVPeriodic());
  }
  else if ( mySurfaceType == GeomAbs_OtherSurface)
    Standard_NoSuchObject::Raise("GeomAdaptor_Surface");
  else if ( mySurfaceType == GeomAbs_OffsetSurface) {
#ifndef DEB
    switch(BasisSurface()->VContinuity()){
#else
    GeomAbs_Shape cont = BasisSurface()->VContinuity();
    switch(cont){
#endif
    case GeomAbs_CN : 
       return GeomAbs_CN; 
    case GeomAbs_C2 : 
       return GeomAbs_C1;
    case GeomAbs_C1 : 
       return GeomAbs_C0;
      default : Standard_NoSuchObject::Raise("GeomAdaptor_Surface::VContinuity");
     
    }
  }
  else if ( mySurfaceType == GeomAbs_SurfaceOfRevolution) {
    GeomAdaptor_Curve GC
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myVFirst, myVLast);
    return GC.Continuity();
  }
  else
    return GeomAbs_CN;

  // portage WNT
  return GeomAbs_CN;
}

//=======================================================================
//function : NbUIntervals
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbUIntervals(const GeomAbs_Shape S) const
{
  Standard_Integer myNbUIntervals = 1;
  GeomAdaptor_Curve myBasisCurve;

  if (mySurfaceType==GeomAbs_BSplineSurface) {
    myBasisCurve.Load
      (myBspl->VIso(myBspl->VKnot(myBspl->FirstVKnotIndex())),
       myUFirst,myULast);
    myNbUIntervals = myBasisCurve.NbIntervals(S);
  }
  else if (mySurfaceType==GeomAbs_SurfaceOfExtrusion) {
    myBasisCurve.Load
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    if (myBasisCurve.GetType() == GeomAbs_BSplineCurve)
      myNbUIntervals = myBasisCurve.NbIntervals(S);
  }
  else if (mySurfaceType==GeomAbs_OffsetSurface){
    GeomAbs_Shape BaseS;
    switch(S){
    case GeomAbs_G1:
    case GeomAbs_G2:
      Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
      
    case GeomAbs_C0: BaseS = GeomAbs_C1; break;
    case GeomAbs_C1: BaseS = GeomAbs_C2; break;
    case GeomAbs_C2: BaseS = GeomAbs_C3; break;
    default: BaseS = GeomAbs_CN;
    }
    GeomAdaptor_Surface Sur
      ((*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface());
    myNbUIntervals = Sur.NbUIntervals(BaseS);
  }
  
  return myNbUIntervals;
}

//=======================================================================
//function : NbVIntervals
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbVIntervals(const GeomAbs_Shape S) const
{
  Standard_Integer myNbVIntervals = 1;
  GeomAdaptor_Curve myBasisCurve;

  if (mySurfaceType==GeomAbs_BSplineSurface) {
    myBasisCurve.Load
      (myBspl->UIso(myBspl->UKnot(myBspl->FirstUKnotIndex())),
       myVFirst,myVLast);
    myNbVIntervals = myBasisCurve.NbIntervals(S);
  }
  else if ( mySurfaceType == GeomAbs_SurfaceOfRevolution) {
    myBasisCurve.Load
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myVFirst, myVLast);
    if (myBasisCurve.GetType() == GeomAbs_BSplineCurve)
      myNbVIntervals = myBasisCurve.NbIntervals(S);
  }
  else if (mySurfaceType == GeomAbs_OffsetSurface){
    GeomAbs_Shape BaseS;
    switch(S){
    case GeomAbs_G1:
    case GeomAbs_G2:
      Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
      
    case GeomAbs_C0: BaseS = GeomAbs_C1; break;
    case GeomAbs_C1: BaseS = GeomAbs_C2; break;
    case GeomAbs_C2: BaseS = GeomAbs_C3; break;
    default: BaseS = GeomAbs_CN;
	break;
    }
    GeomAdaptor_Surface Sur
      ((*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface());
    myNbVIntervals = Sur.NbVIntervals(BaseS);
  }

  return myNbVIntervals;
}

//=======================================================================
//function : UIntervals
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::UIntervals(TColStd_Array1OfReal& T,
                                     const GeomAbs_Shape S) const 
{
  Standard_Integer myNbUIntervals = 1;
  GeomAdaptor_Curve myBasisCurve;

  if (mySurfaceType==GeomAbs_BSplineSurface) {
    myBasisCurve.Load
      (myBspl->VIso(myBspl->VKnot(myBspl->FirstVKnotIndex())),
       myUFirst,myULast);
    myNbUIntervals = myBasisCurve.NbIntervals(S);
    myBasisCurve.Intervals(T,S);
  }
  else if (mySurfaceType==GeomAbs_SurfaceOfExtrusion) {
    myBasisCurve.Load
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    if (myBasisCurve.GetType() == GeomAbs_BSplineCurve) {
      myNbUIntervals = myBasisCurve.NbIntervals(S);
      myBasisCurve.Intervals(T,S);
    }
  }
  else if (mySurfaceType == GeomAbs_OffsetSurface){
    GeomAbs_Shape BaseS=GeomAbs_C0;
    switch(S){
    case GeomAbs_G1:
    case GeomAbs_G2:
      Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
      break;
    case GeomAbs_C0: BaseS = GeomAbs_C1; break;
    case GeomAbs_C1: BaseS = GeomAbs_C2; break;
    case GeomAbs_C2: BaseS = GeomAbs_C3; break;
    default: BaseS = GeomAbs_CN;
    }
    GeomAdaptor_Surface Sur
      ((*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface());
    myNbUIntervals = Sur.NbUIntervals(BaseS);
    Sur.UIntervals(T, BaseS);
  }

  T(T.Lower()) = myUFirst;
  T(T.Lower() + myNbUIntervals) = myULast;
}


//=======================================================================
//function : VIntervals
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::VIntervals(TColStd_Array1OfReal& T, 
                                     const GeomAbs_Shape S) const 
{
  Standard_Integer myNbVIntervals = 1;
  GeomAdaptor_Curve myBasisCurve;

  if (mySurfaceType==GeomAbs_BSplineSurface) {
    myBasisCurve.Load(myBspl->UIso(myBspl->UKnot(myBspl->FirstUKnotIndex())),
                      myVFirst,myVLast);
    myNbVIntervals = myBasisCurve.NbIntervals(S);
    myBasisCurve.Intervals(T,S);
  }
  else if ( mySurfaceType == GeomAbs_SurfaceOfRevolution) {
    myBasisCurve.Load
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myVFirst, myVLast);
    if (myBasisCurve.GetType() == GeomAbs_BSplineCurve) {
      myNbVIntervals = myBasisCurve.NbIntervals(S);
      myBasisCurve.Intervals(T,S);
    }
  }
  else if (mySurfaceType == GeomAbs_OffsetSurface){
    GeomAbs_Shape BaseS=GeomAbs_C0;
    switch(S){
    case GeomAbs_G1:
    case GeomAbs_G2:
      Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
      break;
    case GeomAbs_C0: BaseS = GeomAbs_C1; break;
    case GeomAbs_C1: BaseS = GeomAbs_C2; break;
    case GeomAbs_C2: BaseS = GeomAbs_C3; break;
    default: BaseS = GeomAbs_CN;
    }
    GeomAdaptor_Surface Sur
      ((*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface());
    myNbVIntervals = Sur.NbVIntervals(BaseS);
    Sur.VIntervals(T, BaseS);
  }
  
  T(T.Lower()) = myVFirst;
  T(T.Lower() + myNbVIntervals) = myVLast;
}


//=======================================================================
//function : UTrim
//purpose  : 
//=======================================================================

Handle(Adaptor3d_HSurface) GeomAdaptor_Surface::UTrim
(const Standard_Real First,
 const Standard_Real Last ,
 const Standard_Real Tol   ) const 
{
  Handle(GeomAdaptor_HSurface) HS = 
    new GeomAdaptor_HSurface(mySurface,First,Last,
			     myVFirst,myVLast, Tol, myTolV);
  return HS;
}


//=======================================================================
//function : VTrim
//purpose  : 
//=======================================================================

Handle(Adaptor3d_HSurface) GeomAdaptor_Surface::VTrim
(const Standard_Real First,
 const Standard_Real Last ,
 const Standard_Real Tol   ) const 
{
  Handle(GeomAdaptor_HSurface) HS = 
    new GeomAdaptor_HSurface(mySurface,myUFirst,myULast,
			     First,Last, myTolU, Tol);
  return HS;
}


//=======================================================================
//function : IsUClosed
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsUClosed() const 
{
  if (!mySurface->IsUClosed())
    return Standard_False;
  else {
    Standard_Real U1,U2,V1,V2;
    mySurface->Bounds(U1,U2,V1,V2);
    if (mySurface->IsUPeriodic()) {
      return (Abs(Abs(U1-U2)-Abs(myUFirst-myULast))<Precision::PConfusion());
    }
    else {
      return (   Abs(U1-myUFirst)<Precision::PConfusion() 
              && Abs(U2-myULast )<Precision::PConfusion() );
    }
  }
}

//=======================================================================
//function : IsVClosed
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsVClosed() const 
{
  if (!mySurface->IsVClosed())
    return Standard_False;
  else {
    Standard_Real U1,U2,V1,V2;
    mySurface->Bounds(U1,U2,V1,V2);
    if (mySurface->IsVPeriodic()) {
      return (Abs(Abs(V1-V2)-Abs(myVFirst-myVLast))<Precision::PConfusion());
    }
    else {
      return (   Abs(V1-myVFirst)<Precision::PConfusion() 
              && Abs(V2-myVLast )<Precision::PConfusion() );
    }
  }
}

//=======================================================================
//function : IsUPeriodic
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsUPeriodic() const 
{
  return (mySurface->IsUPeriodic());
}

//=======================================================================
//function : UPeriod
//purpose  : 
//=======================================================================

Standard_Real GeomAdaptor_Surface::UPeriod() const 
{
  Standard_NoSuchObject_Raise_if(!IsUPeriodic()," ");
  return mySurface->UPeriod();
}

//=======================================================================
//function : IsVPeriodic
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsVPeriodic() const 
{
  return (mySurface->IsVPeriodic());
}

//=======================================================================
//function : VPeriod
//purpose  : 
//=======================================================================

Standard_Real GeomAdaptor_Surface::VPeriod() const 
{
  Standard_NoSuchObject_Raise_if(!IsVPeriodic()," ");
  return mySurface->VPeriod();
}

//=======================================================================
//function : Value
//purpose  : 
//=======================================================================

gp_Pnt GeomAdaptor_Surface::Value(const Standard_Real U, 
                                  const Standard_Real V) const 
{
  return mySurface->Value(U,V);
}

//=======================================================================
//function : D0
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::D0(const Standard_Real U, 
                             const Standard_Real V, gp_Pnt& P) const 
{
  mySurface->D0(U,V,P);
}


//=======================================================================
//function : D1
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::D1(const Standard_Real U, 
                             const Standard_Real V, 
			     gp_Pnt&       P,
			     gp_Vec&       D1U, 
			     gp_Vec&       D1V ) const 
{
  Standard_Integer Ideb,Ifin,IVdeb,IVfin,USide=0,VSide=0;
  Standard_Real u = U, v = V;
  if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;}
  else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;}
  if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;}
  else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;}

  switch(mySurfaceType) {
  case  GeomAbs_BSplineSurface: 
    {	
      if((USide==0)&&(VSide==0)){
	myBspl->D1(u,v,P,D1U,D1V);
      }
      else { 
	if(IfUVBound(u,v,Ideb,Ifin,IVdeb,IVfin,USide,VSide))
	  myBspl->LocalD1 (u, v, Ideb, Ifin,IVdeb ,IVfin ,P ,D1U,D1V); 
	else myBspl->D1(u,v,P,D1U,D1V);
      }
      break;
    }
      
    case GeomAbs_SurfaceOfExtrusion  :
      
       if(USide==0) myExtSurf->D1(u,v,P,D1U,D1V);
       else myExtSurf->LocalD1(u,v,USide,P,D1U,D1V);
       break;
     
    case GeomAbs_SurfaceOfRevolution :
     
       if(VSide==0) myRevSurf->D1 (u, v, P,D1U,D1V );
       else myRevSurf->LocalD1 (u, v, VSide, P,D1U,D1V );
       break;
     
    case  GeomAbs_OffsetSurface :
      {
	if((USide==0)&&(VSide==0)) myOffSurf->D1 (u, v,P,D1U,D1V ); 
	else   myOffSurf->LocalD1 (u, v, USide, VSide ,P,D1U,D1V ); 
	break;
      }
      default :   
	mySurface->D1(u,v,P,D1U,D1V);
  }
}

//=======================================================================
//function : D2
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::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_Integer  Ideb,Ifin,IVdeb,IVfin,USide=0,VSide=0;
  Standard_Real u = U, v = V;
  if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;}
  else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;}
  if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;}
  else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;}

  switch(mySurfaceType)
    {
    case  GeomAbs_BSplineSurface:
      
       if((USide==0)&&(VSide==0)) myBspl->D2(u,v,P,D1U,D1V,D2U,D2V,D2UV);
       else{
	 if(IfUVBound(u,v,Ideb,Ifin,IVdeb,IVfin,USide,VSide))
	   myBspl->LocalD2 (u, v, Ideb, Ifin,IVdeb ,IVfin ,P ,D1U,D1V,D2U,D2V,D2UV); 
	 else myBspl->D2(u,v,P,D1U,D1V,D2U,D2V,D2UV);
       }
       break;
     
    case GeomAbs_SurfaceOfExtrusion  :
      
       if(USide==0)  myExtSurf->D2(u,v,P,D1U,D1V,D2U,D2V,D2UV);
       else myExtSurf->LocalD2(u,v,USide,P,D1U,D1V,D2U,D2V,D2UV);
       break;
     
    case GeomAbs_SurfaceOfRevolution :
      
       if(VSide==0) myRevSurf->D2 (u, v, P,D1U,D1V,D2U,D2V,D2UV );
       else myRevSurf->LocalD2 (u, v, VSide, P,D1U,D1V,D2U,D2V,D2UV );
       break;
     
    case  GeomAbs_OffsetSurface :
      {
	if((USide==0)&&(VSide==0)) myOffSurf->D2 (u, v,P,D1U,D1V,D2U,D2V,D2UV ); 
	else myOffSurf->LocalD2 (u, v, USide, VSide ,P,D1U,D1V,D2U,D2V,D2UV ); 
	break;
      }
      default :  { mySurface->D2(u,v,P,D1U,D1V,D2U,D2V,D2UV);
		   break;}
    }
}


//=======================================================================
//function : D3
//purpose  : 
//=======================================================================

void GeomAdaptor_Surface::D3(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,
                             gp_Vec& D3U, gp_Vec& D3V, gp_Vec& D3UUV,
                             gp_Vec& D3UVV) const
{  
  Standard_Integer Ideb,Ifin,IVdeb,IVfin,USide=0,VSide=0;
  Standard_Real u = U, v = V;
  if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;}
  else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;}
  if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;}
  else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;}

  switch(mySurfaceType) {
  case  GeomAbs_BSplineSurface:
    
      if((USide==0)&&(VSide==0))
	myBspl->D3(u,v,P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
      else {
	if(IfUVBound(u,v,Ideb,Ifin,IVdeb,IVfin,USide,VSide))
	  myBspl-> LocalD3 (u, v, Ideb, Ifin,IVdeb ,IVfin ,
			    P ,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV); 
	else
	  myBspl->D3(u,v,P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
      }
      break;
    
  case GeomAbs_SurfaceOfExtrusion  :
    
      if(USide==0)  myExtSurf->D3(u,v,P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
      else myExtSurf->LocalD3(u,v,USide,P,D1U,D1V,D2U,D2V,D2UV,
			      D3U,D3V,D3UUV,D3UVV);
      break;
    
  case GeomAbs_SurfaceOfRevolution :
    
      if(VSide==0) myRevSurf->D3 (u, v, P ,D1U,D1V,D2U,D2V,D2UV,
				  D3U,D3V,D3UUV,D3UVV);
      else myRevSurf->LocalD3 (u, v, VSide, P,D1U,D1V,D2U,D2V,D2UV,
			       D3U,D3V,D3UUV,D3UVV );
      break;
    
  case  GeomAbs_OffsetSurface : 
    {
      if((USide==0)&&(VSide==0)) myOffSurf->D3 (u, v,P ,D1U,D1V,D2U,D2V,D2UV,
						D3U,D3V,D3UUV,D3UVV); 
      else   myOffSurf->LocalD3 (u, v, USide, VSide ,P ,D1U,D1V,D2U,D2V,D2UV,
				 D3U,D3V,D3UUV,D3UVV); 
      break; 
    }
    default : {  mySurface->D3(u,v,P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV); 
		 break;}
  }
}

//=======================================================================
//function : DN
//purpose  : 
//=======================================================================

gp_Vec GeomAdaptor_Surface::DN(const Standard_Real    U,
                               const Standard_Real    V, 
                               const Standard_Integer Nu,
                               const Standard_Integer Nv) const 
{
  Standard_Integer Ideb,Ifin,IVdeb,IVfin,USide=0,VSide=0;
  Standard_Real u = U, v = V;
  if (Abs(U-myUFirst) <= myTolU) {USide= 1; u = myUFirst;}
  else if (Abs(U-myULast) <= myTolU) {USide= -1; u = myULast;}
  if (Abs(V-myVFirst) <= myTolV) {VSide= 1; v = myVFirst;}
  else if (Abs(V-myVLast) <= myTolV) {VSide= -1; v = myVLast;}

  switch(mySurfaceType) {
  case  GeomAbs_BSplineSurface:
    
      if((USide==0)&&(VSide==0)) return  myBspl->DN(u,v,Nu,Nv);
      else {
	if(IfUVBound(u,v,Ideb,Ifin,IVdeb,IVfin,USide,VSide))
	  return myBspl->LocalDN (u, v, Ideb, Ifin,IVdeb ,IVfin ,Nu,Nv ); 
	else
	  return  myBspl->DN(u,v,Nu,Nv); 
      }
    
  case GeomAbs_SurfaceOfExtrusion  :
    
      if(USide==0)  return myExtSurf-> DN (u, v,Nu,Nv );
      else return myExtSurf->LocalDN (u, v, USide,Nu,Nv );
    
    case GeomAbs_SurfaceOfRevolution :
      
	if(VSide==0)  return myRevSurf->DN (u, v, Nu, Nv );
	else  return myRevSurf->LocalDN (u, v,VSide, Nu, Nv );
     
  case  GeomAbs_OffsetSurface :
    
      if((USide==0)&&(VSide==0)) return myOffSurf->DN (u, v, Nu, Nv );
      else return myOffSurf->LocalDN (u, v, USide, VSide, Nu, Nv );
#ifndef DEB
    default:
      break ;
#endif       
    }
  
  return mySurface->DN(u,v, Nu, Nv);
}




//=======================================================================
//function : UResolution
//purpose  : 
//=======================================================================

Standard_Real GeomAdaptor_Surface::UResolution
(const Standard_Real R3d) const
{

  Standard_Real Res = 0.;
  if (     mySurfaceType == GeomAbs_SurfaceOfExtrusion) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.Resolution( R3d);
  }    
  else if (mySurfaceType == GeomAbs_Torus) {
    Handle(Geom_ToroidalSurface)& S = 
      *((Handle(Geom_ToroidalSurface)*)&mySurface);
    Standard_Real R = S->MajorRadius() + S->MinorRadius();
    Res = R3d/(2*R);
  }
  else if (mySurfaceType == GeomAbs_Sphere) {
    Handle(Geom_SphericalSurface)& S = 
      *((Handle(Geom_SphericalSurface)*)&mySurface);
    Res = R3d/(2*S->Radius());
  }
  else if (mySurfaceType == GeomAbs_Cylinder) {
    Handle(Geom_CylindricalSurface)& S =
      *((Handle(Geom_CylindricalSurface)*)&mySurface);
    Res = R3d/(2*S->Radius());
  }
  else if (mySurfaceType == GeomAbs_Cone) {
    Standard_Real res=0;
    if (myVLast - myVFirst > 1.e10) {
      // Pas vraiment borne => resolution inconnue
      res = Precision::Parametric(R3d);
    }
    else {
      Handle(Geom_ConicalSurface)& S =
	*((Handle(Geom_ConicalSurface)*)&mySurface);
       Handle(Geom_Curve) C;
      C = S->VIso(myVLast);
      Standard_Real Rayon1 = (*((Handle(Geom_Circle)*)&C))->Radius();
      C = S->VIso(myVFirst);
      Standard_Real Rayon2 = (*((Handle(Geom_Circle)*)&C))->Radius();
      if ( Rayon1 > Rayon2) res = R3d / Rayon1;
      else                  res = R3d / Rayon2;
    }
    return res;
  }  
  else if (mySurfaceType == GeomAbs_Plane)
    return R3d;
  else if (mySurfaceType == GeomAbs_BezierSurface){
    Standard_Real Ures,Vres;
    (*((Handle(Geom_BezierSurface)*)&mySurface))->Resolution(R3d,Ures,Vres);
    return Ures;
  }
  else if (mySurfaceType == GeomAbs_BSplineSurface){
    Standard_Real Ures,Vres;
    (*((Handle(Geom_BSplineSurface)*)&mySurface))->Resolution(R3d,Ures,Vres);
    return Ures;
  }
  else if (mySurfaceType == GeomAbs_OffsetSurface){
    Handle(Geom_Surface) base = (*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface();
    GeomAdaptor_Surface gabase(base,myUFirst,myULast,myVFirst,myVLast);
    return gabase.UResolution(R3d);
  }
  else {
    return Precision::Parametric(R3d);
  }

  if ( Res <= 1.)  
    return 2*ASin(Res);
  
  return 2*PI;
}

//=======================================================================
//function : VResolution
//purpose  : 
//=======================================================================

Standard_Real GeomAdaptor_Surface::VResolution
(const Standard_Real R3d) const
{
  Standard_Real Res = 0.;
  if (mySurfaceType == GeomAbs_SurfaceOfRevolution) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.Resolution( R3d);
  }
  else if (mySurfaceType == GeomAbs_SurfaceOfExtrusion ||
           mySurfaceType == GeomAbs_Cylinder           ||
           mySurfaceType == GeomAbs_Cone               ||
           mySurfaceType == GeomAbs_Plane)               {
    return R3d;
  }
  else if (mySurfaceType == GeomAbs_Torus) {
    Handle(Geom_ToroidalSurface)& S = 
      *((Handle(Geom_ToroidalSurface)*)&mySurface);
    Res = R3d/(2*S->MinorRadius());
  }
  else if (mySurfaceType == GeomAbs_Sphere) {
    Handle(Geom_SphericalSurface)& S =
      *((Handle(Geom_SphericalSurface)*)&mySurface);
    Res = R3d/(2*S->Radius());
  }
  else if (mySurfaceType == GeomAbs_BezierSurface){
    Standard_Real Ures,Vres;
    (*((Handle(Geom_BezierSurface)*)&mySurface))->Resolution(R3d,Ures,Vres);
    return Vres;
  }
  else if (mySurfaceType == GeomAbs_BSplineSurface){
    Standard_Real Ures,Vres;
    (*((Handle(Geom_BSplineSurface)*)&mySurface))->Resolution(R3d,Ures,Vres);
    return Vres;
  }
  else if (mySurfaceType == GeomAbs_OffsetSurface){
    Handle(Geom_Surface) base = (*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface();
    GeomAdaptor_Surface gabase(base,myUFirst,myULast,myVFirst,myVLast);
    return gabase.VResolution(R3d);
  }
  else {
    return Precision::Parametric(R3d);
  }

  if ( Res <= 1.) 
    return 2*ASin(Res);

  return 2*PI;
}

//=======================================================================
//function : Plane
//purpose  : 
//=======================================================================

gp_Pln GeomAdaptor_Surface::Plane() const 
{
  if (mySurfaceType != GeomAbs_Plane) 
    Standard_NoSuchObject::Raise();
  return (*((Handle(Geom_Plane)*)&mySurface))->Pln();
}

//=======================================================================
//function : Cylinder
//purpose  : 
//=======================================================================

gp_Cylinder GeomAdaptor_Surface::Cylinder() const 
{
  if (mySurfaceType != GeomAbs_Cylinder)
    Standard_NoSuchObject::Raise();
  return (*((Handle(Geom_CylindricalSurface)*)&mySurface))->Cylinder();
}

//=======================================================================
//function : Cone
//purpose  : 
//=======================================================================

gp_Cone GeomAdaptor_Surface::Cone() const 
{
  if (mySurfaceType != GeomAbs_Cone)
    Standard_NoSuchObject::Raise();
  return (*((Handle(Geom_ConicalSurface)*)&mySurface))->Cone();
}

//=======================================================================
//function : Sphere
//purpose  : 
//=======================================================================

gp_Sphere GeomAdaptor_Surface::Sphere() const 
{
  if (mySurfaceType != GeomAbs_Sphere)
    Standard_NoSuchObject::Raise();
  return (*((Handle(Geom_SphericalSurface)*)&mySurface))->Sphere();
}

//=======================================================================
//function : Torus
//purpose  : 
//=======================================================================

gp_Torus GeomAdaptor_Surface::Torus() const 
{
  if (mySurfaceType != GeomAbs_Torus)
    Standard_NoSuchObject::Raise();
  return (*((Handle(Geom_ToroidalSurface)*)&mySurface))->Torus(); 
}

//=======================================================================
//function : UDegree
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::UDegree() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->UDegree(); 
  else if ( mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->UDegree(); 
  else if ( mySurfaceType == GeomAbs_SurfaceOfExtrusion) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.Degree();
  }
  else
    Standard_NoSuchObject::Raise(" ");
  // portage WNT
  return 0;
}

//=======================================================================
//function : NbUPoles
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbUPoles() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->NbUPoles(); 
  else if ( mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->NbUPoles(); 
  else if ( mySurfaceType == GeomAbs_SurfaceOfExtrusion) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.NbPoles();
  }
  else
    Standard_NoSuchObject::Raise(" ");
  // portage WNT
  return 0;
}

//=======================================================================
//function : VDegree
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::VDegree() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->VDegree(); 
  else if ( mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->VDegree(); 
  else if ( mySurfaceType == GeomAbs_SurfaceOfRevolution) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.Degree();
  }
  else
    Standard_NoSuchObject::Raise(" ");
  // portage WNT
  return 0;
}

//=======================================================================
//function : NbVPoles
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbVPoles() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->NbVPoles(); 
  else if ( mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->NbVPoles(); 
  else if ( mySurfaceType == GeomAbs_SurfaceOfRevolution){
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.NbPoles();
  }
  else
    Standard_NoSuchObject::Raise(" ");
  // portage WNT
  return 0;
}

//=======================================================================
//function : NbUKnots
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbUKnots() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->NbUKnots(); 
  else if ( mySurfaceType == GeomAbs_SurfaceOfExtrusion) {
    GeomAdaptor_Curve myBasisCurve
      ((*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve(),
       myUFirst, myULast);
    return myBasisCurve.NbKnots();
  }
  else
    Standard_NoSuchObject::Raise(" ");
  // portage WNT
  return 0;
}

//=======================================================================
//function : NbVKnots
//purpose  : 
//=======================================================================

Standard_Integer GeomAdaptor_Surface::NbVKnots() const 
{
  if (mySurfaceType != GeomAbs_BSplineSurface)
    Standard_NoSuchObject::Raise(" ");
  return (*((Handle(Geom_BSplineSurface)*)&mySurface))->NbVKnots(); 
}
//=======================================================================
//function : IsURational
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsURational() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->IsURational(); 
  else if (mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->IsURational(); 
  else
    return Standard_False;
}

//=======================================================================
//function : IsVRational
//purpose  : 
//=======================================================================

Standard_Boolean GeomAdaptor_Surface::IsVRational() const {
  if (mySurfaceType == GeomAbs_BSplineSurface)
    return (*((Handle(Geom_BSplineSurface)*)&mySurface))->IsVRational(); 
  else if (mySurfaceType == GeomAbs_BezierSurface)
    return (*((Handle(Geom_BezierSurface)*)&mySurface))->IsVRational(); 
  else
    return Standard_False;
}

//=======================================================================
//function : Bezier
//purpose  : 
//=======================================================================

Handle(Geom_BezierSurface) GeomAdaptor_Surface::Bezier() const 
{
  if (mySurfaceType != GeomAbs_BezierSurface)  
    Standard_NoSuchObject::Raise(" GeomAdaptor_Surface::Bezier()");
  return *((Handle(Geom_BezierSurface)*)&mySurface);
}

//=======================================================================
//function : BSpline
//purpose  : 
//=======================================================================

Handle(Geom_BSplineSurface) GeomAdaptor_Surface::BSpline() const 
{
  if (mySurfaceType != GeomAbs_BSplineSurface)  
    Standard_NoSuchObject::Raise(" GeomAdaptor_Surface::BSpline()");
  return *((Handle(Geom_BSplineSurface)*)&mySurface);
}

//=======================================================================
//function : AxeOfRevolution
//purpose  : 
//=======================================================================

gp_Ax1 GeomAdaptor_Surface::AxeOfRevolution() const 
{
  if (mySurfaceType !=  GeomAbs_SurfaceOfRevolution)  
    Standard_NoSuchObject::Raise(" GeomAdaptor_Surface::AxeOfRevolution");  
  return (*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->Axis();
}

//=======================================================================
//function : Direction
//purpose  : 
//=======================================================================

gp_Dir GeomAdaptor_Surface::Direction() const 
{
  if (mySurfaceType !=  GeomAbs_SurfaceOfExtrusion)  
    Standard_NoSuchObject::Raise(" GeomAdaptor_Surface::Direction");
  return (*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->Direction();
}

//=======================================================================
//function : BasisCurve
//purpose  : 
//=======================================================================

Handle(Adaptor3d_HCurve) GeomAdaptor_Surface::BasisCurve() const 
{
  Handle(GeomAdaptor_HCurve) AC;
  Handle(Geom_Curve) C;
  if (mySurfaceType == GeomAbs_SurfaceOfExtrusion)
    C = (*((Handle(Geom_SurfaceOfLinearExtrusion)*)&mySurface))->BasisCurve();
  else if (mySurfaceType == GeomAbs_SurfaceOfRevolution)
    C = (*((Handle(Geom_SurfaceOfRevolution)*)&mySurface))->BasisCurve();
  else
    Standard_NoSuchObject::Raise("GeomAdaptor_Surface::BasisCurve");
  AC = new GeomAdaptor_HCurve(C);
  return AC;
}

//=======================================================================
//function : BasisSurface
//purpose  : 
//=======================================================================

Handle(Adaptor3d_HSurface) GeomAdaptor_Surface::BasisSurface() const 
{
  if (mySurfaceType != GeomAbs_OffsetSurface) 
    Standard_NoSuchObject::Raise("GeomAdaptor_Surface::BasisSurface");
  return new GeomAdaptor_HSurface
    ((*((Handle(Geom_OffsetSurface)*)&mySurface))->BasisSurface(),
     myUFirst,myULast,myVFirst,myVLast);
}

//=======================================================================
//function : OffsetValue
//purpose  : 
//=======================================================================

Standard_Real GeomAdaptor_Surface::OffsetValue() const 
{
  if (mySurfaceType != GeomAbs_OffsetSurface) 
    Standard_NoSuchObject::Raise("GeomAdaptor_Surface::BasisSurface");
  return (*((Handle(Geom_OffsetSurface)*)&mySurface))->Offset();
}

//=======================================================================
//function : IfUVBound <private>
//purpose  :  locates U,V parameters if U,V =First, Last, 
//	      processes the finding span and returns the 
//	      parameters for LocalDi     
//=======================================================================
Standard_Boolean GeomAdaptor_Surface::IfUVBound(const Standard_Real U,
						const Standard_Real V,
						Standard_Integer& IOutDeb,
						Standard_Integer& IOutFin,
						Standard_Integer& IOutVDeb,
						Standard_Integer& IOutVFin,
						const Standard_Integer USide,
						const Standard_Integer VSide) const
{
 Standard_Integer Ideb,Ifin,IVdeb,IVfin;
 Standard_Boolean Local = Standard_False;
 myBspl->LocateU(U, PosTol, Ideb, Ifin, Standard_False);
 if(Ideb == Ifin) Local = Standard_True;
 Span(USide,Ideb,Ifin,Ideb,Ifin,myBspl->NbUKnots());

 myBspl->LocateV(V, PosTol, IVdeb, IVfin, Standard_False); 
 if(IVdeb == IVfin) Local = Standard_True;
 Span(VSide,IVdeb,IVfin,IVdeb,IVfin,myBspl->NbVKnots());

 IOutDeb=Ideb;   IOutFin=Ifin; 
 IOutVDeb=IVdeb; IOutVFin=IVfin;

 return Local;
}     

//=======================================================================
//function : Span <private>
//purpose  : locates U,V parameters if U=UFirst or U=ULast, 
//	     processes the finding span and returns the 
//	     parameters for LocalDi   
//=======================================================================
void GeomAdaptor_Surface::Span(const Standard_Integer Side,
			       const Standard_Integer  Ideb,
			       const Standard_Integer  Ifin,
			       Standard_Integer& OutIdeb,
			       Standard_Integer& OutIfin,
			       const Standard_Integer NbKnots) const
{
  if(Ideb!=Ifin)//not a knot
    { 
      if(Ideb<1) 
	{OutIdeb=1;    OutIfin=2;
        }else
      if(Ifin>NbKnots)
	{ OutIfin=NbKnots; OutIdeb=NbKnots-1;
	}else
      if(Ideb>=(NbKnots-1))
	{OutIdeb=NbKnots-1; OutIfin=NbKnots;
	}else
      if(Ifin<=2)
	{OutIfin=2; OutIdeb=1;
        }else
      if(Ideb>Ifin)
	{OutIdeb=Ifin-1;   OutIfin=Ifin;
	}else
	{ OutIdeb=Ideb;   OutIfin=Ifin; }
    }
  else
    if(Ideb==Ifin)// is a knot
      {
      if(Ideb<=1){ OutIdeb=1;   OutIfin=2;}//first knot
      else
      if(Ifin>=NbKnots) { OutIdeb=NbKnots-1;OutIfin=NbKnots;}//last knot
      else
       {
	if(Side==-1){OutIdeb=Ideb-1;   OutIfin=Ifin;}
	else {OutIdeb=Ideb;   OutIfin=Ifin+1;}
       } 
      }
}
