// File:	GeomAPI_PointsToBSpline.cxx
// Created:	Mon Mar 21 13:41:29 1994
// Author:	Bruno DUMORTIER
//		<dub@fuegox>

#include <GeomAPI_PointsToBSpline.ixx>

#include <AppDef_BSplineCompute.hxx>
#include <AppDef_MultiLine.hxx>
#include <AppParCurves_MultiBSpCurve.hxx>
#include <math_Vector.hxx>
#include <BSplCLib.hxx>


//=======================================================================
//function : GeomAPI_PointsToBSpline
//purpose  : 
//=======================================================================

 GeomAPI_PointsToBSpline::GeomAPI_PointsToBSpline()
{
  myIsDone = Standard_False;
}


//=======================================================================
//function : GeomAPI_PointsToBSpline
//purpose  : 
//=======================================================================

GeomAPI_PointsToBSpline::GeomAPI_PointsToBSpline
  (const TColgp_Array1OfPnt& Points,
   const Standard_Integer    DegMin, 
   const Standard_Integer    DegMax,
   const GeomAbs_Shape       Continuity,
   const Standard_Real       Tol3D)
{
  Init(Points,DegMin,DegMax,Continuity,Tol3D);
}


//=======================================================================
//function : GeomAPI_PointsToBSpline
//purpose  : 
//=======================================================================

GeomAPI_PointsToBSpline::GeomAPI_PointsToBSpline
  (const TColgp_Array1OfPnt&   Points,
   const TColStd_Array1OfReal& Params,
   const Standard_Integer      DegMin, 
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol3D)
{
  Init(Points,Params,DegMin,DegMax,Continuity,Tol3D);
}


//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

void GeomAPI_PointsToBSpline::Init
  (const TColgp_Array1OfPnt& Points,
   const Standard_Integer    DegMin,
   const Standard_Integer    DegMax,
   const GeomAbs_Shape       Continuity,
   const Standard_Real       Tol3D)
{
  Standard_Real Tol2D = 0.; // dummy argument for BSplineCompute.

  AppDef_BSplineCompute TheComputer
    (DegMin,DegMax,Tol3D,Tol2D,0);

  switch( Continuity) {
  case GeomAbs_C0:
    TheComputer.SetContinuity(0); break;

  case GeomAbs_G1: 
  case GeomAbs_C1: 
    TheComputer.SetContinuity(1); break;

  case GeomAbs_G2:
  case GeomAbs_C2:
    TheComputer.SetContinuity(2); break;

  default: 
    TheComputer.SetContinuity(3);
  }
  
  TheComputer.Perform(Points);

  AppParCurves_MultiBSpCurve TheCurve = TheComputer.Value();

#ifdef DEB  
  Standard_Integer Degree = TheCurve.Degree();
#else
  TheCurve.Degree();
#endif
  TColgp_Array1OfPnt Poles(1,TheCurve.NbPoles());

  TheCurve.Curve(1, Poles);
  
  myCurve = new Geom_BSplineCurve(Poles, 
				  TheCurve.Knots(),
				  TheCurve.Multiplicities(),
				  TheCurve.Degree());
  myIsDone = Standard_True;
}


//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

void GeomAPI_PointsToBSpline::Init
  (const TColgp_Array1OfPnt&   Points,
   const TColStd_Array1OfReal& Params,
   const Standard_Integer      DegMin,
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol3D)
{
  if (Params.Length() != Points.Length()) Standard_OutOfRange::Raise("");

  Standard_Real Tol2D = 0.; // dummy argument for BSplineCompute.
  Standard_Integer Nbp = Params.Length();
  math_Vector theParams(1,Nbp);
  theParams(1) = 0.;
  theParams(Nbp) = 1.;

  Standard_Real Uf = Params(Params.Lower());
  Standard_Real Ul = Params(Params.Upper()) - Uf;
  for (Standard_Integer i=2; i<Nbp; i++) {
    theParams(i) = (Params(i)-Uf)/Ul;
  }
  
  AppDef_BSplineCompute TheComputer
    (DegMin,DegMax,Tol3D,Tol2D,0,
     Standard_True,Approx_IsoParametric,Standard_True);

  TheComputer.SetParameters(theParams);

  switch( Continuity) {
  case GeomAbs_C0:
    TheComputer.SetContinuity(0); break;

  case GeomAbs_G1: 
  case GeomAbs_C1: 
    TheComputer.SetContinuity(1); break;

  case GeomAbs_G2:
  case GeomAbs_C2:
    TheComputer.SetContinuity(2); break;

  default: 
    TheComputer.SetContinuity(3);
  }

  TheComputer.Perform(Points);

  AppParCurves_MultiBSpCurve TheCurve = TheComputer.Value();
  
#ifdef DEB
  Standard_Integer Degree = TheCurve.Degree();
#else
  TheCurve.Degree();
#endif
  TColgp_Array1OfPnt Poles(1,TheCurve.NbPoles());
  TColStd_Array1OfReal Knots(TheCurve.Knots().Lower(), 
			     TheCurve.Knots().Upper());

  TheCurve.Curve(1, Poles);
  Knots = TheCurve.Knots();
  BSplCLib::Reparametrize(Params(Params.Lower()),
			  Params(Params.Upper()),
			  Knots);

  myCurve = new Geom_BSplineCurve(Poles, 
				  Knots,
				  TheCurve.Multiplicities(),
				  TheCurve.Degree());
  myIsDone = Standard_True;
}


//=======================================================================
//function : Handle_Geom_BSplineCurve&
//purpose  : 
//=======================================================================

const Handle(Geom_BSplineCurve)& GeomAPI_PointsToBSpline::Curve() const 
{
  if ( !myIsDone) 
    StdFail_NotDone::Raise(" ");
  return myCurve;
}



//=======================================================================
//function : Geom_BSplineCurve
//purpose  : 
//=======================================================================

GeomAPI_PointsToBSpline::operator Handle(Geom_BSplineCurve)() const
{
  return myCurve;
}


