// 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 __NBSPLINESURFACE_H
#define __NBSPLINESURFACE_H


#include "nsurface.h"
#include "nbspline.h"
#include <vector>

class nbsplinesurface : public nparametricsurface
{
protected:
  std::vector<npoint> val; // control points (ordered in u then in v)
  int nCPu; // number of control points (u)
  int nCPv; // number of control points (v)
  std::vector<double> knotsu; // nodal sequence U
  std::vector<double> knotsv; // nodal sequence V
  int nknotsu; // number of knots (U)
  int nknotsv; // number of knots (V)
  int degu; // degree in u
  int degv; // degree in v

public:
  nbsplinesurface() : val(1),nCPu(1),degu(0),nCPv(1),degv(0),nknotsu(2),nknotsv(2),knotsu(2),knotsv(2)
  {
    knotsu[0]=0;
    knotsu[1]=1;
    knotsv[0]=0;
    knotsv[1]=1;
    val[0]=npoint();
  }
  nbsplinesurface(int nCPu_,int degreeu_,int nCPv_,int degreev_) : val(nCPu_*nCPv_),
      nCPu(nCPu_),degu(degreeu_),nknotsu(nCPu_+degreeu_+1),knotsu(nCPu_+degreeu_+1),
      nCPv(nCPv_),degv(degreev_),nknotsv(nCPv_+degreev_+1),knotsv(nCPv_+degreev_+1) {}
  virtual ~nbsplinesurface() {}
  void init(int nCPu_,int degreeu_,int nCPv_,int degreev_)
  {
      val.resize(nCPu_*nCPv_);
      nCPu=nCPu_;
      degu=degreeu_;
      nknotsu=nCPu_+degreeu_+1;
      knotsu.resize(nCPu_+degreeu_+1);
      nCPv=nCPv_;
      degv=degreev_;
      nknotsv=nCPv_+degreev_+1;
      knotsv.resize(nCPv_+degreev_+1);
  }
  void makerevolution(nbspline & myBSpline);
  void makecoons(const nbspline &Cu0,const nbspline &Cu1,const nbspline &Cv0,const nbspline &Cv1,data_container& data);
  virtual int degree(void) const;
  virtual int degree_u(void) const
  {
    return degu;
  }
  virtual int degree_v(void) const
  {
    return degv;
  }
  virtual int nb_CP(void) const
  {
    return nCPu*nCPv;
  }
  virtual int nb_CP_u(int iv=0) const
  {
    return nCPu;
  }
  virtual int nb_CP_v(int iu=0) const
  {
    return nCPv;
  }
  virtual int nb_knots_u(void) const
  {
    return nknotsu ;
  }
  virtual int nb_knots_v(void) const
  {
    return nknotsv ;
  }
  virtual double min_u() const
  {
    return knotsu[degu];
  }
  virtual double max_u() const
  {
    return knotsu[nknotsu-degu-1];
  }
  virtual double min_v() const
  {
    return knotsv[degv];
  }
  virtual double max_v() const
  {
    return knotsv[nknotsv-degv-1];
  }
  virtual void P(double u,double v, npoint& ret) const ;
  
  
  virtual void dPdu(double u,double v, npoint& ret) const ;
  virtual void dPdv(double u,double v, npoint& ret) const ;
  
  virtual void d2Pdu2(double u,double v, npoint& ret) const ;
  virtual void d2Pdv2(double u,double v, npoint& ret) const ;
  
  virtual void d2Pdudv(double u,double v, npoint& ret) const ;
  
  
  
  virtual npoint CP(int whichu,int whichv) const
  {
    return val[whichu+nCPu*whichv];
  }
  virtual npoint CP(int which) const
  {
    return val[which];
  }
  virtual npoint& CP(int whichu,int whichv)
  {
    return val[whichu+nCPu*whichv];
  }
  virtual npoint& CP(int which)
  {
    return val[which];
  }
  virtual void set_CP(int whichu,int whichv,const npoint& pt)
  {
    val[whichu+nCPu*whichv]=pt;
  }
  virtual void set_CP(int which,const npoint& pt)
  {
    val[which]=pt;
  } 
  virtual double u(int which) const
  {
    return knotsu[which];
  }
  virtual double& u(int which)
  {
    return knotsu[which];
  }
  virtual double v(int which) const
  {
    return knotsv[which];
  }
  virtual double& v(int which)
  {
    return knotsv[which];
  }
  void insertknot_u(double u,int r);
  void saturate_u();
  void degree_elevation_u();
  void insertknot_v(double v,int r);
  void saturate_v();
  void degree_elevation_v();

  int findspan(const std::vector<double> &knots,int nknots, int deg, double u) const ;
  void basisfuns(const std::vector<double> &knots,int nknots, int deg, int i, double para, std::vector<double> &N) const ;
  void gradbasisfuns(const std::vector<double> &knots,int nknots,int deg,int i, double u,int n,std::vector<std::vector<double> > &N) const ;
  virtual nsurface* clone() const
  {
    return new nbsplinesurface(*this);
  }
private:
  void insertknotu_(double u,int k,int s,int r);
  void insertknotv_(double v,int k,int s,int r);
  void findspanmult(const std::vector<double> &knots,int nknots, int deg,double u,int &k,int &s);
  void curvepoint(double u, double v, npoint &C) const ;
  void dercurvepoint(double u, double v, int nu,int nv,npoint &C) const ;
  
};



#endif // __NBSPLINESURFACE_H
