#ifndef _NURBS_H_
#define _NURBS_H_

#include "geometric.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#ifndef NULL
#define NULL ((void *)0)
#endif
#define QUADPTS	7
#define NUM_SUBKL 1000

/* Types definition */
//NURBS control point
typedef struct{
	double x;
	double y;
	double z;
	double w;//weight
}nurbs_ctrl_pt;


typedef struct{
	unsigned int deg;					// degree of curve
	unsigned int ncp;					// number of control points
	unsigned int nk;					// number of knots (always! nk=ncp+deg+1)
	unsigned int nsubk;					// number of nonzero knot sub spans (always! ns=nk-2*deg-1)
	unsigned int k_start;				// current segment start knot
	unsigned int k_end;					// current segment end knot
	double* knots;						// knot array
	double* knots_1d;					// knot array for 1st derivative
	double* knots_2d;					// knot array for 2nd derivative
	double* knots_3d;					// knot array for 3rd derivative
	nurbs_ctrl_pt* control_points;		// control point array
	nurbs_ctrl_pt* control_points_1d;	// control point array of 1st derivative curve
	nurbs_ctrl_pt* control_points_2d;	// control point array of 2nd derivative curve
	nurbs_ctrl_pt* control_points_3d;	// control point array of 3rd derivative curve
	nurbs_ctrl_pt* tmp_pts;				// temp ctrl points in deBoor evaluation (size=deg+1)
	nurbs_ctrl_pt* tmp_pts_1d;			// temp ctrl points in deBoor evaluation for 1st derivative (size=deg)
	nurbs_ctrl_pt* tmp_pts_2d;			// temp ctrl points in deBoor evaluation for 2nd derivative (size=deg-1)
	nurbs_ctrl_pt* tmp_pts_3d;			// temp ctrl points in deBoor evaluation for 3rd derivative (size=deg-2)
	double* ctp_u;						// parameter value corresponding to each control point
	double* kL;							// lengths of each knot span
	double* subku;						// subintervals u value
	double* subkL;						// subintervals lengths
	double L;							// length of whole NURBS
}nurbs_curve;

void cart2homo_vect(nurbs_ctrl_pt* cart, nurbs_ctrl_pt* homo, unsigned int len);
void homo2cart_vect(nurbs_ctrl_pt* homo, nurbs_ctrl_pt* cart, unsigned int len);


void scale_pts(nurbs_ctrl_pt* pt, double C, int len);
void knot_setup_uniform(nurbs_curve* curve);
    /* find lower index of knot span in which containing e given parameter u is located */
int nurbs_find_span(int n, int p, double u, double* Uk);
    /* allocate mem and initialize nurbs curve defined in .NURBS file*/
void nurbs_curve_alloc_file(char* path, nurbs_curve* curve);
    /* free curve struct memory */
void nurbs_curve_free(nurbs_curve* curve);
    /* evaluate NURBS and its derivs using DeBoor's algorithm */
void nurbs_deBoor_eval(double u, int k, nurbs_curve* curve, cart_point* Pt, cart_point* dPt, cart_point* ddPt, cart_point* dddPt);
    /* find length of each segment and whole curve using Gauss-Legendre integration */
void nurbs_length_GauLeg(nurbs_curve* curve);
double nurbs_GauLeg_custom_u_length(nurbs_curve* curve, double u);
void nurbs_scale_knots(nurbs_curve* curve);
double nurbs_arc_len(double u,void* data);
double gauss_legendre(double (*f)(double,void*), void* data, double a, double b);
double adaptiveSimpsons(double (*f)(double,void*), void* data,double a, double b,double epsilon,int maxRecursionDepth);
void nurbs_deBoor_eval(
		double u,			// parameter at which to evaluate curve
		int ek,				// externally given knot span (if -1 find it here)
		nurbs_curve* curve, // NURBS curve to be evaluated
		cart_point* Pt,		// evaluated point
		cart_point* dPt,	// evaluated point of 1st derivative
		cart_point* ddPt,	// evaluated point of 2nd derivative
		cart_point* dddPt	// evaluated point of 3rd derivative
		);

#endif
