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

#include "nsurface.h"
#include <vector>
#include <map>
#include "npoint.h"

struct polybary // computes barycentric coordinates from uv coordinates
{
  std::vector<npoint2> vi; // positions of points describing the reference element.
  polybary(int ns_); // by default, located on a unit circle centered at the origin. 1st point on x axis.
  polybary(std::vector<npoint2> &vi_) : vi(vi_) {}
  void init(std::vector<npoint2> &vi_) {vi=vi_;}
  void get_bary(npoint2 v, std::vector<double> &bary) const;
};

//polyindex allows to manage multiple indexes where the sum of the indexes is d.
// <200> <110> <101> <020> <011> <002>
// stored as (permutations are forbidden !)
// [00]  [01]  [02]  [11]  [12]  [22]
// unique index
//  0     1     2     3     4     5

class polyindex
{
  std::vector<int> tab; // position of all indexes (internal storage)
  int deg;// degree : nb of elems in tab
  int ns; // num of indexes : maxval for index +1 (==-1 if overflow)
public:
  polyindex(int d,int n) : deg(d),ns(n),tab(d,0){}
  polyindex(const std::vector<int> &vec); // vec is an index vector (sum of index=deg, num of index = ns)
  int get1index(void) const;  // get an equivalent unique index for storage, alas not dense yet
  void getindex(std::vector<int> &vec) const; //get the index vector (sum of index=deg, num of index = ns)
  void print(void) const;
  bool inc(void); // increment & tells if it overflows.
  polyindex& operator++(); // pre increment
  polyindex operator++(int); // post increment
  bool end(void); // tells if the intex went beyond the end.
  void zero(int ns); // cancel all indexes (zero)
  int getnumindexes(void) const; // total number of distinct indexes.
  polyindex operator +(const polyindex &other) const; // adds two polyindex of same ns.Results in a polyindex d1+d2,ns
};

class nbezierconvexpoly : public nparametricsurface
{
protected:
  std::vector<int> map; //!<mapping ids to consecutive numbers
  std::vector<npoint> val; //!< Control points.
  int ns;  //!< Number of sides.
  int nCP; //!< Number of control points.
  int deg; //!< Degree.
public:

  /// \Constructor.
  /// \param[in] degree_ wanted degree (not polynomial in general).
  /// \param[in] ns_ number of sides of the polygon.
  nbezierconvexpoly(int degree_, int ns_);
  virtual ~nbezierconvexpoly() {}
  virtual int degree(void) const  {return deg;} 
  virtual int degree_u(void) const  {return deg;}
  virtual int degree_v(void) const  {return deg;}
  virtual int nb_CP(void) const  {return nCP;}
  virtual int nb_CP_u(int iv=0) const  {return 0;}
  virtual int nb_CP_v(int iu=0) const  {return 0;}
  virtual double min_u() const  {return -0.5;}
  virtual double max_u() const  {return 0.5;}
  virtual double min_v() const  {return -0.5;}
  virtual double max_v() const  {return 0.5;}
  virtual void P(double u,double v, npoint& ret) const;
  virtual const npoint& CP(const polyindex &pi) const;
  virtual npoint CP(int which) const;
  virtual npoint& CP(int which);
  virtual npoint& CP(const polyindex &pi);
  virtual void set_CP(const polyindex &pi,const npoint& pt);
  virtual void set_CP(int which,const npoint& pt);
  virtual nsurface* clone() const  { return new nbezierconvexpoly(*this);}
  virtual void Display(data_container& data) const;
private:
  void getpoint(std::vector<double> coord, npoint &C) const ;    
};

#endif // __NBEZIERCONVEXPOLY_H
