/****************************************************************************************

		ScrewConstraint.cpp

		Copyright (c)1990 - 1999 MetaCreations. All rights reserved.

		Author:	Guillaume Chermette
		Date:	11/10/99

		Revision History

		when		who			what & why
		==========	==========	======================================================

*****************************************************************************************/

#include "ScrewConstraint.h"


const MCGUID CLSID_ScrewConstraint(R_CLSID_ScrewConstraint);



//--------------------------------------------------------------
void Extension3DInit(IMCUnknown* utilities)
{
	// Perform your dll initialisation there
}


//--------------------------------------------------------------
void Extension3DCleanup()
{
	// Perform any nec clean-up here
}


//--------------------------------------------------------------
TBasicUnknown* MakeCOMObject(const MCCLSID& classId)	// This method instanciate
{														// the object Camera
	TBasicUnknown* res = NULL;

	if (classId == CLSID_ScrewConstraint) res = new ScrewConstraint;

	return res;
}


// Constructor
//--------------------------------------------------------------
ScrewConstraint::ScrewConstraint()
{
	// Data initialisation :
	fData.fAxis			= kRadioZ_id;
	fData.fStep			= 1.0;
	fData.fFreedomValue = 0.0;
}


//--------------------------------------------------------------
void* ScrewConstraint::GetExtensionDataBuffer()
{
	return &fData; // The Shell uses this pointer to set the values of the camera's parameters
}
  

//--------------------------------------------------------------
MCCOMErr ScrewConstraint::ExtensionDataChanged()
{
	return MC_S_OK;
}


//--------------------------------------------------------------
int16 ScrewConstraint::GetResID()
{
	return 141; // This is the view ID in the resource file
}


//--------------------------------------------------------------
int16 ScrewConstraint::GetNbrFreedom() const
{
	return 1;
}


//--------------------------------------------------------------
MCCOMErr ScrewConstraint::IncrementFreedomValue(int16 index, real& increment)
{
	if (index == 1)
		fData.fFreedomValue += increment;

	return MC_S_OK;
}


//--------------------------------------------------------------
MCCOMErr ScrewConstraint::GetMotionLimit(int16 index, ELimitType& limit) const
{
	if (index != 1)
		return MC_E_NOTIMPL;
	else
		limit = eFree;

	return MC_S_OK;
}


//--------------------------------------------------------------
MCCOMErr ScrewConstraint::GetFreedomRange(int16 index, real& min, real& max) const
{
	if (index == 1)
	{
		min = -32767.0f;
		max =  32767.0f;
	}
	return MC_S_OK;
}


//--------------------------------------------------------------
MCCOMErr ScrewConstraint::GetTransform(TTransform3D& transform) const
{
	int16		u,v,w;
	real		alpha,cosa,sina;
	real		altitude;
	TMatrix33	m33;

	altitude = fData.fFreedomValue * fData.fStep;
	alpha = fData.fFreedomValue * kRealTwoPI;

	if (fData.fAxis == kRadioX_id)
	{
		u=1;
		v=2;
		w=0;
	}
	else if (fData.fAxis == kRadioY_id)
	{
		u=2;
		v=0;
		w=1;
	}
	else if (fData.fAxis == kRadioZ_id)
	{
		u=0;
		v=1;
		w=2;
	} 

	transform.fTranslation[u] = 0.0;
	transform.fTranslation[v] = 0.0;
	transform.fTranslation[w] = altitude;
	sina = RealSin(alpha);
	cosa = RealCos(alpha); //QuickSinCos(alpha,sina,cosa);
	m33[u][u] = cosa; m33[u][v] = sina; m33[u][w]=0.0;
	m33[v][u] = -sina; m33[v][v] = cosa; m33[v][w] = 0.0;
	m33[w][u] = 0.0; m33[w][v] = 0.0; m33[w][w] = 1.0;
	transform.fRotationAndScale = m33;
                        
	return MC_S_OK;
}


//--------------------------------------------------------------
MCCOMErr ScrewConstraint::GetTransformPartialDerivate(int16 index, TTransform3D& transform) const
{
	int16 u,v,w;
	real32 alpha,cosa,sina;
	TMatrix33 m33;
	if (fData.fAxis == kRadioX_id)
	{
		u = 1;
		v = 2;
		w = 0;
	}
	else if (fData.fAxis == kRadioY_id)
	{
		u = 2;
		v = 0;
		w = 1;
	}
	else if (fData.fAxis == kRadioZ_id)
	{
		u = 0;
		v = 1;
		w = 2;
	} 
	if (index == 1) 
	{
		transform.fTranslation[u] = 0.0;
		transform.fTranslation[v] = 0.0;
		transform.fTranslation[w] = fData.fStep;
		alpha = kRealTwoPI * fData.fFreedomValue;
		sina  = RealSin(alpha);
		cosa  = RealCos(alpha); //QuickSinCos(alpha,sina,cosa);
		m33[u][u] = -kRealTwoPI * sina;
		m33[u][v] = kRealTwoPI * cosa;
		m33[u][w] = 0.0;
		m33[v][u] = -kRealTwoPI * cosa;
		m33[v][v] = -kRealTwoPI * sina;
		m33[v][w] = 0.0;
		m33[w][u] = 0.0;
		m33[w][v] = 0.0;
		m33[w][w] = 0.0;
		transform.fRotationAndScale = m33;
	}
	return MC_S_OK;
}