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

		Angle.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Vector Math Library, Release 2.0,  1/1/96 
		Copyright 1996 Alec Miller, All Rights Reserved 

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/8/97		Ian			Removed iostream stuff altogether it's not compatible with
								Windows or MSL.
		5/15/96		Alec		new today - added vector math library to InfiniD project

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

#ifndef H_ANGLE
#define H_ANGLE

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicDefines.h"
#include "MCBasicTypes.h"
#include "Real.h"

// our defines are a little unclear as to their conversion, so these are defined
#define kRadToDeg RAD_DEG 
#define kDegToRad DEG_RAD 

/// \addtogroup Data
/// \{

/// TAngle is a lightweight object meant to standardize the use of angles.
/// The value is stored internally in radians for performance.
class TAngle : public TMCObject
{
public:
	enum EUnits 
	{
		kUnits_Degrees,
			kUnits_Radians
	};
	
	// a conversion back to real ( in radians )
	inline operator real	(void) const;
	
	// also use the default copy constructor and =
	inline TAngle				(void);
	inline TAngle				(const real angleValue); // assumes radians	
	inline TAngle				(const real	angleValue, const EUnits angleType);
	
	inline void SetValue		(const real	angleValue, const EUnits angleType);
	
	// retrieve the angle value in a particular format
	inline real InRadians		(void) const;
	inline real InDegrees		(void) const;
	inline real InFormat		(const EUnits units) const;
				
	// retrieval of sin, cos, and tangent and inverse operations
	inline real GetCosine		(void) const;
	inline real GetSine			(void) const;
	inline real GetTangent		(void) const;
	
	static TAngle ArcCosine		(const real value);
	static TAngle ArcSine		(const real value);
	static TAngle ArcTangent	(const real value);
	static TAngle ArcTangentYX	(const real valueY, const real valueX);
	
	inline TAngle& operator+=	(const TAngle& ang);
	inline TAngle& operator-=	(const TAngle& ang);
	inline TAngle& operator*=	(const real scalar);
	inline TAngle& operator/=	(const real scalar);
	
public:
	// Do not use these constants to intialize global vars.  Instantiation 
	// ordering of globals across files is not specified by C++.
	
	static const real	kPiRadians;
	//		= 3.141159...
	static const real	kRadiansToDegreesMultiplier;
	// 		= 180.0 / kPiRadians;
	static const real	kDegreesToRadiansMultiplier;
	// 		= 1.0 / kRadiansToDegreesMultiplier;
	
	static const TAngle kZero;
	//		= 0.0
	static const TAngle k45Degrees;
	//		= 45 degrees
	static const TAngle k90Degrees;
	//		= 90 degrees
	static const TAngle k180Degrees;
	//		= 180 degrees
	static const TAngle k270Degrees;
	//		= 270 degrees
	static const TAngle k360Degrees;
	//		= 360 degrees
	
private:
		real fValue;
};

/// \}

// [operator implementation] -------------------------------------------------------------//

inline TAngle operator+ (const TAngle& lhs, const TAngle& rhs)
	{ return TAngle( lhs.InRadians() + rhs.InRadians() ); }

inline TAngle operator- (const TAngle& lhs, const TAngle& rhs)
	{ return TAngle( lhs.InRadians() - rhs.InRadians() ); }

inline TAngle operator* (const TAngle& lhs, const TAngle& rhs)
	{ return TAngle( lhs.InRadians() * rhs.InRadians() ); }

inline TAngle operator/ (const TAngle& lhs, const TAngle& rhs)
	{ return TAngle( lhs.InRadians() / rhs.InRadians() ); }

inline TAngle operator- (const TAngle& a)
	{ return -a.InRadians(); }

// [inline implementation] -------------------------------------------------------------//

inline TAngle::TAngle			(void)
	{ }
inline TAngle::TAngle			(const real angleValue)
		: fValue( angleValue )	
	{ }
	
inline TAngle::TAngle			(const real	angleValue, const EUnits angleType)
		: fValue( angleType == kUnits_Radians ? angleValue : kDegToRad * angleValue)
	{ }

inline void TAngle::SetValue	(const real	angleValue, const EUnits angleType)
	{ 
		fValue = ( angleType == kUnits_Radians ) ? angleValue : kDegToRad * angleValue;
	}

// ----------------------------
	
inline real TAngle::GetCosine	(void) const
	{ return RealCos( fValue ); }

inline real TAngle::GetSine		(void) const
	{ return RealSin( fValue ); }

inline real TAngle::GetTangent	(void) const
	{ return RealTan( fValue ); }

// ----------------------------

real TAngle::InRadians			(void) const
	{ return fValue; }

real TAngle::InDegrees			(void) const
	{ return kRadToDeg * fValue; }

real TAngle::InFormat			(const EUnits units) const
	{ 
		return ( units == kUnits_Radians ) ? fValue : kRadToDeg * fValue;
	}

// ----------------------------

TAngle& TAngle::operator+=		(const TAngle& ang)
	{ fValue += ang.fValue; return *this; }

TAngle& TAngle::operator-=		(const TAngle& ang)
	{ fValue -= ang.fValue; return *this; }

TAngle& TAngle::operator*=		(const real scalar)
	{ fValue *= scalar; return *this; }

TAngle& TAngle::operator/=		(const real scalar)
	{ fValue /= scalar; return *this; }

// ----------------------------

inline TAngle::operator real	(void) const
	{ return fValue; }

#endif /* H_ANGLE */