/****************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
****************************************************************************/

#pragma once

#include "glmCoreAPI.h"
#include "glmArray.h"
#include "glmVector3.h"

namespace glm 
{ 
	class GLM_CORE_API NURBS
	{
	public:	//methods
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

		NURBS();
		NURBS(const Array<Vector3>& controlPoints, const Array<float>& knots, unsigned int degree);
		NURBS(const Array<Vector3>& controlPoints, unsigned int degree);
		~NURBS();

		bool isValid() const;

		Vector3 pointAt(float abscissa) const;
		Vector3 pointAtDistanceOnCurve(float dist) const;
		Vector3 tangentAt(float u) const;

		Vector3 computeProjectionOnCurve(const Vector3& point, float& returnAbscissa) const;

		float abscissaToDistanceOnCurve(float abscissa) const;
		float distanceOnCurveToAbscissa(float distanceOnCurve) const;

		inline unsigned int getDegree() const { return _degree; }
		inline const Array<float>& getKnots() const { return _knots; }
		inline const Array<float>& getKnotsDistanceOnCurve() const;
		inline const Array<Vector3>& getControlPoints() const { return _controlPoints; }
		inline const Array<float>& getWeights() const { return _weights; }

		int findSpan(float u) const;
		Array<Vector3> curveDerivatives(int num_ders, float u) const;
		Array<float> bsplineBasis(int span, float u) const;
		Array<Array<float>> bsplineDerBasis(int span, float u, int num_ders) const;

		Array<float> computeDistanceApproximations_adaptiveSampling(float minAbscissaSampling = 0.1f, float maxAbscissaSampling = 10.f) const;

	private:	//data
		unsigned int _degree;
		Array<float> _knots;
		mutable Array<float> _knotsRealDistance;	//computed when used only...
		Array<Vector3> _controlPoints;
		Array<float> _weights;
	} ;

	//-----------------------------------------------------------------------------
	inline const Array<float>& NURBS::getKnotsDistanceOnCurve() const
	{
		if (_knotsRealDistance.size() != _knots.size())
			computeDistanceApproximations_adaptiveSampling();
		return _knotsRealDistance;
	}

}

