/*===========================================================================
	Title: BSpline.h
	Module: Pi/MathLib
	Author: Ignacio Castaņo
	Date: 29/05/2000
	License: Public Domain
===========================================================================*/

#ifndef _PI_MATHLIB_BSPLINE_H_
#define _PI_MATHLIB_BSPLINE_H_

/*----------------------------------------------------------------------------
	Doc:
----------------------------------------------------------------------------*/

/** @file BSpline.h
 * @brief BSpline interpolation and aproximation. (NUNRBS)
 *
 * You can find some good notes about splines here:
 * http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/notes.html
**/


/*----------------------------------------------------------------------------
	Headers:
----------------------------------------------------------------------------*/

// Core
#include "Pi/Core/Containers.h"

// MathLib
#include "Pi/MathLib/MathLib.h"
#include "Pi/MathLib/Vector.h"


/*----------------------------------------------------------------------------
	Functions:
----------------------------------------------------------------------------*/

enum KnotPlacement {
	UNIFORM,
	CHORDLENGTH,
	CENTRIPETAL,
	UNIVERSAL,
	OPTIMAL
};

// Place knots.
//void SetKnots(const PiArray<Vec3> & point_array, KnotPlacement method, bool open, PiArray<float> & knot_array);



/*----------------------------------------------------------------------------
	Classes:
----------------------------------------------------------------------------*/

/** BSpline basis function. */
class BSplineBasis {
public:

	/** Ctor. */
	BSplineBasis() {
	}

	/** Ctor. */
	BSplineBasis(uint cpn, uint d, const float k[]) {
		Create(cpn, d, k);
	}


	// Create the basis function.
	MATHLIB_API void Create(uint cpn, uint d, const float k[] = NULL, bool loop = false);

	// Access knots.
	const float & Knot(uint i) const;
	
	// Access knots.
	float & Knot(uint i);

	// Locate the index for the given value.
	uint GetKey(float t);

	// Evaluate the basis for the given t, returns the indices of the first and last non-zero basis.
	MATHLIB_API void EvaluateBasis(float t, int * first, float N[]);

	uint GetDegree() const;

private:

	/// Degree of the curve. d
	uint16 degree;
	
	/// Number of control points. n = cpn-1
	uint16 cpoint_num;
	
	/// Array of control points. size = n+d+2
	PiArray<float> knot_array;

};



/** BSpline curve. */
class BSplineCurve {
public:
	
	/** Ctor. */
	BSplineCurve() {
	}

	/** Ctor. */
	BSplineCurve(uint cpn, uint d, const Vec3 cp[], const float * k = NULL) {
		Create(cpn, d, cp, k);
	}

	// Create the curve.
	MATHLIB_API void Create(uint cpn, uint d, const Vec3 cp[], const float * k = NULL);

	// Get number of control points.
	uint GetControlPointNum() const;
	
	// Access control points.
	const Vec3 & ControlPoint(uint i) const;
		
	// Access control points.
	Vec3 & ControlPoint(uint i);
	
	// Evaluate the curve.
	MATHLIB_API void Evaluate(float t, Vec3 * out);

	// Adjust the control points to aproximate the given set of points.
	MATHLIB_API void Aproximate(const PiArray<float> & time_array, const PiArray<Vec3> & point_array);

	// Create an interpolating bspline.
	MATHLIB_API void Interpolate(const PiArray<float> & time_array, const PiArray<Vec3> & point_array);
	
	
private:

	BSplineBasis basis;

	PiArray<Vec3> cpoint_array;
	
};


/*----------------------------------------------------------------------------
	Inlines:
----------------------------------------------------------------------------*/

/** Get the degree of the basis. */
inline uint BSplineBasis::GetDegree() const {
	return degree;
}

/** Access knots. */
inline const float & BSplineBasis::Knot(uint i) const {
	piDebugCheck(i < knot_array.Size());
	return knot_array[i];
}

/** Access knots. */
inline float & BSplineBasis::Knot(uint i) {
	piDebugCheck(i < knot_array.Size());
	return knot_array[i];
}


/** Get number of control points. */
inline uint BSplineCurve::GetControlPointNum() const {
	return cpoint_array.Size();
}

/** Access control points. */
inline const Vec3 & BSplineCurve::ControlPoint(uint i) const {
	piDebugCheck(i < cpoint_array.Size());
	return cpoint_array[i];
}

/** Access control points. */
inline Vec3 & BSplineCurve::ControlPoint(uint i) {
	piDebugCheck(i < cpoint_array.Size());
	return cpoint_array[i];
}





#endif // _PI_MATHLIB_BSPLINE_H_
