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

#include "nutil.h"
#include "nentity.h"

/// A generic curve.
class ncurve : public nentity
{
public:
  virtual void Discretize(nmesh &mesh,nmesh &bnd, double du=0., double ds=0., double eps=0., double epsr=0., int n=0) const = 0;
  static double FPeps;  //!< Machine epsilon.
  static double FPeps2; //!< FPeps^1/2
  static double FPeps3; //!< FPeps^1/3
  static double FPeps4; //!< FPeps^1/4
  static void update_FPeps(bool mode=false);
  virtual int dim(void) const { return 1;}
};


/// A generic parametric curve.
class nparametriccurve : public ncurve
{
  friend class ntrimmedcurve;
public:
  /// \brief Returns the degree of the curve (if polynomial).
  /// \return Curve degree.
  virtual int degree(void) const {return 0;}

  /// \brief Minimum allowed value of the parameter.
  /// \return Minimum allowed value of the parameter.
  virtual double min_u(void) const =0;

  /// \brief Maximum allowed value of the parameter.
  /// \return Maximum allowed value of the parameter.
  virtual double max_u(void) const =0;

  /// \brief if it is periodic, then min_u and max_u are conventional and not the actual bounds of a curve.
  /// \return True if periodic, false otherwise.
  virtual bool is_periodic(void) const { return false; }

  /// \brief If it is periodic, this is the period.
  /// \return Period.
  virtual double period(void) const {return 0.;}

  /// \brief Point along the curve for parameter u.
  /// \param[in] u parameter.
  /// \param[out] ret point corresponding to parameter u.
  virtual void P(double u,npoint& ret) const =0;

  /// \brief point + first derivative
  /// \param[in] u parameter.
  /// \param[out] p point corresponding to parameter u.
  /// \param[out] dpdu first derivative corresponding to parameter u.
  virtual void dP(double u,npoint& p,npoint& dpdu) const
  {
    P(u,p);
    dPdu(u,dpdu);
  }
  
  /// \brief point + all derivatives until second derivative.
  /// \param[in] u parameter.
  /// \param[out] p point corresponding to parameter u.
  /// \param[out] dpdu first derivative corresponding to parameter u.
  /// \param[out] d2pdu2 second derivative corresponding to parameter u.
  virtual void d2P(double u,npoint& p,npoint& dpdu, npoint& d2pdu2) const
  {
    P(u,p);
    dPdu(u,dpdu);
    d2Pdu2(u,d2pdu2);
  }
  
  /// \brief First derivative - generic numerical implementation.
  /// \param[in] u_ parameter.
  /// \param[out] ret first derivative at parameter u_.
  virtual void dPdu(double u_,npoint& ret) const;

  /// \brief Second derivative, generic numerical implementation.
  /// \param[in] u_ parameter.
  /// \param[out] ret second derivative at parameter u_.
  virtual void d2Pdu2(double u_,npoint& ret) const;

  /// \brief Computes the various differentials w.r. to u.
  /// It bears its name because of the similarity with bivariate manifolds.
  virtual void fundamental_forms(double u, double &M1,double &M2,npoint3 *J=0) const;

  /// \brief Computes curvatures and directions.
  /// \param[in] u parameter.
  /// \param[out] kappa curvature.
  virtual void principal_curvatures(double u, double& kappa, double* m1 = 0, double* m2 = 0, double thr = 1e-5) const ;
                           
  /// \brief Discretizes the curve in line segments for display.
  /// \param[in] data data container to fill with the line segments.
  virtual void Display(data_container& data) const;
  virtual void Discretize(nmesh &mesh, double du=0., double ds=0., double eps=0., double epsr=0., int n=0) const ;
  virtual void Discretize(nmesh &mesh,nmesh &bnd, double du=0., double ds=0., double eps=0., double epsr=0., int n=0) const ;
  virtual ncurve* clone() const =0 ;
private:
  void _Discretize(std::vector< std::pair<npoint3,double> >& pts, double from, npoint3 Posf, double to, npoint3 Post, double du, double ds, double eps, double epsr,int n) const ;    // version par defaut
  void _Display(double from, double to, data_container &data) const ;
};

class nparametricsurface;

/// A parametric curve embedded on a parametric surface.
class nembeddedcurve : public nparametriccurve
{
  const nparametriccurve &crv;
  const nparametricsurface &surf;
public:
  nembeddedcurve(const nparametriccurve &crv_,const nparametricsurface &surf_):crv(crv_),surf(surf_) {}

  /// \brief Minimum allowed value of the parameter.
  /// \return Allowed value.
  virtual double min_u(void) const {return crv.min_u();}

  /// \brief Maximum allowed value of the parameter.
  /// \return Allowed value.
  virtual double max_u(void) const {return crv.max_u();}

  /// \brief Point along the curve for parameter u.
  /// \param[in] u parameter.
  /// \param[out] ret point corresponding to parameter u.
  virtual void P(double u,npoint& ret) const;
//  virtual void dPdu(double u_,npoint& ret) const;  // first derivative - generic numerical implementation
//  virtual void d2Pdu2(double u_,npoint& ret) const; // second derivative, generic numerical implementation

  /// \brief Point along the curve for parameter u, in the parametric space of the support surface
  /// \param[in] u parameter.
  /// \param[out] ret point corresponding to parameter u.
  virtual void Puv(double u,npoint& ret) const;
  
  /// \brief Computes normal and geodesic curvatures of an embedded curve.
  /// \param[in] t curve parameter.
  /// \param[out] kappa curvatures.
  /// \param[out] m1 first fundamental form.
  /// \param[out] m2 second fundamental form.
  virtual void relative_curvatures(double t,double kappa[2], double m1[2][2]=0, double m2[2][2]=0) const;
  
  
  const nparametriccurve& get_uvcurve()  const {return crv;}
  const nparametricsurface& get_surface() const {return surf;}
  virtual ncurve* clone() const 
  {
    return new nembeddedcurve(*this);
  }
};

#endif //__NCURVE_H
