// File:	Geom2dAPI_PointsToBSpline.cxx
// Created:	Wed Mar 23 15:28:27 1994
// Author:	Bruno DUMORTIER
//		<dub@fuegox>

#include <Geom2dAPI_PointsToBSpline.ixx>

#include <AppDef_BSplineCompute.hxx>
#include <AppDef_MultiLine.hxx>
#include <AppParCurves_MultiBSpCurve.hxx>
#include <BSplCLib.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <math_Vector.hxx>


//=======================================================================
//function : Geom2dAPI_PointsToBSpline
//purpose  : 
//=======================================================================

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


//=======================================================================
//function : Geom2dAPI_PointsToBSpline
//purpose  : 
//=======================================================================

Geom2dAPI_PointsToBSpline::Geom2dAPI_PointsToBSpline
  (const TColgp_Array1OfPnt2d& Points,
   const Standard_Integer      DegMin, 
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol2D)
{
  Init(Points,DegMin,DegMax,Continuity,Tol2D);
}


//=======================================================================
//function : Geom2dAPI_PointsToBSpline
//purpose  : 
//=======================================================================

Geom2dAPI_PointsToBSpline::Geom2dAPI_PointsToBSpline
  (const TColStd_Array1OfReal& YValues,
   const Standard_Real         X0,
   const Standard_Real         DX,
   const Standard_Integer      DegMin, 
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol2D)
{
  Init(YValues,X0,DX,DegMin,DegMax,Continuity,Tol2D);
}


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

void Geom2dAPI_PointsToBSpline::Init
  (const TColgp_Array1OfPnt2d& Points,
   const Standard_Integer      DegMin,
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol2D)
{
  Standard_Real Tol3D = 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_Array1OfPnt2d Poles(1,TheCurve.NbPoles());

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

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

void Geom2dAPI_PointsToBSpline::Init
  (const TColStd_Array1OfReal& YValues,
   const Standard_Real         X0,
   const Standard_Real         DX,
   const Standard_Integer      DegMin, 
   const Standard_Integer      DegMax,
   const GeomAbs_Shape         Continuity,
   const Standard_Real         Tol2D)
{
  // first approximate the Y values (with dummy 0 as X values)

  Standard_Real Tol3D = 0.; // dummy argument for BSplineCompute.
  TColgp_Array1OfPnt2d Points(YValues.Lower(),YValues.Upper());
  math_Vector Param(YValues.Lower(),YValues.Upper());
  Standard_Real length = DX * (YValues.Upper() - YValues.Lower());
  Standard_Integer i;
  
  for (i = YValues.Lower(); i <= YValues.Upper(); i++) {
    Param(i) = (X0+(i-1)*DX)/(X0+length);
    Points(i).SetCoord(0.0, YValues(i));
  }

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

  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);

  const AppParCurves_MultiBSpCurve& TheCurve = TheComputer.Value();
  
  Standard_Integer Degree = TheCurve.Degree();
  TColgp_Array1OfPnt2d Poles(1,TheCurve.NbPoles());
  Standard_Integer nk = TheCurve.Knots().Length();
  TColStd_Array1OfReal Knots(1,nk);
  TColStd_Array1OfInteger Mults(1,nk);

  TheCurve.Curve(1, Poles);



  // compute X values for the poles
  TColStd_Array1OfReal XPoles(1,Poles.Upper());

  // start with a line
  TColStd_Array1OfReal    TempPoles(1,2);
  TColStd_Array1OfReal    TempKnots(1,2);
  TColStd_Array1OfInteger TempMults(1,2);
  TempMults.Init(2);
  TempPoles(1) = X0;
  TempPoles(2) = X0 + length;
  TempKnots(1) = 0.;
  TempKnots(2) = 1.;

  // increase the Degree
  TColStd_Array1OfReal    NewTempPoles(1,Degree+1);
  TColStd_Array1OfReal    NewTempKnots(1,2);
  TColStd_Array1OfInteger NewTempMults(1,2);
  BSplCLib::IncreaseDegree(1,Degree,Standard_False,1,
			   TempPoles,TempKnots,TempMults,
			   NewTempPoles,NewTempKnots,NewTempMults);


  // insert the Knots
  BSplCLib::InsertKnots(Degree,Standard_False,1,
			NewTempPoles,NewTempKnots,NewTempMults,
			TheCurve.Knots(),TheCurve.Multiplicities(),
			XPoles,Knots,Mults,
			Epsilon(1));
  
  // scale the knots
  for (i = 1; i <= nk; i++) {
    Knots(i) = X0 + length * Knots(i);
  }

  // set the Poles
  for (i = 1; i <= Poles.Upper(); i++) {
    Poles(i).SetX(XPoles(i));
  }



  myCurve = new Geom2d_BSplineCurve(Poles, Knots, Mults, Degree);
  myIsDone = Standard_True;
}



//=======================================================================
//function : Handle_Geom2d_BSplineCurve&
//purpose  : 
//=======================================================================

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



//=======================================================================
//function : Geom2d_BSplineCurve
//purpose  : 
//=======================================================================

Geom2dAPI_PointsToBSpline::operator Handle(Geom2d_BSplineCurve)() const
{
  return myCurve;
}


