// 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>.
//

#include <iostream>

#include "nlagrange.h"
#include "nspline.h"
#include "nbeziercurve.h"
#include "ncoons.h"
#include "nbspline.h"
#include "nbsplinesurface.h"
#include "nbeziertriangle.h"
#include "ndisplay.h"
#include "gnurbscallbacks.h"
//#include "ncylinder.h"
//#include "narc.h"
//#include "nextrusion.h"

void initsurface(nbsplinesurface &surf,double DX,double DY,double DZ)
{
  for (int i=0;i<surf.nb_CP_u();++i)
  {
    for (int j=0;j<surf.nb_CP_v();++j)
    {
      double R=1.5;
      double x=i*2/ ((double) surf.nb_CP_u()-1)-1;
      double y=j*2/ ((double) surf.nb_CP_v()-1)-1;
      double rr=x*x+y*y;
      double z=sqrt(R*R-rr)-0.9;
      z=z*z*5;
      /*      if ((i<=cpsu/2) && (j<=cpsv/2)) z=0;
            z=0;
            if ((i==cpsu-1) && (j==cpsv-1)) z=1;
            if ((i==1) && (j==1)) z=1;
            if ((i==cpsu-1) && (j==1)) z=1;
            if ((i==1) && (j==cpsv-1)) z=1;    */
      npoint p(x+DX,y+DY,z+DZ,1.0);
      surf.CP(i,j) =p;
    }
  }
  int endsu=surf.degree_u() +1;
  int du=surf.degree_u();
  int cpsu=surf.nb_CP_u()-1;
  for (int i=0;i<endsu;++i)
  {
    surf.u(i) =0.0;
    surf.u(cpsu+du+1-i) = (cpsu+du+2-2*endsu+1);     //1.0;
  }
  for (int i=1;i<= (cpsu+du+2-2*endsu);++i)
  {
    surf.u(i+endsu-1) =i;   //(1.0*i)/(cpsu+du+3-2*endsu);
  }
  int endsv=surf.degree_v() +1;
  int dv=surf.degree_v();
  int cpsv=surf.nb_CP_v()-1;

  for (int i=0;i<endsv;++i)
  {
    surf.v(i) =0.0;
    surf.v(cpsv+dv+1-i) = (cpsv+dv+2-2*endsv+1);     //1.0;
  }
  for (int i=1;i<= (cpsv+dv+2-2*endsv);++i)
  {
    surf.v(i+endsv-1) =i;   //(1.0*i)/(cpsv+dv+3-2*endsv);
  }
//  posv[3]=posv[4]=1.5;//(1.0*i)/(cpsv+dv+3-2*endsv);
//  posu[4]=posu[5]=posu[6]=2;//(1.0*i)/(cpsv+dv+3-2*endsv);
}


void initsurface_degen(nbsplinesurface &surf,double DX,double DY,double DZ)
{
  for (int i=0;i<surf.nb_CP_u();++i)
  {
    for (int j=0;j<surf.nb_CP_v();++j)
    {
      double R=1.5;
      double x=i*2/ ((double) surf.nb_CP_u()-1)-1;
      double y=j*2/ ((double) surf.nb_CP_v()-1)-1;
      double rr=x*x+y*y;
      double z=sqrt(R*R-rr)-0.9;
      x= (x) * (y+1) /2.;
      z=z*z*5;
      /*      if ((i<=cpsu/2) && (j<=cpsv/2)) z=0;
            z=0;
            if ((i==cpsu-1) && (j==cpsv-1)) z=1;
            if ((i==1) && (j==1)) z=1;
            if ((i==cpsu-1) && (j==1)) z=1;
            if ((i==1) && (j==cpsv-1)) z=1;    */
      npoint p(x+DX,y+DY,z+DZ,1.0);
      surf.CP(i,j) =p;
    }
  }
  int endsu=surf.degree_u() +1;
  int du=surf.degree_u();
  int cpsu=surf.nb_CP_u()-1;
  for (int i=0;i<endsu;++i)
  {
    surf.u(i) =0.0;
    surf.u(cpsu+du+1-i) = (cpsu+du+2-2*endsu+1);     //1.0;
  }
  for (int i=1;i<= (cpsu+du+2-2*endsu);++i)
  {
    surf.u(i+endsu-1) =i;   //(1.0*i)/(cpsu+du+3-2*endsu);
  }
  int endsv=surf.degree_v() +1;
  int dv=surf.degree_v();
  int cpsv=surf.nb_CP_v()-1;

  for (int i=0;i<endsv;++i)
  {
    surf.v(i) =0.0;
    surf.v(cpsv+dv+1-i) = (cpsv+dv+2-2*endsv+1);     //1.0;
  }
  for (int i=1;i<= (cpsv+dv+2-2*endsv);++i)
  {
    surf.v(i+endsv-1) =i;   //(1.0*i)/(cpsv+dv+3-2*endsv);
  }
  /*
    int mu=(surf.nb_CP_u())/2-du/2;
    int nu=mu+du-1;
    int mv=(surf.nb_CP_v())/2-dv/2;
    int nv=mv+dv-1;
    */
  int mu=0;
  int nu=surf.nb_CP_u();
  int mv=0;
  int nv=1;

  npoint p(0,0,0,0);

  for (int j=mv;j<nv;++j)
  {
    for (int i=mu;i<nu;++i)
    {
      p+=surf.CP(i,j);
    }
  }
  p.perspective_divide();
  for (int j=mv;j<nv;++j)
  {
    for (int i=mu;i<nu;++i)
    {
      surf.CP(i,j) =p;
    }
  }

//  posv[3]=posv[4]=1.5;//(1.0*i)/(cpsv+dv+3-2*endsv);
//  posu[4]=posu[5]=posu[6]=2;//(1.0*i)/(cpsv+dv+3-2*endsv);
}



void initsurfaceperiodicuv(nbsplinesurface &surf,double DX,double DY,double DZ)
{
  int endsu=surf.degree_u() +1;
  int du=surf.degree_u();
  int cpsu=surf.nb_CP_u()-1;

  int endsv=surf.degree_v() +1;
  int dv=surf.degree_v();
  int cpsv=surf.nb_CP_v()-1;
  int cpsv2=cpsv-dv+1;
  for (int j=0;j<=cpsv;++j)
  {
    double anglev=j*2*n_pi/ ((double)(cpsv2));

    int cpsu2=cpsu-du+1;
    double random2=cos(anglev*6) /6;
    for (int i=0;i<=cpsu;++i)
    {
      double angle=i*2*n_pi/ ((double)(cpsu2));
//      double zz=j*2/((double)(cpsv))-1;
      double random=2* (randr() +randr()-0.5) /7;
      random= (1+cos(anglev*4)) *cos(angle*6) /8;
      npoint p;
      p[0]= (cos(angle+anglev/2) * (0.5+random) +1.5) *cos(anglev) * (1+random2) / (2.5) +DX;
      p[1]= (cos(angle+anglev/2) * (0.5+random) +1.5) *sin(anglev) * (1+random2) / (2.5) +DY;
      p[2]=1+sin(angle+anglev/2) * (0.5+random) / (2.5) +DZ;
      p[3]=1.0;
      surf.CP(i,j) =p;
    }
  }

  for (int i=0;i<endsu;++i)
  {
    surf.u(i) =-endsu+i+1;
    surf.u(cpsu+du+1-i) = (cpsu+du+2-2*endsu+1) +endsu-i-1;
  }
  for (int i=1;i<= (cpsu+du+2-2*endsu);++i)
  {
    surf.u(i+endsu-1) =i;
  }
  for (int i=0;i<endsv;++i)
  {
    surf.v(i) =-endsv+i+1;
    surf.v(cpsv+dv+1-i) = (cpsv+dv+2-2*endsv+1) +endsv-i-1;
  }
  for (int i=1;i<= (cpsv+dv+2-2*endsv);++i)
  {
    surf.v(i+endsv-1) =i;
  }
}


void initbeziertriangle(nbeziertriangle &surf,double DX,double DY,double DZ)
{
  int deg=surf.degree();
  for (int j=0;j<=deg;++j)
  {
    for (int i=0;i<=deg-j;++i)
    {
      int k = deg-i-j;
      double x= ((double) i) / (deg) + ((double) j) / (deg) /2.;
      double y= ((double) j) / (deg) *sqrt(3) /2.;
      double z= (x-y/2) * (x-1) +y* (y-sqrt(3) /2);
      npoint p(x+DX,y+DY,z+DZ,1.0);
      surf.CP(i,j,k) =p;
    }
  }
}


void initbeziertriangle_sphere(nbeziertriangle &surf,double DX,double DY,double DZ)
{
  int deg=surf.degree();
  double sq=sqrt(2) /2.;
  if (deg!=2) return;
  surf.CP(0,0,2) =npoint(1.0+DX,0.0+DY,0.0+DZ,1.0);
  surf.CP(1,0,1) =npoint((0.0+DX) *sq, (0.0+DY) *sq, (0.0+DZ) *sq,sq);
  surf.CP(2,0,0) =npoint((0.0+DX), (1.0+DY), (0.0+DZ),1.0);
  surf.CP(0,1,1) =npoint((0.0+DX) *sq, (0.0+DY) *sq, (0.0+DZ) *sq,sq);
  surf.CP(1,1,0) =npoint((0.0+DX) *sq, (0.0+DY) *sq, (0.0+DZ) *sq,sq);
  surf.CP(0,2,0) =npoint((0.0+DX), (0.0+DY), (1.0+DZ),1.0);
}

void initbeziertriangle_valise(nbeziertriangle &surf,double DX,double DY,double DZ)
{
  int deg=surf.degree();
  double sq=sqrt(2) /2.;
  if (deg!=2) return;
  surf.CP(0,0,2) =npoint((1.0+DX), (0.0+DY), (0.0+DZ),1.0);
  surf.CP(1,0,1) =npoint((1.0+DX) *sq, (1.0+DY) *sq, (0.0+DZ) *sq,sq);
  surf.CP(2,0,0) =npoint((0.0+DX), (1.0+DY), (0.0+DZ),1.0);
  surf.CP(0,1,1) =npoint((1.0+DX) *sq, (0.0+DY) *sq, (1.0+DZ) *sq,sq);
  surf.CP(1,1,0) =npoint((0.0+DX) *sq, (1.0+DY) *sq, (1.0+DZ) *sq,sq);
  surf.CP(0,2,0) =npoint((0.0+DX), (0.0+DY), (1.0+DZ),1.0);
}

void initbeziertriangle_valise_3(nbeziertriangle &surf,double DX,double DY,double DZ)
{
  int deg=surf.degree();
//  double sq=sqrt(2)/3.;
  double sq1= (1+sqrt(2)) /3.;
  double sq2=sqrt(2) / (1+sqrt(2));
  double w=1;
  if (deg!=3) return;
  surf.CP(0,0,3) =npoint((1.0+DX), (0.0+DY), (0.0+DZ),1.0);
  surf.CP(1,0,2) =npoint((1.0+DX) *sq1, (sq2+DY) *sq1, (0.0+DZ) *sq1,sq1);
  surf.CP(2,0,1) =npoint((sq2+DX) *sq1, (1.0+DY) *sq1, (0.0+DZ) *sq1,sq1);
  surf.CP(3,0,0) =npoint((0.0+DX), (1.0+DY), (0.0+DZ),1.0);

  surf.CP(0,1,2) =npoint((1.0+DX) *sq1, (0.0+DY) *sq1, (sq2+DZ) *sq1,sq1);
  surf.CP(1,1,1) =npoint(((1.0+sq2) /2.0+DX) *w, ((1.0+sq2) /2.0+DY) *w, ((1.0+sq2) /2.0+DZ) *w,w);
  surf.CP(2,1,0) =npoint((0.0+DX) *sq1, (1.0+DY) *sq1, (sq2+DZ) *sq1,sq1);

  surf.CP(0,2,1) =npoint((sq2+DX) *sq1, (0.0+DY) *sq1, (1.0+DZ) *sq1,sq1);
  surf.CP(1,2,0) =npoint((0.0+DX) *sq1, (sq2+DY) *sq1, (1.0+DZ) *sq1,sq1);

  surf.CP(0,3,0) =npoint((0.0+DX), (0.0+DY), (1.0+DZ),1.0);

}



void initbezier_curve(nbeziercurve &crv,double DX,double DY,double DZ)
{
  int deg=crv.degree();
  double sq=sqrt(2) /2.;
  if (deg!=2) return;
  crv.CP(0) =npoint((sq+DX), (sq+DY), (0.0+DZ),1.0);
  crv.CP(1) =npoint((sq+DX) *sq, (sq+DY) *sq, (1.0+DZ) *sq,sq);
  crv.CP(2) =npoint((0.0+DX), (0.0+DY), (1.0+DZ),1.0);
  /*
    crv.CP(0)=npoint((1+DX),(0+DY),(0.0+DZ),1.0);
    crv.CP(1)=npoint((1+DX)*sq,(0+DY)*sq,(1.0+DZ)*sq,sq);
    crv.CP(2)=npoint((0.0+DX),(0.0+DY),(1.0+DZ),1.0);
  */
}



int main(void)
{
//  data_container data;
  ndisplay display;
  gnurbscallbacks CB;
  display.setcallbacks(&CB);

  npoint a(0,0,0,1.0),b(1,0,0,1.0),c(1,1,0,1.0),d(0,1,0,1.0);
  npoint ab(0.5,0,0.5,1.0),bc(1,0.5,0.25,1.0),cd(0.5,1,-0.5,1.0),da(0,0.5,-0.25,1.0);
  nbeziercurve cab(0),cbc(0);
  cab.add_CP(a);
  cab.add_CP(ab);
  cab.add_CP((ab*-1+b*2+a) /3);
  cab.add_CP(b);
  cbc.add_CP(b);
  cbc.add_CP(bc);
  cbc.add_CP(c);
  nlagrange ccd(0),cda(0);
  ccd.add_CP(0,d);
  ccd.add_CP(0.5,cd);
  ccd.add_CP(1,c);
  cda.add_CP(0,a);
  cda.add_CP(0.5,da);
  cda.add_CP(1,d);
  ncoons surf(cab,ccd,cda,cbc);

  nbspline c0u(4,2),c1u(4,2),c0v(3,2),c1v(3,2);
  c0u.u(0) =c0u.u(1) =c0u.u(2) =0;
  c0u.u(3) =1;
  c0u.u(4) =c0u.u(5) =c0u.u(6) =2;
  c0u.CP(0) =npoint(0.,0.,0.);
  c0u.CP(1) =npoint(1.,0.,1.);
  c0u.CP(2) =npoint(2.,0.,-1.);
  c0u.CP(3) =npoint(3.,0.,0.);
  c1u=c0u;
  for (int i=0;i<c0u.nb_CP();++i) c1u.CP(i) =c0u.CP(i) +npoint(0.,2.,0.,0.);
  c0v.u(0) =c0v.u(1) =c0v.u(2) =0;
  c0v.u(3) =c0v.u(4) =c0v.u(5) =1;
  c0v.CP(0) =npoint(0.,0.,0.);
  c0v.CP(1) =npoint(0.,1.,-1.);
  c0v.CP(2) =npoint(0.,2.,0.);
  c1v=c0v;
  for (int i=0;i<c0v.nb_CP();++i) c1v.CP(i) =c0v.CP(i) +npoint(3.,0.,0.,0.);

  nbsplinesurface coons_bs;
  nbsplinesurface S1,S2,S3;
  coons_bs.makecoons(c0u,c1u,c0v,c1v,S1,S2,S3);

  properties p;

  p.pointsize=3;
  p.c=color(255,0,0);
  CB.add_entity(&S1,p);
  p.c=color(0,255,0);
  CB.add_entity(&S2,p);
  p.c=color(0,0,255);
  CB.add_entity(&S3,p);
  p.c=color(255,255,255);
  
  CB.add_entity(&c1u,p);
  CB.add_entity(&c0u,p);
  CB.add_entity(&c0v,p);
  CB.add_entity(&c1v,p);
  CB.add_entity(&coons_bs,p);
  
  nbsplinesurface bssurface(15,3,9,2);
  nbsplinesurface bssurface2(5,3,5,2);
  nbsplinesurface bssurface3(5,3,5,3);
  nbsplinesurface bssurface4(5,3,5,3);
  nbeziertriangle beztr(3);
  nbeziertriangle sphere(2);
  nbeziertriangle sphere3(3);
  nbeziercurve curv(3);


  initsurfaceperiodicuv(bssurface,0,0,0);
  initsurface(bssurface2,2,0,2);
  initsurface(bssurface3,5,0,2);
  initsurface_degen(bssurface4,5,0,2);  
  initbeziertriangle(beztr,2,0,0);
  initbeziertriangle_valise(sphere,4,4,4);
  initbeziertriangle_valise_3(sphere3,2,2,0);
  initbezier_curve(curv,2,2,0);

//  narc arc(npoint3(0,0,-5),npoint3(0,0,1),npoint3(1,0,-5),npoint3(-1,0,-5),true);
//  narc arc2(npoint3(0,0,-5),npoint3(0,0,1),npoint3(1,0,-5),npoint3(0,1,-5));
//    arc.Display(data);
//  nextrusion extr(npoint3(0,0,10),arc,10,3);
//  extr.Display(data);
//  arc2.Display(data);
//  display.add_curve(&arc);
//  display.add_curve(&arc2);

//  npoint3 a1(0,4,4);
//  npoint3 a2(4,4,4);
//  npoint3 rad(0,5,4);
//  ncylinder cyl(a1,a2,rad);

//  npoint3 a3(2,2,-4);
//  npoint3 a4(2,2,0);
//  npoint3 rad2(2,3,-4);
//  ncylinder cyl2(a3,a4,rad2);


  CB.add_entity(&bssurface,p);

  CB.add_entity(&bssurface2,p);
  CB.add_entity(&bssurface3,p);
  CB.add_entity(&bssurface4,p);
  CB.add_entity(&sphere,p);
  CB.add_entity(&sphere3,p);
  CB.add_entity(&beztr,p);
  CB.add_entity(&curv,p);
  
/////2
//  bssurface2.Display(data); // surface bspline
//  bssurface3.Display(data); // surface bspline

//  bssurface4.Display(data); // surface bspline
//  beztr.Display(data); // triangle de bezier
//  sphere.Display(data); // coin de valise (deg 2)
//  sphere3.Display(data); // coin de valise (deg. 3)
//cyl.Display(data); // cylindre 1
//  cyl2.Display(data); // cylindre 2
//  curv.degree_elevation();
//  for (int i=0;i<4;++i) { npoint p=curv.CP(i);std::cout<< p[0]/p[3] << " " << p[1]/p[3] << " "<< p[2]/p[3] << " "<< p[3] << std::endl;}
//  curv.Display(data); // arc de cercle
//  display.add_curve(&curv);

//  display.init_data(CB.datas);
//  CB.draw();
  display.display();
  return 0;
}
