// File:	DrawTrSurf_1.cxx
// Created:	Thu Aug 12 19:33:03 1993
// Author:	Bruno DUMORTIER
//		<dub@topsn3>
// Modified by xab, Tue Mar 11 18:31:18 1997
// Modified by PMN 14/04/97 : Passage a Geomlite
// Modified by JPI 01/08/97 : ajout de la commande approxcurve

#include <GeomliteTest.hxx>
#include <Draw_Appli.hxx>
#include <DrawTrSurf.hxx>
#include <DrawTrSurf_Curve.hxx>
#include <DrawTrSurf_Curve2d.hxx>
#include <DrawTrSurf_BezierCurve.hxx>
#include <DrawTrSurf_BSplineCurve.hxx>
#include <DrawTrSurf_BezierCurve2d.hxx>
#include <DrawTrSurf_BSplineCurve2d.hxx>
#include <Draw_Marker3D.hxx>
#include <Draw_Marker2D.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_Color.hxx>
#include <Draw_Display.hxx>

#include <BSplCLib.hxx>

#include <gp.hxx>
#include <gp_Pln.hxx>
#include <gp_Parab2d.hxx>
#include <gp_Elips2d.hxx>
#include <gp_Hypr2d.hxx>

#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Parabola.hxx>
#include <Geom_Hyperbola.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomAdaptor_HSurface.hxx>

#include <GeomLib.hxx>
#include <GeomConvert.hxx>
#include <Geom2dConvert.hxx>

#include <Geom2d_Line.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2d_Ellipse.hxx>
#include <Geom2d_Parabola.hxx>
#include <Geom2d_Hyperbola.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>

#include <GeomLProp.hxx>
#include <GeomLProp_CLProps.hxx>
#include <Geom2dLProp_CLProps2d.hxx>
#include <Geom2dLProp_CurAndInf2d.hxx>

#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>

#include <GeomAbs_SurfaceType.hxx>
#include <GeomAbs_CurveType.hxx>

#include <Precision.hxx>

#include <stdio.h>

#include <TColStd_HArray1OfReal.hxx>
#include <TColStd_HArray2OfReal.hxx>
#include <TColStd_HArray1OfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>

#include <TColGeom_HArray1OfBSplineCurve.hxx>
#include <TColGeom2d_HArray1OfBSplineCurve.hxx>
#include <Convert_CompPolynomialToPoles.hxx>
#include <CPnts_AbscissaPoint.hxx>
#include <GCPnts_AbscissaPoint.hxx>

#include <PLib.hxx> 
#include <GeomAbs_Shape.hxx>
#include <Geom_Curve.hxx>
#include <GeomConvert.hxx>
#include <GeomConvert_ApproxCurve.hxx>
#include <Geom2dConvert_ApproxCurve.hxx>
#include <Geom2d_Curve.hxx>

#include <GeomAdaptor_HCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Geom2dAdaptor_HCurve.hxx>
#include <GeomAdaptor_HCurve.hxx>
#include <Approx_CurvilinearParameter.hxx>
#include <Approx_CurveOnSurface.hxx>
#ifdef WNT
Standard_IMPORT Draw_Viewer dout;
#endif

//=======================================================================
//function : anacurve
//purpose  : 
//=======================================================================

static Standard_Integer anacurve (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 5) return 1;

  Handle(Geom_Geometry) result;
  Handle(Geom2d_Curve)  result2d;

  if (!strcmp(a[0],"line")) {
    if (n == 6)
      result2d = new Geom2d_Line(gp_Pnt2d(atof(a[2]),atof(a[3])),
				 gp_Dir2d(atof(a[4]),atof(a[5])));
    else if (n == 8)
      result = new Geom_Line(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
			     gp_Dir(atof(a[5]),atof(a[6]),atof(a[7])));
    else
      return 1;
  }

  else if (!strcmp(a[0],"circle")) {
    if (n == 5)
      result2d = 
	new Geom2d_Circle(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				   gp_Dir2d(1,0)),
			  atof(a[4]));
    else if (n == 6)
      result = 
	new Geom_Circle(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
			       gp_Dir(0,0,1)),
			atof(a[5]));
    else if (n == 7)
      result2d =
	new Geom2d_Circle(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				   gp_Dir2d(atof(a[4]),atof(a[5]))),
			  atof(a[6]));
    else if (n == 9)
      result = 
	new Geom_Circle(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
			       gp_Dir(atof(a[5]),atof(a[6]),atof(a[7]))),
			atof(a[8]));
    else if (n == 12)
      result = 
	new Geom_Circle(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
			       gp_Dir(atof(a[5]),atof(a[6]),atof(a[7])),
			       gp_Dir(atof(a[8]),atof(a[9]),atof(a[10]))),
			atof(a[11]));
    else
      return 1;
  }
  
  else if (!strcmp(a[0],"parabola")) {
    if (n == 5)
      result2d = 
	new Geom2d_Parabola(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				     gp_Dir2d(1,0)),
			    atof(a[4]));
    else if (n == 6)
      result = 
	new Geom_Parabola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				 gp_Dir(0,0,1)),
			  atof(a[5]));
    else if (n == 7)
      result2d = 
	new Geom2d_Parabola(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				     gp_Dir2d(atof(a[4]),atof(a[5]))),
			    atof(a[6]));
    else if (n == 9)
      result = 
	new Geom_Parabola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				 gp_Dir(atof(a[5]),atof(a[6]),atof(a[7]))),
			  atof(a[8]));
    else if (n == 12)
      result = 
	new Geom_Parabola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				 gp_Dir(atof(a[5]),atof(a[6]),atof(a[7])),
				 gp_Dir(atof(a[8]),atof(a[9]),atof(a[10]))),
			  atof(a[11]));
    else
      return 1;
  }
  
  else if (!strcmp(a[0],"ellipse")) {
    if (n == 6)
      result2d = 
	new Geom2d_Ellipse(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				    gp_Dir2d(1,0)),
			   atof(a[4]),atof(a[5]));
    else if (n == 7)
      result = 
	new Geom_Ellipse(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				gp_Dir(0,0,1)),
			 atof(a[5]),atof(a[6]));
    else if (n == 8)
      result2d = 
	new Geom2d_Ellipse(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				    gp_Dir2d(atof(a[4]),atof(a[5]))),
			   atof(a[6]), atof(a[7]));
    else if (n == 10)
      result = 
	new Geom_Ellipse(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				gp_Dir(atof(a[5]),atof(a[6]),atof(a[7]))),
			 atof(a[8]), atof(a[9]));
    else if (n == 13)
      result = 
	new Geom_Ellipse(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				gp_Dir(atof(a[5]),atof(a[6]),atof(a[7])),
				gp_Dir(atof(a[8]),atof(a[9]),atof(a[10]))),
			 atof(a[11]), atof(a[12]));
    else
      return 1;
  }
  
  else if (!strcmp(a[0],"hyperbola")) {
    if (n == 6)
      result2d = 
	new Geom2d_Hyperbola(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				      gp_Dir2d(1,0)),
			     atof(a[4]),atof(a[5]));
    else if (n == 7)
      result = 
	new Geom_Hyperbola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				  gp_Dir(0,0,1)),
			   atof(a[5]),atof(a[6]));
    else if (n == 8)
      result2d = 
	new Geom2d_Hyperbola(gp_Ax22d(gp_Pnt2d(atof(a[2]),atof(a[3])),
				      gp_Dir2d(atof(a[4]),atof(a[5]))),
			     atof(a[6]), atof(a[7]));
    else if (n == 10)
      result = 
	new Geom_Hyperbola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				  gp_Dir(atof(a[5]),atof(a[6]),atof(a[7]))),
			   atof(a[8]), atof(a[9]));
    else if (n == 13)
      result = 
	new Geom_Hyperbola(gp_Ax2(gp_Pnt(atof(a[2]),atof(a[3]),atof(a[4])),
				  gp_Dir(atof(a[5]),atof(a[6]),atof(a[7])),
				  gp_Dir(atof(a[8]),atof(a[9]),atof(a[10]))),
			   atof(a[11]), atof(a[12]));
    else
      return 1;
  }
  
  if (!result.IsNull())
    DrawTrSurf::Set(a[1],result);
  else if (!result2d.IsNull())
    DrawTrSurf::Set(a[1],result2d);
  else
    return 1;

  return 0;
}

//=======================================================================
//function : polecurve
//purpose  : 
//=======================================================================

static Standard_Integer polecurve (Draw_Interpretor& , Standard_Integer n, char** a)
{
  Standard_Integer k,i;


  if (n < 3) return 1;

  if (!strcmp(a[0],"beziercurve")) {
    
    Standard_Integer np = atoi(a[2]);
    if (np == 0) return 1;
    
    i = (n - 3) / (np);
    if (i < 3 || i > 4) return 1;
    Standard_Boolean hasw = i == 4;
    
    TColgp_Array1OfPnt poles(1,np);
    TColStd_Array1OfReal weights(1,np);
    
    k = 3;
    for (i = 1; i <= np; i++) {
      poles(i).SetCoord(atof(a[k]),atof(a[k+1]),atof(a[k+2]));
      k += 3;
      if (hasw) {
	weights(i) = atof(a[k]);
	k++;
      }
    }
    
    Handle(Geom_BezierCurve) result;
    if (hasw)
      result = new Geom_BezierCurve(poles,weights);
    else
      result = new Geom_BezierCurve(poles);
    
    DrawTrSurf::Set(a[1],result);
  }
  
  else if (!strcmp((*a[0] == 'p') ? a[0]+1 : a[0],"bsplinecurve")) {
    Standard_Integer deg = atoi(a[2]);
    Standard_Integer nbk = atoi(a[3]);

    TColStd_Array1OfReal    knots(1, nbk);
    TColStd_Array1OfInteger mults(1, nbk);
    k = 4;
    Standard_Integer Sigma = 0;
    for (i = 1; i<=nbk; i++) {
      knots( i) = atof(a[k]);
      k++;
      mults( i) = atoi(a[k]);
      Sigma += mults(i);
      k++;
    }

    Standard_Boolean periodic = *a[0] == 'p';
    Standard_Integer np;
    if (periodic)
      np = Sigma - mults(nbk);
    else
      np = Sigma - deg  -1;

    TColgp_Array1OfPnt   poles  (1, np);
    TColStd_Array1OfReal weights(1, np);
    
    for (i = 1; i <= np; i++) {
      poles(i).SetCoord(atof(a[k]),atof(a[k+1]),atof(a[k+2]));
      k += 3;
      weights(i) = atof(a[k]);
      k++;
    }
    
    Handle(Geom_BSplineCurve) result =
      new Geom_BSplineCurve(poles, weights, knots, mults, deg, periodic);
    DrawTrSurf::Set(a[1],result);
  }
  
  return 0;
}

//=======================================================================
//function : polecurve2d
//purpose  : 
//=======================================================================

static Standard_Integer polecurve2d (Draw_Interpretor& , Standard_Integer n, char** a)
{
  Standard_Integer k,i;


  if (n < 3) return 1;

  if (!strcmp(a[0],"2dbeziercurve")) {
    
    Standard_Integer np = atoi(a[2]);
    if (np == 0) return 1;
    
    i = (n - 2) / (np);
    if (i < 2 || i > 3) return 1;
    Standard_Boolean hasw = i == 3;
    
    TColgp_Array1OfPnt2d poles(1,np);
    TColStd_Array1OfReal weights(1,np);
    
    k = 3;
    for (i = 1; i <= np; i++) {
      poles(i).SetCoord(atof(a[k]),atof(a[k+1]));
      k += 2;
      if (hasw) {
	weights(i) = atof(a[k]);
	k++;
      }
    }
    
    Handle(Geom2d_BezierCurve) result;
    if (hasw)
      result = new Geom2d_BezierCurve(poles,weights);
    else
      result = new Geom2d_BezierCurve(poles);
    
    DrawTrSurf::Set(a[1],result);
  }
  
  else if (!strcmp((*(a[0]+2) == 'p') ? a[0]+3 : a[0]+2,"bsplinecurve")) {
    Standard_Integer deg = atoi(a[2]);
    Standard_Integer nbk = atoi(a[3]);

    TColStd_Array1OfReal    knots(1, nbk);
    TColStd_Array1OfInteger mults(1, nbk);
    k = 4;
    Standard_Integer Sigma = 0;
    for (i = 1; i<=nbk; i++) {
      knots( i) = atof(a[k]);
      k++;
      mults( i) = atoi(a[k]);
      Sigma += mults(i);
      k++;
    }

    Standard_Boolean periodic = *(a[0]+2) == 'p';
    Standard_Integer np;
    if (periodic)
      np = Sigma - mults(nbk);
    else
      np = Sigma - deg  -1;

    TColgp_Array1OfPnt2d poles  (1, np);
    TColStd_Array1OfReal weights(1, np);
    
    for (i = 1; i <= np; i++) {
      poles(i).SetCoord(atof(a[k]),atof(a[k+1]));
      k += 2;
      weights(i) = atof(a[k]);
      k++;
    }
    
    Handle(Geom2d_BSplineCurve) result =
      new Geom2d_BSplineCurve(poles, weights, knots, mults, deg, periodic);
    DrawTrSurf::Set(a[1],result);
  }
  
  return 0;
}

//=======================================================================
//function : reverse
//purpose  : 
//=======================================================================

static Standard_Integer reverse (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 2) return 1;

  Standard_Integer i;
  for (i = 1; i < n; i++) {

    Handle(Geom_Curve) GC = DrawTrSurf::GetCurve(a[i]);
    if (!GC.IsNull()) {
      GC->Reverse();
      Draw::Repaint();
    }
    Handle(Geom2d_Curve) GC2d = DrawTrSurf::GetCurve2d(a[i]);
    if (!GC2d.IsNull()) {
      GC2d->Reverse();
      Draw::Repaint();
    }
  }
  return 0;
}

//=======================================================================
//function : cmovepole
//purpose  : 
//=======================================================================

static Standard_Integer cmovepole (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 5) return 1;

  Standard_Real dx = atof(a[3]);
  Standard_Real dy = atof(a[4]);
  Standard_Real dz=0;
  if (n >= 6) dz = atof(a[5]);
  Standard_Integer Index = atoi(a[2]);

  Handle(Geom_BezierCurve) G1 = DrawTrSurf::GetBezierCurve(a[1]);
  if (!G1.IsNull()) {
    gp_Pnt P = G1->Pole(Index);
    P.SetCoord(P.X()+dx, P.Y()+dy, P.Z()+dz);
    G1->SetPole(Index,P);
    Draw::Repaint();
    return 0;
  }


  Handle(Geom_BSplineCurve) G2 = DrawTrSurf::GetBSplineCurve(a[1]);
  if (!G2.IsNull()) {
    gp_Pnt P = G2->Pole(Index);
    P.SetCoord(P.X()+dx, P.Y()+dy, P.Z()+dz);
    G2->SetPole(Index,P);
    Draw::Repaint();
    return 0;
  }

  Handle(Geom2d_BezierCurve) G3 = DrawTrSurf::GetBezierCurve2d(a[1]);
  if (!G3.IsNull()) {
    gp_Pnt2d P = G3->Pole(Index);
    P.SetCoord(P.X()+dx, P.Y()+dy);
    G3->SetPole(Index,P);
    Draw::Repaint();
    return 0;
  }


  Handle(Geom2d_BSplineCurve) G4 = DrawTrSurf::GetBSplineCurve2d(a[1]);
  if (!G4.IsNull()) {
    gp_Pnt2d P = G4->Pole(Index);
    P.SetCoord(P.X()+dx, P.Y()+dy);
    G4->SetPole(Index,P);
    Draw::Repaint();
    return 0;
  }



  return 0;
}

//=======================================================================
//function : cmovetangent
//purpose  : 
//=======================================================================

static Standard_Integer cmovetangent (Draw_Interpretor& di, Standard_Integer n, char** a)
{
  Standard_Integer dimension,
  condition,
  error_status ;
  Standard_Real u,
  x,
  y,
  z,
  tolerance,
  tx,
  ty,
  tz ;
  u = atof(a[2]);
  x = atof(a[3]);
  y = atof(a[4]);
  z = 0.0e0,
  tolerance = 1.0e-5 ;
  dimension = 3 ;
  if (n <= 8) {
    dimension = 2 ;
    if (n < 7) {
      return 1 ;
    }
  }
  else {
    dimension = 3 ;
    if (n < 9) {
      return 1 ;
    }
  }
  condition = 0 ;
  error_status  = 0 ;
  if (dimension == 3) {
    Handle(Geom_BSplineCurve) G2 = DrawTrSurf::GetBSplineCurve(a[1]);
    if (!G2.IsNull()) {
      z  = atof(a[5]) ;
      tx = atof(a[6]) ;
      ty = atof(a[7]) ;
      tz = atof(a[8]) ;
      if (n == 10) {
	condition = Max(atoi(a[9]), -1)  ;
	condition = Min(condition, G2->Degree()-1) ;
      }
      gp_Pnt p;
      gp_Vec tangent ;
      p.SetCoord(x,y,z);
      tangent.SetCoord(tx,ty,tz) ;
      
      G2->MovePointAndTangent(u, 
			      p, 
			      tangent,
			      tolerance,
			      condition,
			      condition,
			      error_status) ;
      if (! error_status) {
	Draw::Repaint();
	}
      else {
	di << "Not enought degree of freedom increase degree please" << "\n";
      }
      
      return 0;
    }
  }
  else {
    Handle(Geom2d_BSplineCurve) G2 = DrawTrSurf::GetBSplineCurve2d(a[1]);
    if (!G2.IsNull()) {
      tx = atof(a[5]) ;
      ty = atof(a[6]) ;
      if (n == 8) {
	condition = Max(atoi(a[7]), -1)  ;
	condition = Min(condition, G2->Degree()-1) ;
      }
      gp_Pnt2d p;
      gp_Vec2d tangent ;
      p.SetCoord(x,y);
      tangent.SetCoord(tx,ty) ;
      
      G2->MovePointAndTangent(u, 
			      p, 
			      tangent,
			      tolerance,
			      condition,
			      condition,
			      error_status) ;
      if (! error_status) {
	Draw::Repaint();
	}
      else {
	di << "Not enought degree of freedom increase degree please" << "\n";
      }
      
      return 0;
    }
   } 
  return 0;
}


//=======================================================================
//function : cmovepoint
//purpose  : 
//=======================================================================

static Standard_Integer cmovepoint (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 5) return 1;

  Standard_Real dx = atof(a[3]);
  Standard_Real dy = atof(a[4]);
  Standard_Real dz=0;
  if (n >= 6 && n != 7) dz = atof(a[5]);
  Standard_Real u = atof(a[2]);
  Standard_Integer index1 = 0;
  Standard_Integer index2 = 0;
  Standard_Integer fmodif, lmodif;
  if (n == 7) {
    index1 = atoi(a[5]);
    index2 = atoi(a[6]);
  }
  else if (n == 8) {
    index1 = atoi(a[6]);
    index2 = atoi(a[7]);
  }

  Handle(Geom_BSplineCurve) G2 = DrawTrSurf::GetBSplineCurve(a[1]);
  if (!G2.IsNull()) {
    if (index1 == 0) {
      index1 = 2;
      index2 = G2->NbPoles()-1;
    }
    gp_Pnt p;
    G2->D0(u, p);
    p.SetCoord(p.X()+dx, p.Y()+dy, p.Z()+dz);
    G2->MovePoint(u, p, index1, index2, fmodif, lmodif);
    Draw::Repaint();
    return 0;
  }

  Handle(Geom2d_BSplineCurve) G4 = DrawTrSurf::GetBSplineCurve2d(a[1]);
  if (!G4.IsNull()) {
    if (index1 == 0) {
      index1 = 2;
      index2 = G4->NbPoles()-1;
    }
    gp_Pnt2d p;
    G4->D0(u, p);
    p.SetCoord(p.X()+dx, p.Y()+dy);
    G4->MovePoint(u, p, index1, index2, fmodif, lmodif);
    Draw::Repaint();
    return 0;
  }
  return 0;
}

//=======================================================================
//function : cinsertknot
//purpose  : 
//=======================================================================

static Standard_Integer cinsertknot (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 4) return 1;

  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  if (GBs.IsNull() && GBs2d.IsNull()) return 1;

  if (n <= 4) {
    Standard_Real    knot = atof(a[2]);
    Standard_Integer mult = 1;
    if (n == 4) mult = atoi(a[3]);
    if (!GBs.IsNull())
      GBs->InsertKnot(knot,mult,Precision::PConfusion());
    else
      GBs2d->InsertKnot(knot,mult,Precision::PConfusion());
  }

  else {
    // multiple insertion
    if (n % 2 != 0) return 1;
    Standard_Integer i,nbk = (n-2) / 2;
    TColStd_Array1OfReal    knots(1,nbk);
    TColStd_Array1OfInteger mults(1,nbk);
    for (i = 2; i < n; i += 2) {
      knots(i/2) = atof(a[i]);
      mults(i/2) = atoi(a[i+1]);
    }

    if (!GBs.IsNull())
      GBs->InsertKnots(knots,mults,Precision::PConfusion());
    else
      GBs2d->InsertKnots(knots,mults,Precision::PConfusion());

  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : csetknot
//purpose  : 
//=======================================================================

static Standard_Integer csetknot (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 4) return 1;

  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  if (GBs.IsNull() && GBs2d.IsNull()) return 1;

  Standard_Integer index = atoi(a[2]);
  Standard_Real    knot  = atof(a[3]);

  if ( n == 4) {
    if (!GBs.IsNull())
      GBs->SetKnot(index,knot);
    else
      GBs2d->SetKnot(index,knot);
  }
  else {
    Standard_Integer mult  = atoi(a[4]);
    if (!GBs.IsNull())
      GBs->SetKnot(index,knot,mult);
    else
      GBs2d->SetKnot(index,knot,mult);
  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : cremknot
//purpose  : 
//=======================================================================

static Standard_Integer cremknot (Draw_Interpretor& di, Standard_Integer n, char** a)
{
  if (n < 3) return 1;

  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  if (GBs.IsNull() && GBs2d.IsNull()) return 1;

  Standard_Integer index = atoi(a[2]);
  Standard_Integer mult  = 0;
  if (n >= 4) mult = atoi(a[3]);

  Standard_Real tol = RealLast();
  if (n >= 5) tol = atof(a[4]);

  if (!GBs.IsNull()) {
    if (!GBs->RemoveKnot(index,mult,tol))
      di << "Remove knots failed"<<"\n";
  }
  else {
    if (!GBs2d->RemoveKnot(index,mult,tol))
      di << "Remove knots failed"<<"\n";
  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : increasedegree
//purpose  : 
//=======================================================================

static Standard_Integer increasedegree (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 3) return 1;

  Standard_Integer Deg = atoi(a[2]);

  Handle(Geom_BezierCurve) GBz = DrawTrSurf::GetBezierCurve(a[1]);
  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BezierCurve) GBz2d = DrawTrSurf::GetBezierCurve2d(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  if (!GBz.IsNull()) 
    GBz->Increase(Deg);
  else if (!GBs.IsNull())
    GBs->IncreaseDegree(Deg);
  else if (!GBz2d.IsNull()) 
    GBz2d->Increase(Deg);
  else if (!GBs2d.IsNull())
    GBs2d->IncreaseDegree(Deg);
  else
    return 1;

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : removepole
//purpose  : 
//=======================================================================

static Standard_Integer removepole (Draw_Interpretor& di, Standard_Integer n, char** a)
{
  if (n < 3) return 1;

  Standard_Integer Index = atoi(a[2]);

  Handle(Geom_BezierCurve)   GBZ   = DrawTrSurf::GetBezierCurve(a[1]);
  Handle(Geom2d_BezierCurve) GBZ2d = DrawTrSurf::GetBezierCurve2d(a[1]);
  if (!GBZ.IsNull()) {
    GBZ->RemovePole(Index);
  }
  else if (!GBZ2d.IsNull()) {
    GBZ2d->RemovePole(Index);
  }
  else {
    di << "rempole needs a bezier curve";
    return 1;
  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : insertpole
//purpose  : 
//=======================================================================

static Standard_Integer insertpole (Draw_Interpretor& di, Standard_Integer n, char** a)
{
  if (n < 6) return 1;

  Standard_Integer Index = atoi(a[2]);

  Handle(Geom_BezierCurve)   GBZ   = DrawTrSurf::GetBezierCurve(a[1]);
  Handle(Geom2d_BezierCurve) GBZ2d = DrawTrSurf::GetBezierCurve2d(a[1]);
  if (!GBZ.IsNull()) {
    gp_Pnt P (atof(a[3]),atof(a[4]),atof(a[5]));
    if ( n == 7)
      GBZ->InsertPoleAfter(Index,P,atof(a[6]));
    else
      GBZ->InsertPoleAfter(Index,P);
  }
  else if (!GBZ2d.IsNull()) {
    gp_Pnt2d P (atof(a[3]),atof(a[4]));
    if ( n == 6)
      GBZ2d->InsertPoleAfter(Index,P,atof(a[5]));
    else
      GBZ2d->InsertPoleAfter(Index,P);
  }
  else {
    di << "insertpole needs a bezier curve";
    return 1;
  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : cfindp
//purpose  : 
//=======================================================================

static Standard_Integer cfindp (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 6) return 1;

  Standard_Integer Index = 0;
  Standard_Integer view = atoi(a[2]);
  Standard_Real x = atof(a[3]);
  Standard_Real y = atof(a[4]);

  Draw_Display d = dout.MakeDisplay(view);

  Handle(Draw_Drawable3D) D = Draw::Get(a[1]);

  Handle(DrawTrSurf_BezierCurve) DBz = 
    Handle(DrawTrSurf_BezierCurve)::DownCast(D);
  if( !DBz.IsNull())
    DBz->FindPole( x, y, d, 5, Index);
  else {
    Handle(DrawTrSurf_BSplineCurve) DBs = 
      Handle(DrawTrSurf_BSplineCurve)::DownCast(D);
    if (!DBs.IsNull())
      DBs->FindPole( x, y, d, 5, Index);
    else {
      Handle(DrawTrSurf_BezierCurve2d) DBz = 
	Handle(DrawTrSurf_BezierCurve2d)::DownCast(D);
      if( !DBz.IsNull())
	DBz->FindPole( x, y, d, 5, Index);
      else {
	Handle(DrawTrSurf_BSplineCurve2d) DBs = 
	  Handle(DrawTrSurf_BSplineCurve2d)::DownCast(D);
	if (!DBs.IsNull())
	  DBs->FindPole( x, y, d, 5, Index);
	else 
	  return 1;
      }
    }
  }
  
  Draw::Set(a[5],Index);
  
  return 0;
}


//=======================================================================
//function : csetperiodic
//purpose  : 
//=======================================================================

static Standard_Integer csetperiodic (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 2) return 1;

  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);
  
  if (GBs.IsNull() && GBs2d.IsNull()) return 1;
  
  if (!strcmp(a[0],"setperiodic")) {
    if (!GBs.IsNull()) 
      GBs->SetPeriodic();
    else
      GBs2d->SetPeriodic();
  }
  else if (!strcmp(a[0],"setnotperiodic")) {
    if (!GBs.IsNull()) 
      GBs->SetNotPeriodic();
    else
      GBs2d->SetNotPeriodic();
  }

  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : value
//purpose  : 
//=======================================================================

static Standard_Integer value (Draw_Interpretor& ,
			       Standard_Integer n, char** a)
{
  if (n < 4) return 1;

  Handle(Geom_Curve) GC = DrawTrSurf::GetCurve(a[1]);
  if (GC.IsNull()) return 1;

  Standard_Real U = atof(a[2]);

  Standard_Boolean DrawPoint = ( n%3 == 1);
  if ( DrawPoint) n--;

  gp_Pnt P;
  if (n > 6) {
    if (n < 9) return 1;
    gp_Vec D1;
    if (n > 9) {
      if (n < 12) return 1;
      gp_Vec D2;
      GC->D2(U,P,D1,D2);
      Draw::Set(a[9] ,D2.X());
      Draw::Set(a[10],D2.Y());
      Draw::Set(a[11],D2.Z());
    }
    else 
      GC->D1(U,P,D1);
    Draw::Set(a[6],D1.X());
    Draw::Set(a[7],D1.Y());
    Draw::Set(a[8],D1.Z());
  }
  else 
    GC->D0(U,P);

  if ( n > 3) {
    Draw::Set(a[3],P.X());
    Draw::Set(a[4],P.Y());
    Draw::Set(a[5],P.Z());
  }
  if ( DrawPoint) {
    DrawTrSurf::Set(a[n],P);
  }
  
  return 0;
}


//=======================================================================
//function : value2d
//purpose  : 
//=======================================================================

static Standard_Integer value2d (Draw_Interpretor& , 
				 Standard_Integer n, char** a)
{
  if (n < 4) return 1;

  Handle(Geom2d_Curve) GC = DrawTrSurf::GetCurve2d(a[1]);
  if (GC.IsNull()) return 1;

  Standard_Real U = atof(a[2]);

  Standard_Boolean DrawPoint = ( n%2 == 0);
  if ( DrawPoint ) n--;

  gp_Pnt2d P;
  if (n > 5) {
    if (n < 7) return 1;
    gp_Vec2d D1;
    if (n > 7) {
      if (n < 9) return 1;
      gp_Vec2d D2;
      GC->D2(U,P,D1,D2);
      Draw::Set(a[7] ,D2.X());
      Draw::Set(a[8],D2.Y());
    }
    else 
      GC->D1(U,P,D1);
    Draw::Set(a[5],D1.X());
    Draw::Set(a[6],D1.Y());
  }
  else 
    GC->D0(U,P);

  if ( n > 3 ) {
    Draw::Set(a[3],P.X());
    Draw::Set(a[4],P.Y());
  }
  if ( DrawPoint ) {
    DrawTrSurf::Set(a[n], P);
  }
  
  return 0;
}

//=======================================================================
//function : segment
//purpose  : 
//=======================================================================

static Standard_Integer segment (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 4) return 1;

  Handle(Geom_BezierCurve) GBz = DrawTrSurf::GetBezierCurve(a[1]);
  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BezierCurve) GBz2d = DrawTrSurf::GetBezierCurve2d(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  Standard_Real f = atof(a[2]), l = atof(a[3]);

  if (!GBz.IsNull()) 
    GBz->Segment(f,l);
  else if (!GBs.IsNull())
    GBs->Segment(f,l);
  else if (!GBz2d.IsNull()) 
    GBz2d->Segment(f,l);
  else if (!GBs2d.IsNull())
    GBs2d->Segment(f,l);
  else
    return 1;

  Draw::Repaint();
  return 0;
}


//=======================================================================
//function : setorigin
//purpose  : 
//=======================================================================

static Standard_Integer setorigin (Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 3) return 1;

  Handle(Geom_BSplineCurve) GBs = DrawTrSurf::GetBSplineCurve(a[1]);
  Handle(Geom2d_BSplineCurve) GBs2d = DrawTrSurf::GetBSplineCurve2d(a[1]);

  if (!GBs.IsNull())
    GBs->SetOrigin(atoi(a[2])); 
  if (!GBs2d.IsNull())
    GBs2d->SetOrigin(atoi(a[2])); 
  else
    return 1;

  Draw::Repaint();
  return 0;
}


//=======================================================================
//function : point
//purpose  : 
//=======================================================================

static Standard_Integer point(Draw_Interpretor& , Standard_Integer n, char** a)
{
  if (n < 4) return 1;
  if (n >= 5) {
    gp_Pnt P(atof(a[2]),atof(a[3]),atof(a[4]));
    DrawTrSurf::Set(a[1],P);
  }
  else {
    gp_Pnt2d P(atof(a[2]),atof(a[3]));
    DrawTrSurf::Set(a[1],P);
  }

  return 0;
}

//=======================================================================
//function : coord
//purpose  : 
//=======================================================================

static Standard_Integer coord(Draw_Interpretor&,
			      Standard_Integer n, char** a) 
{
  if ( n == 4) {
    gp_Pnt2d P;
    if ( !DrawTrSurf::GetPoint2d(a[1],P)) return 1;
    Draw::Set(a[2],P.X());
    Draw::Set(a[3],P.Y());
  }
  else if ( n == 5) {
    gp_Pnt  P;
    if ( !DrawTrSurf::GetPoint(a[1],P)) return 1;
    Draw::Set(a[2],P.X());
    Draw::Set(a[3],P.Y());
    Draw::Set(a[4],P.Z());
  }
  else 
    return 1;

  return 0;
}

//=======================================================================
//function : 
//purpose  : 
//=======================================================================
static Standard_Integer minmaxcurandinf(Draw_Interpretor& di, 
				   Standard_Integer argc, char** argv)
{
  if (argc < 2) return 1;

  Handle(Geom2d_Curve)  C1 = DrawTrSurf::GetCurve2d(argv[1]);
  if (C1.IsNull()) return 1;

  Draw_Color              Couleur;
  Geom2dLProp_CurAndInf2d Sommets;  

  Sommets.PerformCurExt (C1);
  if (Sommets.IsDone() && !Sommets.IsEmpty()) {
    for (Standard_Integer i = 1; i <= Sommets.NbPoints(); i++){      
      Couleur = Draw_vert;
      if (Sommets.Type(i) == LProp_MinCur) {
	Couleur = Draw_orange;
	di << "  Maximum of curvature at U ="<<Sommets.Parameter(i)<<"\n";
      }
      else {
	di << "  Minimum of curvature at U ="<<Sommets.Parameter(i)<<"\n";
      }
      gp_Pnt2d P = C1->Value(Sommets.Parameter(i));
      Handle(Draw_Marker2D) dr = new Draw_Marker2D(P,Draw_Plus,Couleur); 
      dout << dr;
    }
    dout.Flush();
  }
   
  Geom2dLProp_CurAndInf2d Sommets2;
  Sommets2.PerformInf (C1);
  
  if (Sommets2.IsDone() && !Sommets2.IsEmpty()) {
    for (Standard_Integer i = 1; i <= Sommets2.NbPoints(); i++){
      gp_Pnt2d P = C1->Value(Sommets2.Parameter(i));
      Handle(Draw_Marker2D) dr = new Draw_Marker2D(P,Draw_Plus,Draw_bleu); 
      dout << dr;
      di << "  Inflexion at U ="<<Sommets2.Parameter(i)<<"\n";
    }
    dout.Flush();
  }
  return 0;
}
//=======================================================================
//function :  shcurvature
//purpose  :  affiche le peigne de courbure
//=======================================================================
static Standard_Integer shcurvature(Draw_Interpretor&, 
				   Standard_Integer argc, char** argv)
{
  if (argc < 2) return 1;

   Handle(DrawTrSurf_Curve2d) C2d =  Handle(DrawTrSurf_Curve2d)
                                  ::DownCast(Draw::Get(argv[1]));
   Handle(DrawTrSurf_Curve) C3d =  Handle(DrawTrSurf_Curve)
                                  ::DownCast(Draw::Get(argv[1]));
   
  if (C2d.IsNull()) {
    if (C3d.IsNull()) return 1;
    C3d->ShowCurvature();
  }
  else {
    C2d->ShowCurvature();
  }
  Draw::Repaint();
  return 0;
}

//=======================================================================
//function :  clcurvature
//purpose  :  efface le peigne de courbure
//=======================================================================
static Standard_Integer clcurvature(Draw_Interpretor&, 
				   Standard_Integer argc, char** argv)
{
  if (argc < 2) return 1; 
   Handle(DrawTrSurf_Curve2d) C2d =  Handle(DrawTrSurf_Curve2d)
                                  ::DownCast(Draw::Get(argv[1]));
   Handle(DrawTrSurf_Curve) C3d =  Handle(DrawTrSurf_Curve)
                                  ::DownCast(Draw::Get(argv[1]));

  if (C2d.IsNull()) {
    if (C3d.IsNull()) return 1;
    C3d->ClearCurvature();
  }
  else {
    C2d->ClearCurvature();
  }
  Draw::Repaint();
  return 0;
}

//=======================================================================
//function :  radiusmax
//purpose  :  definit le rayon de courbure maximum a afficher
//=======================================================================
static Standard_Integer radiusmax(Draw_Interpretor&, 
				  Standard_Integer argc, char** argv)
{
  if (argc < 3) return 1; 
  Standard_Real Radius = atof(argv[2]);
   Handle(DrawTrSurf_Curve2d) C2d =  Handle(DrawTrSurf_Curve2d)
                                  ::DownCast(Draw::Get(argv[1]));
   Handle(DrawTrSurf_Curve) C3d =  Handle(DrawTrSurf_Curve)
                                  ::DownCast(Draw::Get(argv[1]));

  if (C2d.IsNull()) {
    if (C3d.IsNull()) return 1;
    C3d->SetRadiusMax(Radius);
  }
  else {
    C2d->SetRadiusMax(Radius);
  }
  Draw::Repaint();
  return 0;
}

//=======================================================================
//function :  radiusratio
//purpose  :  definit le ratio du rayon de courbure a afficher
//=======================================================================
static Standard_Integer radiusratio(Draw_Interpretor&, 
				  Standard_Integer argc, char** argv)
{
  if (argc < 3) return 1;
  Standard_Real Ratio = atof(argv[2]);
  Handle(DrawTrSurf_Curve2d) C2d =  Handle(DrawTrSurf_Curve2d)
                                  ::DownCast(Draw::Get(argv[1]));
  Handle(DrawTrSurf_Curve) C3d =  Handle(DrawTrSurf_Curve)
                                  ::DownCast(Draw::Get(argv[1]));

  if (C2d.IsNull()) { 
    if (C3d.IsNull()) return 1;
    C3d->SetRadiusRatio(Ratio);
  }
  else {
    C2d->SetRadiusRatio(Ratio);
  }
  Draw::Repaint();
  return 0;
}

//=======================================================================
//function : 
//purpose  : 
//=======================================================================
static Standard_Integer localprop(Draw_Interpretor& di, 
				  Standard_Integer argc, char** argv)
{
  if (argc < 3) return 1;

  Standard_Real U =  atof(argv[2]);

  Handle(Geom2d_Curve)  C2d = DrawTrSurf::GetCurve2d(argv[1]);
  Handle(Geom_Curve)    C3d;


  if (C2d.IsNull()) {
    C3d = DrawTrSurf::GetCurve(argv[1]);
    if (C3d.IsNull()) return 1;
    GeomLProp_CLProps Prop (C3d,2,Precision::Confusion());
    Prop.SetParameter(U);
    Handle(Draw_Marker3D)drp = new Draw_Marker3D(Prop.Value(),
						 Draw_Plus,
						 Draw_vert );
    dout << drp;
    if (Prop.IsTangentDefined()) {
      Standard_Real K = Prop.Curvature();
      di <<" Curvature : "<<K<<"\n";

      if (Abs(K) > Precision::Confusion()) {
	Standard_Real R = 1/Abs(K);
	gp_Pnt        Center;
	Prop.CentreOfCurvature(Center);
	gp_Dir Tang;
	gp_Dir Nor;
	Prop.Tangent(Tang);
	Prop.Normal(Nor);
	gp_Dir AxC = Nor^Tang;
	gp_Ax2 Axe(Center,AxC,Nor);
	Handle(Geom_Circle) Cir3d = new Geom_Circle(Axe,R);
	Handle(DrawTrSurf_Curve) dr;
	dr = new DrawTrSurf_Curve(Cir3d);
	dout << dr;
	dout.Flush();
      }
    }
    else 
      di <<"Tangent undefined."<<"\n";  
  }
  else {
    Geom2dLProp_CLProps2d Prop (C2d,2,Precision::Confusion());
    Prop.SetParameter(U);
    Handle(Draw_Marker2D) drp = new Draw_Marker2D(Prop.Value(),
						  Draw_Plus,
						  Draw_vert);
    dout << drp;
    if (Prop.IsTangentDefined()) {
      Standard_Real K = Prop.Curvature();
      gp_Pnt2d      Center;

      di <<" Curvature : "<<K<<"\n";

      if (Abs(K) > Precision::Confusion()) {
	Standard_Real R = 1/Abs(K);
	Prop.CentreOfCurvature(Center);
	gp_Ax2d Axe(Center,gp::DX2d());
	Handle(Geom2d_Circle) Cir2d = new Geom2d_Circle(Axe,R);
	Handle(DrawTrSurf_Curve2d) dr;
	dr = new DrawTrSurf_Curve2d(Cir2d,Draw_rouge,30,Standard_False);
	dout << dr;
	dout.Flush();
      }
    }
    else 
      di <<"Tangent undefined."<<"\n";
  }
  return 0;
}  
//=======================================================================
//function : rawcont
//purpose  : 
//=======================================================================

static Standard_Integer rawcont(Draw_Interpretor& di, Standard_Integer n, char** a)
{
  if (n < 5) return 1;

  Handle(Geom_Curve) GC1;
  GC1 = DrawTrSurf::GetCurve(a[1]);
  Handle(Geom_Curve) GC2;
  GC2 = DrawTrSurf::GetCurve(a[2]);
  Standard_Real param1 =
    atof(a[3]) ;
  Standard_Real param2 =
    atof(a[4]) ;
  if (GC1.IsNull() || GC2.IsNull())
    return 1;
  gp_Pnt a_point1,
    a_point2 ;
  GC1->D0(param1,
	  a_point1) ;
  GC2->D0(param2,
	  a_point2) ;
  if (a_point2.SquareDistance(a_point1) < Precision::Confusion()) {
    GeomAbs_Shape cont =
      GeomLProp::Continuity(GC1,
			    GC2,
			    param1,
			    param2,
			    Standard_True,
			    Standard_True,
			    Precision::Confusion(),
			    Precision::Angular()) ;
    switch (cont) {
    case GeomAbs_C0: 
      di << " C0 Continuity " << "\n" ;
      break ;
    case GeomAbs_G1:
      di << " G1 Continuity " << "\n" ;
      break ;
    case GeomAbs_C1 :
      di << " C1 Continuity " << "\n" ;
      break ;
    case GeomAbs_C2 :
      di << " C2 Continuity " << "\n" ;
      break ; 
#ifndef DEB
    default:
      break ; 
#endif
    }
  }
  else {
    di << " not C0 continuity " << "\n" ;
  }
  return 0 ;
}
//=======================================================================
//function : approxcurveonsurf
//purpose  : 
//=======================================================================
static Standard_Integer approxcurveonsurf(Draw_Interpretor& di, Standard_Integer n, char** a)
{
  Standard_Real Tol = 1.e-7;              // Tolerance (default 0.1mm) 
  GeomAbs_Shape Continuity = GeomAbs_C1;  // Continuity order : 0, 1 or 2 (default 1)
  Standard_Integer MaxDeg = 14;           // Maximum degree
  Standard_Integer MaxSeg = 16; /*1*/          // Maximum number of segments

  if ( n>8 || n<4) return 1;

  if (n>4) Tol = Max(atof(a[4]),1.e-10);

  if (n>5) {
    if (atoi(a[5]) == 0) Continuity = GeomAbs_C0;
    if (atoi(a[5]) == 2) Continuity = GeomAbs_C2;
  }

  if (n>6) {
    MaxDeg = atoi(a[6]);
    if (MaxDeg<1 || MaxDeg>14) MaxDeg = 14;
  }

  if (n>7) MaxSeg = atoi(a[7]);
  Handle(Geom2d_Curve) curve2d = DrawTrSurf::GetCurve2d(a[2]);
  Handle(Geom_Surface) Surf = DrawTrSurf::GetSurface(a[3]);

  Handle(Geom2dAdaptor_HCurve) A2d = new (Geom2dAdaptor_HCurve)(curve2d);
  Handle(GeomAdaptor_HSurface) AS = new (GeomAdaptor_HSurface)(Surf);

  Approx_CurveOnSurface App(A2d, AS, A2d->FirstParameter(), A2d->LastParameter(),
			    Tol,  Continuity,  MaxDeg, MaxSeg,
			    Standard_True, Standard_False);

  if(App.HasResult()) {
    Handle(Geom_BSplineCurve) BSCurve = App.Curve3d(); 
    DrawTrSurf::Set(a[1], BSCurve);
    return 0;
  }

  di << "Approximation failed !" << "\n";
  return 1;
			    
}

//=======================================================================
//function : approxcurve
//purpose  : 
//=======================================================================
static Standard_Integer approxcurve(Draw_Interpretor& di, Standard_Integer n, char** a)
{ 
  Standard_Real Tol = 1.e-7;              // Tolerance (default 0.1mm) 
  GeomAbs_Shape Continuity = GeomAbs_C1;  // Continuity order : 0, 1 or 2 (default 1)
  Standard_Integer MaxDeg = 14;           // Maximum degree
  Standard_Integer MaxSeg = 16;           // Maximum number of segments
  
  Standard_Integer Case, shift;
// Case == 1 : 3d approximation without reparametrization
// Case == 2 : 2d approximation without reparametrization
// Case == 3 : 3d approximation with reparametrization
// Case == 4 : curve_on_surface approximation with reparametrization
// Case == 5 : 2 curves_on_surfaces approximation with reparametrization

  Handle(Geom_Curve) curve;
  Handle(Geom2d_Curve) curve2d, curve2d2;
  Handle(Geom_Surface) surface, surface2;

  if(n < 2) return 1;

  if (!strcmp(a[1],"-L")) {
// aproximation with curvilinear abscissa reparametrization
    if (n > 11 || n < 4) return 1;
    Tol = 1.e-4;
    curve = DrawTrSurf::GetCurve(a[3]);
    if (!curve.IsNull()) {
      shift = 4;
      Case = 3;
    }
    else {
// approx curve_on_surface
      if (n < 5) return 1;
      curve2d = DrawTrSurf::GetCurve2d(a[3]); 
      surface = DrawTrSurf::GetSurface(a[4]);
      if (curve2d.IsNull() || surface.IsNull()) {
	return 1;
      }
      if (n >= 7) {
	curve2d2 = DrawTrSurf::GetCurve2d(a[5]); 
	surface2 = DrawTrSurf::GetSurface(a[6]);
	if (curve2d2.IsNull() || surface2.IsNull()) {
	  shift = 5;
	  Case = 4;
	}
	else {
// approx 2 curves_on_surfaces
	  shift = 7;
	  Case = 5;
	}
      }
      else {
	shift = 5;
	Case = 4;
      }
    }
  }
  else {
// aproximation without reparamitrization
    if ( n>7 || n<3) return 1;
    shift = 3;
    curve = DrawTrSurf::GetCurve(a[2]);
    if (curve.IsNull()) {
      curve2d = DrawTrSurf::GetCurve2d(a[2]); 
      if (curve2d.IsNull()) {
	return 1;
      }
      Case = 2;
    }
    else
      Case = 1;
  }
  
  if (n>shift) Tol = Max(atof(a[shift]),1.e-10);
  
  if (n>shift+1) {
    if (atoi(a[shift+1]) == 0) Continuity = GeomAbs_C0;
    if (atoi(a[shift+1]) == 2) Continuity = GeomAbs_C2;
  }
  
  if (n>shift+2) {
      MaxDeg = atoi(a[shift+2]);
      if (MaxDeg<1 || MaxDeg>14) MaxDeg = 14;
    }
  
  if (n>shift+3) MaxSeg = atoi(a[shift+3]);
    
  if (Case == 1) {
    GeomConvert_ApproxCurve appr(curve, Tol, Continuity, MaxSeg, MaxDeg);
    if(appr.HasResult()) {
      //appr.Dump(cout);
      Standard_SStream aSStream;
      appr.Dump(aSStream);
      aSStream << ends;
      di << GetSString(aSStream);
      Handle(Geom_BSplineCurve) BSCurve = appr.Curve(); 
      DrawTrSurf::Set(a[1], BSCurve);
    }
 }   

  else if (Case == 2) {
    Geom2dConvert_ApproxCurve appr(curve2d, Tol, Continuity, MaxSeg, MaxDeg);
    if(appr.HasResult()) {
      //appr.Dump(cout);
      Standard_SStream aSStream;
      appr.Dump(aSStream);
      aSStream << ends;
      di << GetSString(aSStream);
      Handle(Geom2d_BSplineCurve) BSCurve = appr.Curve(); 
      DrawTrSurf::Set(a[1], BSCurve);
    }
  }    

  else if (Case == 3) {
    Handle(Adaptor3d_HCurve) HACur = new GeomAdaptor_HCurve(curve);
    Approx_CurvilinearParameter appr(HACur, Tol, Continuity, MaxDeg, MaxSeg);
    if(appr.HasResult()) {
      //appr.Dump(cout);
      Standard_SStream aSStream;
      appr.Dump(aSStream);
      aSStream << ends;
      di << GetSString(aSStream);
      Handle(Geom_BSplineCurve) BSCurve = appr.Curve3d(); 
      DrawTrSurf::Set(a[2], BSCurve);
    }
}    
  else if (Case == 4) {
    Handle(Adaptor2d_HCurve2d) HACur2d = new Geom2dAdaptor_HCurve(curve2d);
    Handle(Adaptor3d_HSurface) HASur = new GeomAdaptor_HSurface(surface);
    Approx_CurvilinearParameter appr(HACur2d, HASur, Tol, Continuity, MaxDeg, MaxSeg);
    if(appr.HasResult()) {
      //appr.Dump(cout);
      Standard_SStream aSStream;
      appr.Dump(aSStream);
      aSStream << ends;
      di << GetSString(aSStream);
      Handle(Geom_BSplineCurve) BSCurve = appr.Curve3d(); 
      DrawTrSurf::Set(a[2], BSCurve);
    }
  }

  else if (Case == 5) {
    Handle(Adaptor2d_HCurve2d) HACur2d = new Geom2dAdaptor_HCurve(curve2d);
    Handle(Adaptor3d_HSurface) HASur = new GeomAdaptor_HSurface(surface);
    Handle(Adaptor2d_HCurve2d) HACur2d2 = new Geom2dAdaptor_HCurve(curve2d2);
    Handle(Adaptor3d_HSurface) HASur2 = new GeomAdaptor_HSurface(surface2);
    Approx_CurvilinearParameter appr(HACur2d, HASur, HACur2d2, HASur2, Tol, Continuity, MaxDeg, MaxSeg);
    if(appr.HasResult()) {
      //appr.Dump(cout);
      Standard_SStream aSStream;
      appr.Dump(aSStream);
      aSStream << ends;
      di << GetSString(aSStream);
      Handle(Geom_BSplineCurve) BSCurve = appr.Curve3d(); 
      DrawTrSurf::Set(a[2], BSCurve);
    }
  }
  

  return 0;
}

//=======================================================================
//function : newbspline
//purpose  : reduce the multiplicity of the knots to their minimum 
//           compared to the degree of the curve
//=======================================================================

static Standard_Integer splitc1(Draw_Interpretor& di,
				   Standard_Integer n, char** c)

{Standard_Real      tolerance=1.0e-5,
   angular_tolerance = 1.0e-4 ;
 Standard_Integer   optiontab,i;
 char name[100];

 if (n<3) return 1;
 optiontab=atoi(c[2]);
 if (n >= 4 )
   tolerance=atof(c[3]);
 if (n >= 5) {
   angular_tolerance = atof(c[4]) ;
 }
 Handle(Geom_Curve) ACurve = Handle(Geom_Curve)::DownCast(DrawTrSurf::Get(c[1])) ;
 
 Standard_Real f = ACurve->FirstParameter();
 Standard_Real l = ACurve->LastParameter();

 if ( Precision::IsInfinite(f) || Precision::IsInfinite(l)) {
   di << " Error: Infinite curves" << "\n";
   return 1;
 }

 Handle(Geom_BSplineCurve) BS = GeomConvert::CurveToBSplineCurve(ACurve);
 
 if ( BS.IsNull()) return 1;

 if (optiontab){
   Handle(TColGeom_HArray1OfBSplineCurve)  tabBS;
   GeomConvert::C0BSplineToArrayOfC1BSplineCurve(BS,
						 tabBS,
						 angular_tolerance,
						 tolerance);
   for (i=0;i<=(tabBS->Length()-1);i++){
     sprintf(name,"%s_%d",c[1],i+1);
     Standard_CString new_name = name ;
     DrawTrSurf::Set(new_name,
                     tabBS->Value(i));
     di.AppendElement(name);
   }
 }
 else{
   GeomConvert::C0BSplineToC1BSplineCurve(BS,
					  tolerance,
					  angular_tolerance) ;

   DrawTrSurf::Set(c[1],BS);
 }
 return 0;
}

//=======================================================================
//function : splitc12d
//purpose  : reduce the multiplicity of the knots to their minimum 
//           compared to the degree of the curve
//=======================================================================

static Standard_Integer splitc12d(Draw_Interpretor& di,
				     Standard_Integer n, char** c)

{Standard_Real      tolerance=1.0e-5,
   angular_tolerance = 1.0e-4 ;
 Standard_Integer   optiontab,i;
 char name[100];

 if (n<3) return 1;
 optiontab=atoi(c[2]);
 if (n==4)
   tolerance=atof(c[3]);
 if (n==5) 
   angular_tolerance = atof(c[4]) ;
 Handle(Geom2d_Curve) ACurve = Handle(Geom2d_Curve)::DownCast(DrawTrSurf::GetCurve2d(c[1])) ;
 
 Standard_Real f = ACurve->FirstParameter();
 Standard_Real l = ACurve->LastParameter();

 if ( Precision::IsInfinite(f) || Precision::IsInfinite(l)) {
   di << " Error: Infinite curves" << "\n";
   return 1;
 }

 Handle(Geom2d_BSplineCurve) BS = Geom2dConvert::CurveToBSplineCurve(ACurve);
 
 if ( BS.IsNull()) return 1;

 if (optiontab){
   Handle(TColGeom2d_HArray1OfBSplineCurve)  tabBS;
   Geom2dConvert::C0BSplineToArrayOfC1BSplineCurve(BS,
						   tabBS,
						   angular_tolerance,
						   tolerance);
   for (i=0;i<=(tabBS->Length()-1);i++){
     sprintf(name,"%s_%d",c[1],i+1);
     Standard_CString new_name = name ;
     DrawTrSurf::Set(new_name,
		     tabBS->Value(i));
     di.AppendElement(name);
   }
 }
 else{
   Geom2dConvert::C0BSplineToC1BSplineCurve(BS,tolerance);
   DrawTrSurf::Set(c[1],BS);
 }
 return 0;
}

//=======================================================================
//function : canceldenom
//purpose  : set the value of the denominator cancel its first 
//           derivative on the boundaries of the surface if possible
//=======================================================================

static Standard_Integer canceldenom(Draw_Interpretor& ,
				     Standard_Integer n, char** c)

{Standard_Integer    uoption,voption;
 Standard_Boolean    udirection=Standard_False;
 Standard_Boolean    vdirection=Standard_False;
 if (n<4) return 1;
 uoption=atoi(c[2]);
 voption=atoi(c[3]);
 if (uoption)
   udirection=Standard_True;
 if (voption)
   vdirection=Standard_True;
 Handle(Geom_BSplineSurface) BSurf = Handle(Geom_BSplineSurface)::DownCast(DrawTrSurf::GetBSplineSurface(c[1]));
 GeomLib::CancelDenominatorDerivative(BSurf,udirection,vdirection);
 DrawTrSurf::Set(c[1],BSurf);
 return 0;
}

//=======================================================================
//function : length
//purpose  : eval curve's length
//=======================================================================

static Standard_Integer length(Draw_Interpretor& di,
			       Standard_Integer n, char** a)
{
  if (n<2) return 1;
  Handle(Geom_Curve) GC = DrawTrSurf::GetCurve(a[1]);
  Handle(Geom2d_Curve) GC2d = DrawTrSurf::GetCurve2d(a[1]);
  Standard_Real Tol = Precision::Confusion(), L;
  if (n==3) Tol = atof(a[2]);

  if (!GC.IsNull()) {
    GeomAdaptor_Curve AC(GC);
    L = GCPnts_AbscissaPoint::Length(AC, Tol);
  }  
  else if (!GC2d.IsNull()) {
    Geom2dAdaptor_Curve AC(GC2d);
    L = GCPnts_AbscissaPoint::Length(AC, Tol);
  }
  else {
    di << a[1] << "is not a curve" << "\n";
    return 1;
  }

  di << "The length " << a[1] << " is " << L << "\n";
  return 0;
}



//=======================================================================
//function : CurveCommands
//purpose  : 
//=======================================================================

void  GeomliteTest::CurveCommands(Draw_Interpretor& theCommands)
{
  
  static Standard_Boolean loaded = Standard_False;
  if (loaded) return;
  loaded = Standard_True;
  
  DrawTrSurf::BasicCommands(theCommands);
  
  char* g;
  
  
  // analytic curves
  g = "GEOMETRY curves creation";


  theCommands.Add("point",
		  "point name x y [z]",
		  __FILE__,
		  point ,g);
  
  theCommands.Add("line",
		  "line name pos dir",
		  __FILE__,
		  anacurve,g);
  
  theCommands.Add("circle",
		  "circle name x y [z [dx dy dz]] [ux uy [uz]] radius",
		  __FILE__,
		  anacurve,g);
  
  theCommands.Add("ellipse",
		  "ellipse name x y [z [dx dy dz]] [ux uy [uz]] major minor",
		  __FILE__,
		  anacurve,g);
  theCommands.Add("parabola",
		  "parabola name x y [z [dx dy dz]] [ux uy [uz]] focal",
		  __FILE__,
		  anacurve,g);
  theCommands.Add("hyperbola",
		  "hyperbola name x y [z [dx dy dz]] [ux uy [uz]] major minor",
		  __FILE__,
		  anacurve,g);

  theCommands.Add("beziercurve",
		  "beziercurve name nbpole pole, [weight]",
		  __FILE__,
		  polecurve,g);

  theCommands.Add("bsplinecurve",
		  "bsplinecurve name degree nbknots  knot, umult  pole, weight",
		  __FILE__,
		  polecurve,g);

  theCommands.Add("pbsplinecurve",
		  "pbsplinecurve name degree nbknots  knot, umult  pole, weight (periodic)",
		  __FILE__,
		  polecurve,g);

  theCommands.Add("2dbeziercurve",
		  "2dbeziercurve name nbpole pole, [weight]",
		  __FILE__,
		  polecurve2d,g);

  theCommands.Add("2dbsplinecurve",
		  "2dbsplinecurve name degree nbknots  knot, umult  pole, weight",
		  __FILE__,
		  polecurve2d,g);

  theCommands.Add("2dpbsplinecurve",
		  "2dpbsplinecurve name degree nbknots  knot, umult  pole, weight (periodic)",
		  __FILE__,
		  polecurve2d,g);

  g = "GEOMETRY Curves and Surfaces modification";

  theCommands.Add("reverse",
		  "reverse name ... ",
		  __FILE__,
		  reverse,g);

  theCommands.Add("cmovep",
		  "cmovep name index dx dy dz",
		  __FILE__,
		  cmovepole,g);

  theCommands.Add("cmovepoint",
		  "cmovepoint name u dx dy [dz index1 index2]",
		  __FILE__,
		  cmovepoint,g);

  theCommands.Add("cmovetangent",
                  "cmovetangent name u  x y [z] tx ty [tz constraint = 0]",
		  __FILE__,
		  cmovetangent,g) ;

  theCommands.Add("insertknot",
		  "insertknot name knot [mult = 1] [knot mult ...]",
		  __FILE__,
		  cinsertknot,g);

  theCommands.Add("setknot",
		  "setknot name index knot [mult]",
		  __FILE__,
		  csetknot,g);

  theCommands.Add("remknot",
		  "remknot name index [mult] [tol]",
		  __FILE__,
		  cremknot,g);

  theCommands.Add("incdeg",
		  "incdeg name degree",
		  __FILE__,
		  increasedegree,g);

  theCommands.Add("rempole",
		  "rempole name index",
		  __FILE__,
		  removepole,g);

  theCommands.Add("insertpole",
		  "insertpole name index x y [z] [weight]",
		  __FILE__,
		  insertpole,g);

  theCommands.Add("cfindp",
		  "cfindp name view x y index",
		  __FILE__,
		  cfindp,g);

  theCommands.Add("setperiodic",
		  "setperiodic name ...",
		  __FILE__,
		  csetperiodic,g);

  theCommands.Add("setnotperiodic",
		  "setnotperiodic name",
		  __FILE__,
		  csetperiodic,g);

  theCommands.Add("segment",
		  "segment name Ufirst Ulast",
		   __FILE__,
		  segment , g);

  theCommands.Add("setorigin",
		  "setorigin name knotindex",
		   __FILE__,
		  setorigin , g);

  g = "GEOMETRY curves and surfaces analysis";

  theCommands.Add("cvalue",
		  "cvalue curvename U  X Y Z [D1X D1Y D1Z D2X D2Y D2Z]",
		  __FILE__,
		  value,g);

  theCommands.Add("2dcvalue",
		  "2dcvalue curvename U  X Y [D1X D1Y D2X D2Y]",
		  __FILE__,
		  value2d,g);

  theCommands.Add("coord",
		  "coord P x y [z]: set in x y [z] the coordinates of P",
		  __FILE__,
		  coord,g);

  theCommands.Add("minmaxcurandinf",
		  "minmaxcurandinf curve",
		  __FILE__,
		  minmaxcurandinf,g);
  
  theCommands.Add("shcurvature",
		  "shcurvature curvename",
		  __FILE__,
		  shcurvature,g);

  theCommands.Add("clcurvature",
		  "clcurvature curvename",
		  __FILE__,
		  clcurvature,g);
  

 theCommands.Add("radiusmax",
		  "radiusmax curvename  radius",
		  __FILE__,
		  radiusmax,g);

 theCommands.Add("radiusratio",
		  "radiusratio curvename ratio",
		  __FILE__,
		  radiusratio,g); 
  theCommands.Add("localprop",
		  "localprop curvename U",
		  __FILE__,
		  localprop,g);
  theCommands.Add("rawcont",
		  "rawcont curve1 curve2 u1 u2",
		  __FILE__,
		  rawcont,g) ;
  theCommands.Add("approxcurve",
                  "approxcurve [-L] name curve1 [Surf1] [curve2d2 Surf2] [Tol [cont [maxdeg [maxseg]]]] ",
		  __FILE__,
		  approxcurve,g);

  theCommands.Add("approxcurveonsurf",
                  "approxcurveonsurf name curve2d surface [Tol [cont [maxdeg [maxseg]]]] ",
		  __FILE__,
		  approxcurveonsurf,g);

 theCommands.Add("length", "length curve [Tol]", 
		  __FILE__,
		  length, g);


  theCommands.Add("splitc1",
		  "splitc1 bspline resultinarray(0/1) [tol] [angtol] ",
		  __FILE__,
		  splitc1,g);

  theCommands.Add("splitc12d",
		  "splitc12d bspline2d resultinarray(0/1) [tol] [angtol] ",
		  __FILE__,
		  splitc12d,g);
  theCommands.Add("canceldenom",
		  "canceldenom BSpline-Surface UDirection(0/1) VDirection(0/1)",
		  __FILE__,
		  canceldenom,g);

 

}
