// Gnurbs - A curve and surface library
// Copyright (C) 2008-2026 Eric Bechet
//
// See the LICENSE file for contributions and license information.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//

#ifndef __NBEZIERCURVE_H
#define __NBEZIERCURVE_H


#include "ncurve.h"
#include <vector>
#include <iostream>
#include <list>

/// A Bezier curve.
class nbeziercurve : public nparametriccurve
{
  std::vector<npoint> val; //!< Array of control points.
  int nCP; //!< Number of control points.
public:

  /// Constructor.
  /// \param[in] nCP_ number of control points.
  /// \warning Control points are unitialized.
  nbeziercurve(int nCP_) : val(nCP_),nCP(nCP_) {}

  /// Constructor.
  /// \param[in] nCP_ number of control points.
  /// \param[in] tab_ table of control points.
  nbeziercurve(int nCP_, npoint tab_[]) : val(nCP_),nCP(nCP_) 
  {
    for (int i=0;i<nCP;++i) val[i]=tab_[i];
  }

  /// \brief Returns the polynomial degree.
  /// \return Degree.
  virtual int degree(void) const
  {
    return nCP-1 ;
  }

  /// \brief Returns the number of control points.
  /// \return Number of control points.
  virtual int nb_CP(void) const
  {
    return nCP ;
  }

  /// \brief Adds a control point at the end of the array.
  /// \param[in] val_ control point to add.
  virtual void add_CP(const npoint &val_)
  {
    val.push_back(val_);
    nCP++;
  }

  /// \brief Returns the minimal possible value for the parameter u.
  /// \return Minimal value.
  virtual double min_u(void) const
  {
    return 0.;
  }

  /// \brief Returns the maxima possible value for the parameter u.
  /// \return Maximal value.
  virtual double max_u(void) const
  {
    return 1.;
  }

  /// \brief Evalute basis functions.
  /// \param[in] which basis function number.
  /// \param[in] u evaluation value.
  /// \return Value of basis function "which" at u.
  double Basis(int which,double u) const;

  /// \brief Computes the coordinates of a point along the curve.
  /// \param[in] u_ curve parameter.
  /// \param[out] ret point on the curve at parameter u_.
  virtual void P(double u_,npoint& ret) const;
  virtual void dPdu(double u_,npoint& ret) const ; 
  virtual void d2Pdu2(double u_,npoint& ret) const ;

  /// \brief Returns one of the control points (numbering starts at 0) (constant version).
  /// \param[in] which wanted control point number.
  /// \return Control point.
  virtual npoint CP(int which) const
  {
    return val[which];
  }

  /// \brief Returns one of the control points (numbering starts at 0) (non-constant version).
  /// \param[in] which wanted control point number.
  /// \return Control point.
  virtual npoint& CP(int which)
  {
    return val[which]; 
  }

  /// \brief Sets a control point to a specified position.
  /// \param[in] which control point number to set.
  /// \param[in] pt new control point position.
  virtual void set_CP(int which,const npoint& pt)
  {
    val[which]=pt;
  }

  /// \brief Sets the number of control points.
  /// \param[in] nb new number of control points.
  /// \warning If nb > previous number of control points: the new control points are unitialized.
  /// If nb > previous number of control points: the last control points are lost. The first control points are keept.
  virtual void set_nb_CP(int nb)
  {
    val.resize(nb);
    nCP=nb;
  }

  /// \brief Increases the degree of the curve by 1 (curve remains geometrically unchanged).
  void degree_elevation();

  /// \brief Translates the curve by vector vec.
  /// \param[in] vec translation vector.
  void translate(npoint vec);

  /// \brief Cuts the curve into two new curves.
  /// \param[in] u_ cut parameter.
  /// \param[out] ret cut point.
  /// \param[out] left obtained left curve.
  /// \param[out] right obtained right curve.
  void cut(double u_, npoint & ret,nbeziercurve &left,nbeziercurve &right) const;
  void Display(data_container& data) const;    // version optimisee
  virtual nbeziercurve* clone() const // returns a clone of the curve (allocated on the heap)
  {
    return new nbeziercurve(*this);
  }
private:
  int binom(int i,int n) const ;
  double bezierBasisRecurrence(int degree, int which,double u_) const ;
  void DeCasteljau(double u_, npoint & ret) const ;
  void DeCasteljau(double u_, npoint & ret,nbeziercurve &left,nbeziercurve &right) const ;
  void DeCasteljau(double u_, int stop,std::vector<npoint>& ret) const ;
  void recursivedivide(std::list<nbeziercurve> &list,int deep) const;
};

#endif // __NBEZIERCURVE_H

