#include"stdafx.h"
#include"ViewSpline.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


SplineLoop::SplineLoop(int pnts,Stuff::Scalar radius,Stuff::Point3D &pos)
{
	noc=pnts;
	Verify(noc>=2);
	int i;
	
	CtrlPoint.SetLength(noc);
	CtrlVector.SetLength(noc);
	
	Stuff::YawPitchRange pcd;
	
	pcd.range=radius;
	pcd.pitch=0;
	
	DefRadius=radius;
	DefCenter=pos;
	
	
	for(i=0,pcd.yaw=0.0f;i<noc;i++,pcd.yaw+=Stuff::Two_Pi/noc)
	{
		CtrlPoint[i].z=pcd.range*(Stuff::Scalar)cos(pcd.yaw);
		CtrlPoint[i].x=pcd.range*(Stuff::Scalar)sin(pcd.yaw);
		CtrlPoint[i].y=0.0f;
		CtrlPoint[i]+=pos;
		//Calulate Normals to the circle for inital Vectors
		CtrlVector[i].x=noc*pcd.range*(Stuff::Scalar)(cos(pcd.yaw));
		CtrlVector[i].y=0.0f;
		CtrlVector[i].z=noc*pcd.range*(Stuff::Scalar)(-sin(pcd.yaw));
	}
	
	
	XCurve.SetCurve(CtrlPoint[0].x,CtrlPoint[0].x,1.0f);
	YCurve.SetCurve(CtrlPoint[0].y,CtrlPoint[0].y,1.0f);
	ZCurve.SetCurve(CtrlPoint[0].z,CtrlPoint[0].z,1.0f);
	
	
	Stuff::Scalar sx,sy,sz;
	Stuff::Scalar sx2,sy2,sz2;
	for(i=0;i<noc;i++)
	{
		if(i!=0 && i!=(noc-1))
		{
			XCurve.InsertKey((Stuff::Scalar)i/noc);
			YCurve.InsertKey((Stuff::Scalar)i/noc);
			ZCurve.InsertKey((Stuff::Scalar)i/noc);
		}
		
		if(i!=(noc-1))
		{
			sx=CtrlVector[i].x;
			sy=CtrlVector[i].y;
			sz=CtrlVector[i].z;
			
			sx2=CtrlVector[i+1].x;
			sy2=CtrlVector[i+1].y;
			sz2=CtrlVector[i+1].z;
			XCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].x,CtrlVector[i].x,CtrlPoint[i+1].x,CtrlVector[i+1].x,1.0f/noc);
			YCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].y,CtrlVector[i].y,CtrlPoint[i+1].y,CtrlVector[i+1].y,1.0f/noc);
			ZCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].z,CtrlVector[i].z,CtrlPoint[i+1].z,CtrlVector[i+1].z,1.0f/noc);
		}
		else
		{
			XCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].x,CtrlVector[i].x,CtrlPoint[0].x,CtrlVector[0].x,1.0f/noc);
			YCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].y,CtrlVector[i].y,CtrlPoint[0].y,CtrlVector[0].y,1.0f/noc);
			ZCurve[i].SetHermiteKey(((Stuff::Scalar)i/noc),CtrlPoint[i].z,CtrlVector[i].z,CtrlPoint[0].z,CtrlVector[0].z,1.0f/noc);
		}
	}
	
}

void SplineLoop::ResetCurve(Stuff::Scalar radius,Stuff::Point3D &pos)
{
	int i;
	
	Stuff::YawPitchRange pcd;
	
	DefRadius=radius;
	DefCenter=pos;
	
	pcd.range=radius;
	pcd.pitch=0;
	
	
	for(i=0,pcd.yaw=0.0f;i<noc;i++,pcd.yaw+=Stuff::Two_Pi/noc)
	{
		CtrlPoint[i].z=pcd.range*(Stuff::Scalar)cos(pcd.yaw);
		CtrlPoint[i].x=pcd.range*(Stuff::Scalar)sin(pcd.yaw);
		CtrlPoint[i].y=0.0f;
		CtrlPoint[i]+=pos;
		//Calulate Normals to the circle for inital Vectors
		CtrlVector[i].x=noc*pcd.range*(Stuff::Scalar)(cos(pcd.yaw));
		CtrlVector[i].y=0.0f;
		CtrlVector[i].z=noc*pcd.range*(Stuff::Scalar)(-sin(pcd.yaw));
	}
	
	RebuildCurve();
	
}

void SplineLoop::GetCPoint(int pn,Stuff::Point3D  *cp,Stuff::Vector3D *cv)
{
	Verify(pn<noc);
	*cp=CtrlPoint[pn];
	*cv=CtrlVector[pn];
}


void SplineLoop::SetCPoint(int pn,Stuff::Point3D  &cp,Stuff::Vector3D &cv)
{
	Verify(pn<noc);
	CtrlPoint[pn]=cp;
	CtrlVector[pn]=cv;
	RebuildCurve(pn);
}

int SplineLoop::GetClosestCPoint(Stuff::Point3D &cp)
{
	int i,fp;
	Stuff::Scalar lv,tv;
	Stuff::Point3D tp;
	
	fp=0;
	tp.x=cp.x-CtrlPoint[0].x;
	tp.y=cp.y-CtrlPoint[0].y;
	tp.z=cp.z-CtrlPoint[0].z;
	lv=(Stuff::Scalar)sqrt(tp.x*tp.x+tp.y*tp.y+tp.z*tp.z);
	
	for(i=0;i<noc;i++)
	{
		tp.x=cp.x-CtrlPoint[i].x;
		tp.y=cp.y-CtrlPoint[i].y;
		tp.z=cp.z-CtrlPoint[i].z;
		tv=(Stuff::Scalar)sqrt(tp.x*tp.x+tp.y*tp.y+tp.z*tp.z);
		if(tv<lv) {lv=tv; fp=i;}
	}
	
	
	return fp;
}




void SplineLoop::Evaluate(Stuff::Scalar t,Stuff::Point3D *pnt,Stuff::Vector3D *vct)
{
	pnt->x=XCurve.ComputeValue(t);
	pnt->y=YCurve.ComputeValue(t);
	pnt->z=ZCurve.ComputeValue(t);
	
	vct->x=XCurve.ComputeSlope(t);
	vct->y=YCurve.ComputeSlope(t);
	vct->z=ZCurve.ComputeSlope(t);
}

SplineLoop::~SplineLoop()
{
} 

void SplineLoop::RebuildCurve(int crv)
{
	int i;
	Stuff::Scalar rhnoc=1.0f/noc;
	for(i=0;i<noc;i++)
	{
		
		if(i!=(noc-1))	
		{
			XCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].x,CtrlVector[i].x,CtrlPoint[i+1].x,CtrlVector[i+1].x,rhnoc);
			YCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].y,CtrlVector[i].y,CtrlPoint[i+1].y,CtrlVector[i+1].y,rhnoc);
			ZCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].z,CtrlVector[i].z,CtrlPoint[i+1].z,CtrlVector[i+1].z,rhnoc);
		}
		else
		{
			XCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].x,CtrlVector[i].x,CtrlPoint[0].x,CtrlVector[0].x,rhnoc);
			YCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].y,CtrlVector[i].y,CtrlPoint[0].y,CtrlVector[0].y,rhnoc);
			ZCurve[i].SetHermiteKey(((Stuff::Scalar)i*rhnoc),CtrlPoint[i].z,CtrlVector[i].z,CtrlPoint[0].z,CtrlVector[0].z,rhnoc);
		}
	}
	
}