/*
///////////////////////////////////////////////////////////////////////////////////////////////////
// Description : LinkObj.cpp
//   
//  Definition of the link editors objects            
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// inherit from  :	CPA_Object
//					CPA_EdMot<ACP_tdxHandleOfLink>
///////////////////////////////////////////////////////////////////////////////////////////////////
// Creation date: 21 jan 1997                        Author: J Thénoz
///////////////////////////////////////////////////////////////////////////////////////////////////
// Modification date:			                      Author: 
// 
//
// 
//
///////////////////////////////////////////////////////////////////////////////////////////////////
*/

//ANNECY Shaitan Nettoyage (12/05/98) {
/*
#include "stdafx.h"
#include "acp_base.h"
#include "resource.h"
#include "incitf.h"
#include "incgam.h"
#include "incai.h"
#include "LinkMod.hpp"
#include "LinkDia.hpp"
#include "RotDia.hpp"
#include "incgli.h"
#include "WPObj.hpp"
#include "WayObj.hpp"
#include "LinkObj.hpp"
#include "Link2D.hpp"
#include "Inter.hpp"
#include "TanObj.hpp"

#include "LinkLine.hpp"
#include "LinkBez.hpp"
#include "LinkArc.hpp"

#include "LinkObj.hpp"



DeclareTemplateStatic(WP_tdhLink); 


//---- static
Waypoint_Interface*	Link::ms_poInterface;			// Interface
DiaLink* Link::ms_poDiaLink;						// Dialog 
RotationDia* Link::ms_poRotationDia;				// Rotation Dialog
CPA_List<tdst_LinkObject> Link::ms_oListLinkObject; // List of the present links
long Link::ms_lNbLink=0;


void Link::fn_vInitObject (Waypoint_Interface* poInterface)
{
	CPA_EdMot<WP_tdhLink>::Init (WP_fnh_Link_Create, WP_fnv_Link_Copy, WP_fnv_Link_Destroy);
	LinkLine::fn_vRegisterObject();
	LinkBez::fn_vRegisterObject();
	LinkArc::fn_vRegisterObject();
	ms_poInterface = poInterface;
}


void Link::fn_vSetDialog ( DiaLink* poDiaLink, RotationDia* poRotationDia )
{
	ms_poDiaLink=poDiaLink;
	ms_poDiaLink->fn_vInitDialog ();
	ms_poRotationDia=poRotationDia;
	ms_poRotationDia->fn_vInitDialog ();
}


Link* Link::fn_pCreateLink ( Way* poWay, char cType, WayPoint* poFirstWP, WayPoint* poSecondWP, WP_tdhLink hLink )
{
	CPA_SuperObject* poSuperLink = ms_poInterface->GetInterface()->GetNewSuperObject ( E_ss_NoSave, C_NoType );
	poSuperLink->SetTypeSO (C_Protected);
	Link* poLink;
	
	POSITION xPos;
	tdst_LinkObject* pst_LinkObject;

	if (hLink)
		cType = (char) WP_fneuc_Link_GetConnectionType (hLink);

	// important loop that call the right constructor
	for ( pst_LinkObject=ms_oListLinkObject.GetHeadElement (xPos); pst_LinkObject; pst_LinkObject=ms_oListLinkObject.GetNextElement (xPos) ) 
		if (pst_LinkObject->cType==cType)
			poLink = pst_LinkObject->fn_pConstruct ( poWay->GetInterface(), poWay, hLink );

	poLink->fn_vSetDraw (TRUE);
	poSuperLink->SetObject(poLink);
	poLink->SetSuperObject(poSuperLink);

	//---- set dynamics parameters
	if (!hLink)
	{
		ACP_tdstDynaParam stDynParam;
		WP_fnv_Link_GetDynamicParameter ( (WP_tdhLink)(poLink->GetEngineStruct()), &stDynParam );
		fn_vDynamicObject_ChangeParams(	&stDynParam, C_ucNone, 0., 0., 0.);
		WP_fnv_Link_SetDynamicParameter ( (WP_tdhLink)(poLink->GetEngineStruct()), &stDynParam );
	}
	
	//---- create the graphic object
	poLink->fn_vConstructGraphic ();
	poLink->fn_vSetWaypoints ( poFirstWP, poSecondWP );
	return poLink;
}

Link* Link::fn_pCreateLink ( Way* poWay, WP_tdhLink hLink, WayPoint* poFirstWP, WayPoint* poSecondWP )
{
	Link* poLink;
	char cType;
	cType =  (char) WP_fneuc_Link_GetConnectionType (hLink);
	poLink = fn_pCreateLink ( poWay, cType, poFirstWP, poSecondWP, hLink );
	poLink->fn_vSetDrawOutHierarchy (TRUE);
	poLink->fn_vInitEditorFromEngine ();
	return poLink;
}

Link* Link::CloneLink ( Way* poWay, Link* poLink, CString& szNewLinkName )
{
	char cNewType = WP_ConnType_ucInvalid;
	POSITION xPos;
	tdst_LinkObject* pst_LinkObject;
	WayPoint *poFirstWP, *poSecondWP;

	// search the type of the new link
	for ( pst_LinkObject=ms_oListLinkObject.GetHeadElement (xPos); pst_LinkObject; pst_LinkObject=ms_oListLinkObject.GetNextElement (xPos) ) 
		if (!strcmp (pst_LinkObject->szName, szNewLinkName)) cNewType = pst_LinkObject->cType;
	if (cNewType == WP_ConnType_ucInvalid) return NULL;

	// Set waypoints
	poLink->fn_vGetWaypoints ( &poFirstWP, &poSecondWP );

	// Set dynamic parameters
	ACP_tdstDynaParam stDynParam;						// dynamic param
	WP_tde_ucConnectionDynamicType eConnectionType;		// type

	WP_fnv_Link_GetDynamicParameter ( (WP_tdhLink)(poLink->GetEngineStruct()), &stDynParam );
	eConnectionType = WP_fneuc_Link_GetConnectionDynamicType ( (WP_tdhLink)(poLink->GetEngineStruct()) );
	
	Link* poNewLink = fn_pCreateLink ( poWay, cNewType, poFirstWP, poSecondWP );
	
	WP_fnv_Link_SetDynamicParameter ( (WP_tdhLink)(poNewLink->GetEngineStruct()), &stDynParam );
	WP_fnv_Link_SetConnectionDynamicType ( (WP_tdhLink)(poNewLink->GetEngineStruct()), eConnectionType );

	return poNewLink;
}

Link::Link( CPA_ObjectDLLBase *p_oDLL, CPA_BaseObject *p_oOwner, WP_tdhLink hLink ):
	CPA_BaseObject ( p_oDLL, "Link" ),
	CPA_EdMot<WP_tdhLink>(hLink)
{
	m_poParent = (Way*)p_oOwner;
	m_bAddInHierarchy=FALSE;
	m_bRemoveInHierarchy=FALSE;
	m_bDraw=FALSE;
	m_bCanDrawOutHierarchy=FALSE;
	m_bRotationMode=FALSE;
	m_bFirstEdition=TRUE;
	m_xOrientationTangentLenght=0.5f;
	m_bXDirectOrientation=TRUE;
	m_bYDirectOrientation=TRUE;
	m_bZDirectOrientation=TRUE;
	m_lNbLapXOrientation=0L;
	m_lNbLapYOrientation=0L;
	m_lNbLapZOrientation=0L;
	m_xFirstTwistOrientation=0.;
	m_xSecondTwistOrientation=0.;

	// name
	CString csName;
	csName.Format ("Link%d", ms_lNbLink);
	ms_lNbLink++;
	fn_eRename (csName);

	//--- init dyn params
	WP_fnv_Link_SetConnectionDynamicType ( GetStruct(), WP_ConDynType_ucNone );

	//--- orientation tangent
	GEO_tdstColor stColor;
	stColor.xR = 0.f;
	stColor.xG = 0.f;
	stColor.xB = 0.8f;
	m_poFirstOrientationTangent = new Tangent ( p_oDLL, this, eFixLenghtTangent, eVariableOrientationTangent, eControlDownChangeNeighbour, eShiftDownChangeAll, &stColor );
	
	stColor.xR = 0.8f;
	stColor.xG = 0.8f;
	stColor.xB = 0.f;
	m_poSecondOrientationTangent = new Tangent ( p_oDLL, this, eFixLenghtTangent, eVariableOrientationTangent,eControlDownChangeNeighbour, eShiftDownChangeAll, &stColor );
}


Link::Link( CPA_ObjectDLLBase *p_oDLL, CPA_BaseObject *p_oOwner ):
	CPA_BaseObject ( p_oDLL, "Link" ),
	CPA_EdMot<WP_tdhLink>()
{
	WP_fnv_Link_SetConnectionType ( (WP_tdhLink)GetStruct(), WP_ConnType_ucInvalid);	
	
	m_poParent = (Way*)p_oOwner;
	m_bAddInHierarchy=FALSE;
	m_bRemoveInHierarchy=FALSE;
	m_bDraw=FALSE;
	m_bCanDrawOutHierarchy=FALSE;
	m_bRotationMode=FALSE;
	m_bFirstEdition=TRUE;
	m_xOrientationTangentLenght=0.5f;
	m_bXDirectOrientation=TRUE;
	m_bYDirectOrientation=TRUE;
	m_bZDirectOrientation=TRUE;
	m_lNbLapXOrientation=0L;
	m_lNbLapYOrientation=0L;
	m_lNbLapZOrientation=0L;
	m_xFirstTwistOrientation=0.;
	m_xSecondTwistOrientation=0.;


	// name
	CString csName;
	csName.Format ("Link%d", ms_lNbLink);
	ms_lNbLink++;
	fn_eRename (csName);

	//--- init dyn params
	WP_fnv_Link_SetConnectionDynamicType ( GetStruct(), WP_ConDynType_ucNone );
	fn_vWayNotifySave ();

	//--- orientation tangent
	GEO_tdstColor stColor;
	stColor.xR = 0.f;
	stColor.xG = 0.f;
	stColor.xB = 0.8f;
	m_poFirstOrientationTangent = new Tangent ( p_oDLL, this, eFixLenghtTangent, eVariableOrientationTangent, eControlDownChangeNeighbour, eShiftDownChangeAll, &stColor );
	
	stColor.xR = 0.8f;
	stColor.xG = 0.8f;
	stColor.xB = 0.f;
	m_poSecondOrientationTangent = new Tangent ( p_oDLL, this, eFixLenghtTangent, eVariableOrientationTangent,eControlDownChangeNeighbour, eShiftDownChangeAll, &stColor );
}


//-------------------------------------------------------------------
// Data
//-------------------------------------------------------------------
long Link::GetDataType (void)
{
	return C_ucLink;
}

void* Link::GetData (void)
{
	return GetStruct();
}


SCRIPT_tdeReturnValue Link::CallBackLoad (FILE *p_fFile, char *szAction, char *szParams[], SCRIPT_tdeAction cType)
{
	return R_SCRIPT_NormalReturn;
}

void Link::fn_vSplitLink ( Way* poWay, WayPoint* poWP, Link** pLinkBefore, Link** pLinkAfter )
{
	// create and set the extrems WP
	*pLinkBefore = (Link*)(poWay->fn_pCreateLink(WP_ConnType_ucStaticLine)->GetObject());
	*pLinkAfter = (Link*)(poWay->fn_pCreateLink(WP_ConnType_ucStaticLine)->GetObject());
	(*pLinkBefore)->fn_vSetWaypoints ( m_poFirstWP, poWP ); 
	(*pLinkAfter)->fn_vSetWaypoints ( poWP, m_poSecondWP );
}

Link* Link::fn_pMergeLink ( Way* poWay, Link* pLink )
{
	if (!pLink) return NULL;
	Link* pMergeLink = (Link*)(poWay->fn_pCreateLink(WP_ConnType_ucStaticLine)->GetObject());

	// set the extrems WP	
	WayPoint *oFirstWP, *oSecondWP, *oBufferWP;
	fn_vGetWaypoints ( &oFirstWP, &oBufferWP );	
	pLink->fn_vGetWaypoints ( &oBufferWP, &oSecondWP );	
	pMergeLink->fn_vSetWaypoints ( oFirstWP, oSecondWP );
	return pMergeLink;
}


//-------- Set
void Link::fn_vSetType ( WP_tde_ucConnectionType cType )
{
	WP_fnv_Link_SetConnectionType ( ((WP_tdhLink)GetEngineStruct()), cType );
}

//-------- Get
char Link::fn_cGetType ( void )
{
	return WP_fneuc_Link_GetConnectionType ( ((WP_tdhLink)GetEngineStruct()) );
}

void Link::fn_vSave ( SCR_tdst_File_Description *_p_stFile )
{
	ACP_tdstDynaParam stDynParam;
	unsigned char ucDynamicType;
	float fSpeed1, fSpeed2, fSpeed3; 
	long lNbParam=0;
	char* dszParam [20];
	char a20_20_szParam [20][20];

	fn_vGetSaveInfo ( a20_20_szParam, lNbParam );
	
	// dynamic conection type
	switch ( WP_fneuc_Link_GetConnectionDynamicType (GetStruct()) )
	{
		case WP_ConDynType_ucNone : strcpy ( a20_20_szParam[1],		"None"); break;
		case WP_ConDynType_ucConstant : strcpy ( a20_20_szParam[1], "Constant"); break;
		case WP_ConDynType_ucLinear : strcpy ( a20_20_szParam[1],	"Linear"); break;
		case WP_ConDynType_ucSinus : strcpy ( a20_20_szParam[1],	"Sinus"); break;
		default : dszParam[1][0]=0; break;
	}

	// dynamic param
	WP_tdhLink hLink = (WP_tdhLink)GetEngineStruct();
	WP_fnv_Link_GetDynamicParameter(hLink,&stDynParam);

	fn_vDynamicObject_GetParams( &stDynParam, &ucDynamicType, &fSpeed1, &fSpeed2, &fSpeed3);

	switch ( ucDynamicType )
	{
	case C_ucConst : 
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed1 );
		break;
	case C_ucLinear :
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed1 );
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed2 );
		break;
	case C_ucSinus : 
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed1 );
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed2 );
		sprintf ( a20_20_szParam[lNbParam++], "%g", fSpeed3 );
		break;
	}

	// save rotation parameters
	MTH3D_tdstVector stFirstOrientationVector, stSecondOrientationVector;
	fn_vDynamicObject_GetRotation( &stDynParam, &stFirstOrientationVector, &stSecondOrientationVector );

	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetXofVector(&stFirstOrientationVector) );
	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetYofVector(&stFirstOrientationVector) );
	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetZofVector(&stFirstOrientationVector) );
	
	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetXofVector(&stSecondOrientationVector) );
	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetYofVector(&stSecondOrientationVector) );
	sprintf ( a20_20_szParam[lNbParam++], "%g", MTH3D_M_xGetZofVector(&stSecondOrientationVector) );

	// write entry
	for ( long lCounter = 0; lCounter<20; lCounter++ ) dszParam[lCounter]=a20_20_szParam[lCounter];

	SCR_M_SvL0_SaveEntry( _p_stFile, "Link", SCR_CC_C_Cfg_NoChar );
	SCR_fn_v_SvL0_SaveParameters_AP( _p_stFile, SCR_EF_SvL0_Normal, lNbParam, dszParam);
}


Waypoint_Interface* Link::GetInterface (void)
{
	return ms_poInterface; 
}
	
void Link::fn_vWayNotifySave (void)
{
	m_poParent->fn_vNotifySave ();
}

void Link::fn_vEdit (void)
{
	int iPos = m_poParent->fn_iIsWayPointInNet (m_poFirstWP,m_poSecondWP);
	GetInterface()->fn_vEdit ( m_poParent, iPos>0 ? iPos : 0 );
}

void Link::fn_vSelectWay (void)
{
	GetInterface()->GetInterface()->fn_vAddSelectedObject ( m_poParent->GetSuperObject(), FALSE);
	m_poParent->fn_vSelectAllWP ();
}

void Link::fn_vConstructGraphic (void)
{
	m_poFirstOrientationTangent->GetSuperObject()->SetSuperObjectOwner (GetSuperObject());	
	m_poSecondOrientationTangent->GetSuperObject()->SetSuperObjectOwner (GetSuperObject());	
}

void Link::fn_vInitGraphic (void)
{
	if (!m_bFirstEdition) return;
	m_bFirstEdition = FALSE;

	fn_vComputeAxis ();

	MTH3D_tdstVector stFirstFixVertex, stSecondFixVertex;
	MTH3D_tdstVector stFirstMoveVertex, stSecondMoveVertex;

	WP_fnv_WayPoint_ComputeLocation (  (WP_tdhWayPoint)(m_poFirstWP->GetEngineStruct()), &stFirstFixVertex );
	WP_fnv_WayPoint_ComputeLocation (  (WP_tdhWayPoint)(m_poSecondWP->GetEngineStruct()), &stSecondFixVertex );

	// init orientation parameters
	MTH3D_tdstVector u;
	

	ACP_tdstDynaParam stDynaParam;
	MTH3D_tdstVector stFirstEngineOrientationVector, stSecondEngineOrientationVector;
	MTH3D_tdstVector stFirstEditorOrientationVector, stSecondEditorOrientationVector;
	MTH_tdxReal stFirstXRot, stFirstYRot, stFirstZRot;
	MTH_tdxReal stSecondXRot, stSecondYRot, stSecondZRot;

	stFirstXRot = MTH_C_ZERO;
	stFirstYRot = MTH_C_ZERO;
	stFirstZRot = MTH_C_ZERO;
	stSecondXRot = MTH_C_ZERO;
	stSecondYRot = MTH_C_ZERO;
	stSecondZRot = MTH_C_ZERO;

	WP_tdhLink hLink = (WP_tdhLink)GetEngineStruct();
	WP_fnv_Link_GetDynamicParameter (hLink,&stDynaParam);
	fn_vDynamicObject_GetRotation( &stDynaParam, &stFirstEngineOrientationVector, &stSecondEngineOrientationVector );

	
	u =stSecondFixVertex;
	MTH3D_M_vSubVector( &u, &u, &stFirstFixVertex );
	
	MTH3D_M_vNormalizeVector(&u,&u);
	MTH3D_M_vMulScalarVector(&u,m_xOrientationTangentLenght,&u);
	stFirstMoveVertex = stFirstFixVertex;
	stSecondMoveVertex = stSecondFixVertex;
	
	if (MTH3D_M_xNormVector(&stFirstEngineOrientationVector)>=1e-10)  
	{
		MTH3D_M_vGetVectorElements ( &stFirstXRot, &stFirstYRot, &stFirstZRot, &stFirstEngineOrientationVector );
		fn_vRotation2Vertex ( &stFirstEditorOrientationVector, &m_xFirstTwistOrientation, &stFirstXRot, &stFirstYRot, &stFirstZRot );

		MTH3D_M_vNormalizeVector(&stFirstEditorOrientationVector,&stFirstEditorOrientationVector);
		MTH3D_M_vMulScalarVector(&stFirstEditorOrientationVector,m_xOrientationTangentLenght,&stFirstEditorOrientationVector);
	}	
	else stFirstEditorOrientationVector = u;

	MTH3D_M_vAddVector(&stFirstMoveVertex,&stFirstMoveVertex,&stFirstEditorOrientationVector);    
	

	if (MTH3D_M_xNormVector(&stSecondEngineOrientationVector)>=1e-10)  
	{
		MTH3D_M_vGetVectorElements ( &stSecondXRot, &stSecondYRot, &stSecondZRot, &stSecondEngineOrientationVector );
		
		fn_vRotation2Vertex ( &stSecondEditorOrientationVector, &m_xSecondTwistOrientation, &stSecondXRot, &stSecondYRot, &stSecondZRot );

		MTH3D_M_vNormalizeVector(&stSecondEditorOrientationVector,&stSecondEditorOrientationVector);
		MTH3D_M_vMulScalarVector(&stSecondEditorOrientationVector,m_xOrientationTangentLenght,&stSecondEditorOrientationVector);
	}
	else stSecondEditorOrientationVector = u;    
	
	MTH3D_M_vAddVector(&stSecondMoveVertex,&stSecondMoveVertex,&stSecondEditorOrientationVector);

	fn_vExtractModulusRotation ( &m_bXDirectOrientation, &m_lNbLapXOrientation, stFirstXRot, stSecondXRot );
	fn_vExtractModulusRotation ( &m_bYDirectOrientation, &m_lNbLapYOrientation, stFirstYRot, stSecondYRot );
	fn_vExtractModulusRotation ( &m_bZDirectOrientation, &m_lNbLapZOrientation, stFirstZRot, stSecondZRot );

	// matrix compute
	Link::fn_vRotationGraphic (TRUE);
	m_poFirstOrientationTangent->fn_vSetAbsoluteVertex ( &stFirstFixVertex, &stFirstMoveVertex );
	m_poSecondOrientationTangent->fn_vSetAbsoluteVertex ( &stSecondFixVertex, &stSecondMoveVertex );
	Link::fn_vRotationGraphic (FALSE);
}

void Link::fn_vRotationGraphic (BOOL bRotation)
{
	if (m_bRotationMode==bRotation) return;
	m_bRotationMode=bRotation;

	if (bRotation)
	{
		// hierarchy	
		GetInterface()->GetInterface()->fn_bInsertObjectInHierarchy (m_poFirstOrientationTangent->GetSuperObject(), GetSuperObject(),FALSE,FALSE,FALSE);
		GetInterface()->GetInterface()->fn_bInsertObjectInHierarchy (m_poSecondOrientationTangent->GetSuperObject(), GetSuperObject(),FALSE,FALSE,FALSE);
	
		// dialog
		if (ms_poDiaLink->fn_bIsEditLink(this)) ms_poDiaLink->fn_vEdit (NULL);
	}
	else
	{
		// hierarchy	
		GetInterface()->GetInterface()->fn_bDeleteObjectInHierarchy (m_poFirstOrientationTangent->GetSuperObject(), FALSE, FALSE, FALSE, FALSE );
		GetInterface()->GetInterface()->fn_bDeleteObjectInHierarchy (m_poSecondOrientationTangent->GetSuperObject(), FALSE, FALSE, FALSE, FALSE );
	
		// dialog
		if (ms_poRotationDia->fn_bIsEditLink(this)) ms_poRotationDia->fn_vEdit (NULL);
	}
}

void Link::fn_vDraw (void)
{
	if (m_bRotationMode)
	{
		fn_vComputeAxis();
		m_poFirstOrientationTangent->fn_vDraw ();
		m_poSecondOrientationTangent->fn_vDraw ();
		fn_vDrawRotation ();
		fn_vRefreshEngineOrientation();
	}
	else 
	{
		fn_vComputeAxis();
		fn_vDrawNormal ();
	}
}

void Link::fn_vComputeAxis (void)
{
	MTH3D_tdstVector stFirstVertex, stSecondVertex;
	MTH3D_tdstVector stVectorU, stVectorV, stVectorN;
	MTH3D_tdstVector n, u, v;

	WP_fnv_WayPoint_ComputeLocation ( (WP_tdhWayPoint)(m_poFirstWP->GetEngineStruct()), &stFirstVertex );
	WP_fnv_WayPoint_ComputeLocation ( (WP_tdhWayPoint)(m_poSecondWP->GetEngineStruct()), &stSecondVertex );

	n = stSecondVertex;
	MTH3D_M_vSubVector(&n,&n,&stFirstVertex);
	GLI_tdxValue lenght = MTH3D_M_xNormVector( &n );

	MTH3D_M_vNormalizeVector(&n,&n);
	if (n.xX||n.xY) { MTH3D_M_vSetVectorElements ((&u),(-n.xY),(n.xX),0.); }
	else { MTH3D_M_vSetVectorElements((&u),0.,(-n.xZ),n.xY); } 
	MTH3D_M_vNormalizeVector(&u,&u);
	MTH3D_M_vCrossProductVector((&v),(&n),(&u));
	MTH3D_M_vNormalizeVector(&v,&v);


	// change the local matrix
	GetInterface()->fn_vComputeAbsoluteMatrix (GetSuperObject());
	GEO_tdxHandleToMatrix hAbsoluteLineMatrix = HIE_fn_hGetSuperObjectGlobalMatrix (GetSuperObject()->GetStruct());
	POS_fn_vSetIdentityMatrix( hAbsoluteLineMatrix );
	POS_fn_vSetTranslationVector(  hAbsoluteLineMatrix, &stFirstVertex );
	POS_fn_vSetRotationMatrix( hAbsoluteLineMatrix , &n, &u, &v );

	POS_fn_vGetScaleMatrix( hAbsoluteLineMatrix, &stVectorN, &stVectorU, &stVectorV );
	MTH3D_M_vMulScalarVector( &stVectorN, lenght, &stVectorN);
	POS_fn_vSetScaleMatrix( hAbsoluteLineMatrix, &stVectorN, &stVectorU, &stVectorV );
	POS_fn_vNormalizeMatrix( hAbsoluteLineMatrix ) ;
	GetInterface()->fn_vComputeNewRelativeMatrix (GetSuperObject()->GetStruct());
}


void Link::fn_vSetXDirectOrientation ( BOOL bXDirectOrientation )
{
	m_bXDirectOrientation = bXDirectOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetYDirectOrientation ( BOOL bYDirectOrientation )
{
	m_bYDirectOrientation = bYDirectOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetZDirectOrientation ( BOOL bZDirectOrientation )
{
	m_bZDirectOrientation = bZDirectOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetNbLapXOrientation ( long lNbLapXOrientation )
{
	m_lNbLapXOrientation = lNbLapXOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetNbLapYOrientation ( long lNbLapYOrientation )
{
	m_lNbLapYOrientation = lNbLapYOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetNbLapZOrientation ( long lNbLapZOrientation )
{
	m_lNbLapZOrientation = lNbLapZOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetFirstTwistOrientation ( MTH_tdxReal xFirstTwistOrientation )
{
	m_xFirstTwistOrientation = xFirstTwistOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vSetSecondTwistOrientation ( MTH_tdxReal xSecondTwistOrientation )
{
	m_xSecondTwistOrientation = xSecondTwistOrientation;
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vRefreshEngineOrientation (void)
{
	ACP_tdstDynaParam stDynaParam;
	MTH3D_tdstVector stFirstEngineOrientationVector, stSecondEngineOrientationVector;
	MTH3D_tdstVector stFirstAbsoluteOrientationVector, stSecondAbsoluteOrientationVector;
	WP_tdhLink hLink = (WP_tdhLink)GetEngineStruct();

	m_poFirstOrientationTangent->fn_pGetAbsoluteTangent (&stFirstAbsoluteOrientationVector);
	m_poSecondOrientationTangent->fn_pGetAbsoluteTangent (&stSecondAbsoluteOrientationVector);

	MTH_tdxReal xXStartRot, xYStartRot, xZStartRot;
	MTH_tdxReal xXEndRot, xYEndRot, xZEndRot;
	
	fn_vVertex2Rotation ( &xXStartRot, &xYStartRot, &xZStartRot, &stFirstAbsoluteOrientationVector, &m_xFirstTwistOrientation );
	fn_vVertex2Rotation ( &xXEndRot, &xYEndRot, &xZEndRot, &stSecondAbsoluteOrientationVector, &m_xSecondTwistOrientation );
	fn_vComputeModulusRotation ( &xXStartRot, &xXEndRot, m_bXDirectOrientation, m_lNbLapXOrientation );
	fn_vComputeModulusRotation ( &xYStartRot, &xYEndRot, m_bYDirectOrientation, m_lNbLapYOrientation );
	fn_vComputeModulusRotation ( &xZStartRot, &xZEndRot, m_bZDirectOrientation, m_lNbLapZOrientation );

	MTH3D_M_vSetVectorElements ( &stFirstEngineOrientationVector, xXStartRot, xYStartRot, xZStartRot );
	MTH3D_M_vSetVectorElements ( &stSecondEngineOrientationVector, xXEndRot, xYEndRot, xZEndRot );

	WP_fnv_Link_GetDynamicParameter (hLink,&stDynaParam);
	fn_vDynamicObject_SetRotation( &stDynaParam, &stFirstEngineOrientationVector, &stSecondEngineOrientationVector );
	WP_fnv_Link_SetDynamicParameter (hLink,&stDynaParam);

	fn_vWayNotifySave();
}

void Link::fn_vChangeNeighbourTangent (Tangent* pTangent)
{
	Link* pChangeLink;
	if (m_poFirstOrientationTangent==pTangent)
	{
		pChangeLink = m_poParent->fn_pPrevLink (this);
		if (pChangeLink) 
		{
			MTH3D_tdstVector stTangent;
			pTangent->fn_pGetAbsoluteTangent(&stTangent);
			pChangeLink->fn_vSetOrientationTangent ( 2, &stTangent );   
			pChangeLink->fn_vDraw ();
		}
	}
	else
	{
		pChangeLink = m_poParent->fn_pNextLink (this);
		if (pChangeLink) 
		{
			MTH3D_tdstVector stTangent;
			pTangent->fn_pGetAbsoluteTangent(&stTangent);
			pChangeLink->fn_vSetOrientationTangent ( 1, &stTangent );   
			pChangeLink->fn_vDraw ();
		}
	}
}

void Link::fn_vReinitOrientationTangent (Tangent* poTangent)
{
	MTH3D_tdstVector stFirstFixVertex, stSecondFixVertex;

	WP_fnv_WayPoint_ComputeLocation (  (WP_tdhWayPoint)(m_poFirstWP->GetEngineStruct()), &stFirstFixVertex );
	WP_fnv_WayPoint_ComputeLocation (  (WP_tdhWayPoint)(m_poSecondWP->GetEngineStruct()), &stSecondFixVertex );

	MTH3D_tdstVector u;
	u =stSecondFixVertex;
	MTH3D_M_vSubVector( &u, &u, &stFirstFixVertex );
	
	MTH3D_M_vNormalizeVector(&u,&u);
	MTH3D_M_vMulScalarVector(&u,m_xOrientationTangentLenght,&u);

	poTangent->fn_vSetTangentDirection (&u);
	GetInterface()->GetInterface()->fn_vUpdateAll (E_mc_JustDraw);
}

void Link::fn_vChangeAllTangent (Tangent* pTangent)
{
	// on pourrait blinder en s'assurant que la tangente reçue est bien une tangente d'orientation
	MTH3D_tdstVector stTangent;
	pTangent->fn_pGetAbsoluteTangent(&stTangent);
	m_poParent->fn_vChangeAllOrientationTangent (&stTangent);
}


void Link::fn_vSetOrientationTangent ( int iSide, MTH3D_tdstVector* pTangentVertex )
{
	switch (iSide)
	{
	case 1 : m_poFirstOrientationTangent->fn_vSetTangentDirection (pTangentVertex); break;
	case 2 : m_poSecondOrientationTangent->fn_vSetTangentDirection (pTangentVertex); break;
	}
}

void Link::fn_vSetAllOrientationTangent (MTH3D_tdstVector* pTangentVertex)
{
	m_poFirstOrientationTangent->fn_vSetTangentDirection (pTangentVertex);
	m_poSecondOrientationTangent->fn_vSetTangentDirection (pTangentVertex);
	fn_vRefreshEngineOrientation ();
}

void Link::fn_vVertex2Rotation (MTH_tdxReal* pxXRot, MTH_tdxReal* pxYRot, MTH_tdxReal* pxZRot, MTH3D_tdstVector* pstVector, MTH_tdxReal* pxRot )
{
	MTH3D_tdstVector stU, stV, stW;
	MTH3D_tdstVector stu, stw;
	MTH_tdxReal xSin, xCos;
	MTH3D_tdstMatrix stMatrix;

	MTH3D_tdstVector stOx, stOz;

	MTH3D_M_vSetVectorElements( &stOx, 1.f, 0.f, 0.f);
	MTH3D_M_vSetVectorElements( &stOz, 0.f, 0.f, 1.f);

	stV = *pstVector;
	MTH3D_M_vNormalizeVector (&stV, &stV);

	if ( fn_bIsRealNul(MTH3D_M_xGetXofVector(&stV)) && fn_bIsRealNul(MTH3D_M_xGetYofVector(&stV)) )
	{
		MTH3D_M_vCrossProductVector ( &stu, &stOx, &stV );
	}
	else 
	{
		MTH3D_M_vCrossProductVector ( &stu, &stV, &stOz );
	}
	
	MTH3D_M_vNormalizeVector (&stu, &stu);

	MTH3D_M_vCrossProductVector (&stw, &stu, &stV);

	MTH_tdxReal sinRot = MTH_M_xSin ( *pxRot );
	MTH_tdxReal cosRot = MTH_M_xCos ( *pxRot );

	MTH3D_M_vMulScalarVector ( &stw, cosRot, &stw );
	MTH3D_M_vMulScalarVector ( &stu, sinRot, &stu );
	MTH3D_M_vAddVector ( &stW, &stw, &stu);

	MTH3D_M_vCrossProductVector (&stU, &stV, &stW);

	fn_vCorrectNulValue ( &stU );
	fn_vCorrectNulValue ( &stV );
	fn_vCorrectNulValue ( &stW );


	// Ox rotation
	*pxXRot =  atan2 ( MTH3D_M_xGetZofVector(&stV), MTH3D_M_xGetYofVector(&stV) );
	xSin = sin (*pxXRot);
	xCos = cos (*pxXRot);
	MTH3D_M_vSetMatrixLineXElements( &stMatrix, 1.f, 0.f, 0.f );
	MTH3D_M_vSetMatrixLineYElements( &stMatrix, 0.f, xCos, xSin );
	MTH3D_M_vSetMatrixLineZElements( &stMatrix, 0.f, -xSin, xCos )
	MTH3D_M_vMulMatrixVector( &stU, &stMatrix, &stU);
	MTH3D_M_vMulMatrixVector( &stV, &stMatrix, &stV);
	MTH3D_M_vMulMatrixVector( &stW, &stMatrix, &stW);
	

	// Oz rotation
	*pxZRot =  atan2 ( -MTH3D_M_xGetXofVector(&stV), MTH3D_M_xGetYofVector(&stV) );
	xSin = MTH_M_xSin (*pxZRot);
	xCos = MTH_M_xCos (*pxZRot);
	MTH3D_M_vSetMatrixLineXElements( &stMatrix, xCos, xSin, 0.f );
	MTH3D_M_vSetMatrixLineYElements( &stMatrix, -xSin, xCos, 0.f );
	MTH3D_M_vSetMatrixLineZElements( &stMatrix, 0.f, 0.f, 1.f )
	MTH3D_M_vMulMatrixVector( &stU, &stMatrix, &stU);
	MTH3D_M_vMulMatrixVector( &stV, &stMatrix, &stV);
	MTH3D_M_vMulMatrixVector( &stW, &stMatrix, &stW);


	fn_vCorrectNulValue ( &stU );
	fn_vCorrectNulValue ( &stV );
	fn_vCorrectNulValue ( &stW );

	// Oy rotation
	if ( !fn_bIsRealNul(MTH3D_M_xGetZofVector(&stU)) || !fn_bIsRealNul(MTH3D_M_xGetXofVector(&stU)) ) 
		*pxYRot = atan2 ( -MTH3D_M_xGetZofVector(&stU), MTH3D_M_xGetXofVector(&stU) );
	else
		*pxYRot =  atan2 ( MTH3D_M_xGetXofVector(&stW), MTH3D_M_xGetZofVector(&stW) );

	xSin = MTH_M_xSin (*pxYRot);
	xCos = MTH_M_xCos (*pxYRot);
	MTH3D_M_vSetMatrixLineXElements( &stMatrix, xCos, 0.f, -xSin );
	MTH3D_M_vSetMatrixLineYElements( &stMatrix, 0.f, 1.f, 0.f );
	MTH3D_M_vSetMatrixLineZElements( &stMatrix, xSin, 0.f, xCos )
	MTH3D_M_vMulMatrixVector( &stU, &stMatrix, &stU);
	MTH3D_M_vMulMatrixVector( &stV, &stMatrix, &stV);
	MTH3D_M_vMulMatrixVector( &stW, &stMatrix, &stW);
}


void Link::fn_vRotation2Vertex ( MTH3D_tdstVector* pstVector, MTH_tdxReal* pxRot, MTH_tdxReal* pxXRot, MTH_tdxReal* pxYRot, MTH_tdxReal* pxZRot )
{
	MTH3D_tdstVector stU, stV, stW;
	MTH_tdxReal xSin, xCos;

	MTH3D_M_vSetVectorElements( &stU, 1.f, 0.f, 0.f);
	MTH3D_M_vSetVectorElements( &stV, 0.f, 1.f, 0.f);
	MTH3D_M_vSetVectorElements( &stW, 0.f, 0.f, 1.f);

	// Ox rotation
	xSin = MTH_M_xSin (*pxXRot);
	xCos = MTH_M_xCos (*pxXRot);
	MTH3D_M_vMulScalarVector ( &stV, xCos, &stV );
	MTH3D_M_vMulScalarVector ( &stW, xSin, &stW );
	MTH3D_M_vAddVector ( &stV, &stV, &stW);
	MTH3D_M_vCrossProductVector (&stW, &stU, &stV);


	// Oz rotation
	xSin = MTH_M_xSin (*pxZRot);
	xCos = MTH_M_xCos (*pxZRot);
	MTH3D_M_vMulScalarVector ( &stU, xCos, &stU );
	MTH3D_M_vMulScalarVector ( &stV, xSin, &stV );
	MTH3D_M_vAddVector ( &stU, &stU, &stV);
	MTH3D_M_vCrossProductVector (&stV, &stW, &stU);

	
	// Oy rotation
	xSin = MTH_M_xSin (*pxYRot);
	xCos = MTH_M_xCos (*pxYRot);
	MTH3D_M_vMulScalarVector ( &stW, xCos, &stW );
	MTH3D_M_vMulScalarVector ( &stU, xSin, &stU );
	MTH3D_M_vAddVector ( &stW, &stW, &stU);
	MTH3D_M_vCrossProductVector (&stU, &stV, &stW);

	*pstVector = stV;
	MTH3D_M_vMulScalarVector(pstVector,m_xOrientationTangentLenght,pstVector);
	
	MTH3D_tdstMatrix stMatrix;
	MTH3D_tdstVector stOz;
	MTH3D_M_vSetColumnInMatrix ( &stMatrix, &stU, 0 );
	MTH3D_M_vSetColumnInMatrix ( &stMatrix, &stV, 1 );
	MTH3D_M_vSetColumnInMatrix ( &stMatrix, &stW, 2 );
	MTH3D_M_vInverMatrix (&stMatrix, &stMatrix);
	MTH3D_M_vGetColumnInMatrix ( &stOz, &stMatrix, 2 );

	*pxRot = - atan2 ( MTH3D_M_xGetXofVector(&stOz), MTH3D_M_xGetZofVector(&stOz) );
}

void Link::fn_vCorrectNulValue ( MTH3D_tdstVector* pstVector )
{
	if ( fn_bIsRealNul (MTH3D_M_xGetXofVector (pstVector)) )	MTH3D_M_vSetXofVector (pstVector,0.);
	if ( fn_bIsRealNul (MTH3D_M_xGetYofVector (pstVector)) )	MTH3D_M_vSetYofVector (pstVector,0.);
	if ( fn_bIsRealNul (MTH3D_M_xGetZofVector (pstVector)) )	MTH3D_M_vSetZofVector (pstVector,0.);
}

BOOL Link::fn_bIsRealNul ( MTH_tdxReal& rReal )
{
	return ( fabs(rReal) < 1.e-5);
}

void Link::fn_vComputeModulusRotation ( MTH_tdxReal* xStartRot, MTH_tdxReal* xEndRot, BOOL bDirectOrientation, long lNbLapOrientation )
{
	// direct orientation
	if (bDirectOrientation && (*xStartRot-1e-5)>(*xEndRot)) (*xEndRot)+=MTH_C_2Pi;
	else if (!bDirectOrientation && (*xStartRot)<(*xEndRot-1e-3)) (*xStartRot)+=MTH_C_2Pi;

	// number of laps
	long lSignedLap = bDirectOrientation ? lNbLapOrientation : -lNbLapOrientation;
	(*xEndRot) += lSignedLap * MTH_C_2Pi;
}

void Link::fn_vExtractModulusRotation ( BOOL* bDirectOrientation, long* lNbLapOrientation, MTH_tdxReal& xStartRot, MTH_tdxReal& xEndRot )
{
	*bDirectOrientation = (xEndRot>=xStartRot);

	if (*bDirectOrientation) 
	{
		*lNbLapOrientation = (long)((xEndRot-xStartRot+1e-3)/MTH_C_2Pi);
		xEndRot -= (*lNbLapOrientation) * MTH_C_2Pi;
		if (xEndRot+1e-3>=MTH_C_Pi) xEndRot -= MTH_C_2Pi;
	}
	else 
	{
		*lNbLapOrientation = (long)((xStartRot-xEndRot+1e-3)/MTH_C_2Pi);
		xEndRot += (*lNbLapOrientation) * MTH_C_2Pi;
		if (xStartRot-1e-3<-MTH_C_Pi) xStartRot += MTH_C_2Pi;
	}
}

*/
//ENDANNECY Shaitan Nettoyage }
