/*
 *=======================================================================================
 * Name        : DNMMTH.c
 * Author      : CB / YLG / VL               
 * Description : 
 *=======================================================================================
 */
 
#include "MEC/DNMMTH.h"
#include "MTH.h"
 
/*
 **************************************************************************************************
 **************************************************************************************************
	TOOLS
 **************************************************************************************************
 **************************************************************************************************
 */
/*
 *=================================================================================================
 Projection of a vector on a plane                       
 Beware : ||_p_stPlaneNorm|| = ||_p_stProjDirection)|| = 1 
 *=================================================================================================
 */
void MTH_fn_vVectorPlaneProjection(
	MTH3D_tdstVector *_p_stResult,
	MTH3D_tdstVector *_p_stSource,
	MTH3D_tdstVector *_p_stPlaneNorm,
	MTH3D_tdstVector *_p_stProjDirection
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  MTH3D_tdstVector	a_stVector[1];
  MTH3D_tdstVector	*p_stTmp = a_stVector;
 
  MTH_tdxReal		xAlpha;
  MTH_tdxReal		xDotProduct;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
  if(_p_stProjDirection != _p_stPlaneNorm)
    xDotProduct = MTH3D_M_xDotProductVector(_p_stProjDirection,_p_stPlaneNorm);
  else
    xDotProduct = MTH_C_ONE;
 
  if(!MTH_M_bEqualZero(xDotProduct)) 
  {
    xAlpha = MTH_M_xNeg(MTH3D_M_xDotProductVector(_p_stSource,_p_stPlaneNorm));
    xAlpha = MTH_M_xDiv(xAlpha,xDotProduct);
    
	MTH3D_M_vCopyVector(p_stTmp,_p_stProjDirection);
    MTH3D_M_vMulScalarVector(p_stTmp, xAlpha, p_stTmp);
 
    if(_p_stResult != _p_stSource)
      MTH3D_M_vCopyVector(_p_stResult,_p_stSource);
    MTH3D_M_vAddVector(_p_stResult,_p_stResult,p_stTmp);
  }
}
 
/*
 *=================================================================================================
 Compute a rotation thanks a source vector and an image vector 
 ||_p_stSrcUnitVector|| = ||_p_stImaUnitVector|| = 1           
 *=================================================================================================
 */
MTH_tdstRotation *MTH_p_stRotationComputeRotationWith2Vectors(MTH_tdstRotation *_p_stResult,
                                                              MTH3D_tdstVector *_p_stSrcUnitVector,
                                                              MTH3D_tdstVector *_p_stImaUnitVector)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  MTH3D_tdstVector	*p_stAxis;
  MTH_tdxReal		xCos;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  
#ifdef DNM_DEBUG
  if(_p_stResult == NULL)
    return NULL;
  if(_p_stSrcUnitVector == NULL)
    return NULL;
  if(_p_stImaUnitVector == NULL)
    return NULL;
#endif
  
  p_stAxis = MTH_M_p_stRotationGetAxis(_p_stResult);
  
  MTH3D_M_vCrossProductVectorWithoutBuffer(p_stAxis,_p_stSrcUnitVector,_p_stImaUnitVector);
  if 
	  (
	  MTH_M_bIsNullWithEpsilon(MTH3D_M_xGetXofVector(p_stAxis), MTH_M_xDoubleToReal(1.0e-5))
	  && MTH_M_bIsNullWithEpsilon(MTH3D_M_xGetYofVector(p_stAxis), MTH_M_xDoubleToReal(1.0e-5))
	  && MTH_M_bIsNullWithEpsilon(MTH3D_M_xGetZofVector(p_stAxis), MTH_M_xDoubleToReal(1.0e-5))
	  )
  {
/*CB
	  if(MTH_M_xSign(MTH3D_M_xGetXofVector(_p_stSrcUnitVector)) != MTH_M_xSign(MTH3D_M_xGetXofVector(_p_stImaUnitVector)))
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
	  }
	  else if(MTH_M_xSign(MTH3D_M_xGetYofVector(_p_stSrcUnitVector)) != MTH_M_xSign(MTH3D_M_xGetYofVector(_p_stImaUnitVector)))
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
	  }
	  else if(MTH_M_xSign(MTH3D_M_xGetZofVector(_p_stSrcUnitVector)) != MTH_M_xSign(MTH3D_M_xGetZofVector(_p_stImaUnitVector)))
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
	  }
	  else
	  {
		  MTH_M_RotationSetNull(_p_stResult);
	  }
	  */
	  if
		(
			MTH_M_bEqualWithEpsilon(MTH3D_M_xGetXofVector(_p_stSrcUnitVector), MTH3D_M_xGetXofVector(_p_stImaUnitVector), MTH_M_xDoubleToReal(1.0e-5))
		&&	MTH_M_bEqualWithEpsilon(MTH3D_M_xGetYofVector(_p_stSrcUnitVector), MTH3D_M_xGetYofVector(_p_stImaUnitVector), MTH_M_xDoubleToReal(1.0e-5))
		&&	MTH_M_bEqualWithEpsilon(MTH3D_M_xGetZofVector(_p_stSrcUnitVector), MTH3D_M_xGetZofVector(_p_stImaUnitVector), MTH_M_xDoubleToReal(1.0e-5))
		)
	  {
		  MTH_M_RotationSetNull(_p_stResult);
	  }
	  else
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
	  }
  }
  else
  {
	  MTH3D_M_vNormalizeVector(p_stAxis, p_stAxis);
	  
	  xCos = MTH3D_M_xDotProductVector(_p_stSrcUnitVector,_p_stImaUnitVector);
	  if( MTH_M_bLessEqual(xCos, MTH_C_MinusONE))
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
	  }
	  else if ( MTH_M_bGreaterEqual(xCos, MTH_C_ONE)) 
	  {
		  MTH_M_RotationSetNull(_p_stResult);
	  }
	  else
	  {
		  MTH_M_xRotationSetAngle(_p_stResult,MTH_M_xACos(xCos));
	  }
  }
  
  return _p_stResult;
}
 
/*
 *=================================================================================================
 Rotation(Vector/Point) 
 *=================================================================================================
 */
MTH3D_tdstVector *MTH_p_stRotationMulVector
(
	MTH_tdstRotation	*_p_stRotation,
    MTH3D_tdstVector	*_p_stSource,
    MTH3D_tdstVector	*_p_stResult
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    MTH3D_tdstVector		stTmp0,stTmp1;
    MTH3D_tdstVector		*p_stAxis;
    MTH_tdxReal				xCos,xSin,xValue, xAngle;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
#ifdef DNM_DEBUG
    if(_p_stRotation == NULL)
        return NULL;
    if(_p_stSource == NULL)
        return NULL;
    if(_p_stResult == NULL)
        return NULL;
#endif
 
    /* R(r) = (cosq)r + (1 - cosq)n(n·r) + (sinq)n^r */
	xAngle = MTH_M_xRotationGetAngle(_p_stRotation);
    xCos = MTH_M_xCos(xAngle);
    xSin = MTH_M_xSin(xAngle);
    p_stAxis = MTH_M_p_stRotationGetAxis(_p_stRotation);
 
    MTH3D_M_vCrossProductVector(&stTmp0,p_stAxis,_p_stSource);
    MTH3D_M_vMulScalarVector(&stTmp0, xSin, &stTmp0);
 
    xValue = MTH_M_xMul(MTH3D_M_xDotProductVector(p_stAxis,_p_stSource),MTH_M_xSub(MTH_C_ONE,xCos));
    MTH3D_M_vCopyVector(&stTmp1,p_stAxis);
    MTH3D_M_vMulScalarVector(&stTmp1, xValue, &stTmp1);
 
    if(_p_stSource != _p_stResult)
        MTH3D_M_vCopyVector(_p_stResult,_p_stSource);
    MTH3D_M_vMulScalarVector(_p_stResult, xCos, _p_stResult);
 
    MTH3D_M_vAddVector(_p_stResult, _p_stResult, &stTmp1);
    MTH3D_M_vAddVector(_p_stResult, _p_stResult, &stTmp0);
 
    return _p_stResult;
}
 
 
 
 
/*
 *=================================================================================================
 Matrix -> Rotation 
 *=================================================================================================
 */
 
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
MTH_tdstRotation *MTH_p_stRotationFromMatrix 
(
	MTH_tdstRotation *_p_stResult,  
	MTH3D_tdstMatrix *_p_stRotationMatrix
)
{
 
	static MTH_tdxReal s_xLimit = MTH_M_xDoubleToReal(2.999999);
	MTH3D_tdstVector *p_stAxis;
	MTH_tdxReal xTrace, xCos,xSin;
	MTH3D_tdstVector stI, stJ, stK;
  
#ifdef DNM_DEBUG
  if(_p_stResult == NULL)
    return NULL;
  if(_p_stRotationMatrix == NULL)
    return NULL;
#endif
  
	xTrace = MTH3D_M_xTraceMatrix( _p_stRotationMatrix);
 
	if (MTH_M_bLess(xTrace,s_xLimit))
	{
		MTH3D_M_vGetVectorsInMatrix ( &stI, &stJ, &stK, _p_stRotationMatrix );
 
		p_stAxis = MTH_M_p_stRotationGetAxis(_p_stResult);
    
		MTH3D_M_vSetXofVector ( p_stAxis, MTH_M_xSub ( MTH3D_M_xGetZofVector(&stJ), MTH3D_M_xGetYofVector(&stK) ) );
		MTH3D_M_vSetYofVector ( p_stAxis, MTH_M_xSub ( MTH3D_M_xGetXofVector(&stK), MTH3D_M_xGetZofVector(&stI) ) );
		MTH3D_M_vSetZofVector ( p_stAxis, MTH_M_xSub ( MTH3D_M_xGetYofVector(&stI), MTH3D_M_xGetXofVector(&stJ) ) );
 
		if (MTH3D_M_bIsNullVector(p_stAxis))
		{
			if (MTH_M_bEqual (MTH3D_M_xGetXofVector(&stI),MTH_C_ONE))
			{
				MTH3D_M_vSetBaseIVector (p_stAxis);
				MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
			}
			else if (MTH_M_bEqual (MTH3D_M_xGetYofVector(&stJ),MTH_C_ONE))
			{
				MTH3D_M_vSetBaseJVector (p_stAxis);
				MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
			}
			else if (MTH_M_bEqual (MTH3D_M_xGetZofVector(&stK),MTH_C_ONE))
			{
				MTH3D_M_vSetBaseKVector (p_stAxis);
				MTH_M_xRotationSetAngle(_p_stResult,MTH_C_Pi);
			}
		}
		else
		{
			MTH3D_M_vNormalizeVector (p_stAxis,p_stAxis);
			xCos = MTH_M_xMul ( MTH_M_xSub(xTrace,MTH_C_ONE) , MTH_C_Inv2 );
			xSin = MTH_M_xAdd3(MTH3D_M_xGetXofVector(&stJ),MTH3D_M_xGetXofVector(&stK),MTH3D_M_xGetYofVector(&stK));
 
			if (MTH_M_bLessEqual( xCos, MTH_C_MinusONE)) MTH_M_xRotationSetAngle ( _p_stResult, MTH_C_Pi);
			else if (MTH_M_bGreaterEqual( xCos, MTH_C_ONE)) MTH_M_xRotationSetAngle ( _p_stResult, MTH_C_ZERO );
			else 
				MTH_M_xRotationSetAngle (_p_stResult,MTH_M_bGreaterEqualZero(xSin)?MTH_M_xNeg(MTH_M_xACos(xCos)):MTH_M_xACos(xCos));
		}
	}
	else MTH_M_RotationSetNull(_p_stResult);
 
	return _p_stResult;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
 
 
