#ifndef _dkutilMathEx__
#define _dkutilMathEx__

namespace dkutil{
#ifdef USE_DKINGYO_SINTABLESIZE_256
#	define DKINGYO_SINTABLESIZE 256
#else
#	define DKINGYO_SINTABLESIZE 360
#endif
#define DKINGYO_SINTABLEMASK		255//(DKINGYO_SINTABLESIZE - 1)
/// Multiplier for degrees to radians
#define DKINGYO_DTOR    0.0174532925199432957692369077
/// Multiplier for radians to degrees
#define DKINGYO_RTOD    57.295779513082320876798154814

//#define DKINGYO_DTOR_FLOAT 0.01745329f
//#define DKINGYO_RTOD_FLOAT 57.2957795f

/*!
d金魚が使いそうな数学ロジックを集めたもの。
内部の変数はstaticなのでいくら宣言してもメモリは圧迫しないと思うよ。<br>
<br>
<b>■最近知った　私の理解が間違っているかもしれない　数学用語</b>
<br>
degree：でぃぐりー：普通は0から360度の角度の単位？　学校で教えられているやつ<br>
radian：らじあん：私にはまったくわからない角度単位 degreeな角度 * π / 180 で算出されるもの<br>
<br>
そして、Ｃ言語ではもっぱら”ラジアン”ばっかり使われる^^;私が中学生の時は超戸惑ったよ！<br>
このクラスは私が扱いやすいようにDegreeを扱うのに非常に都合がよくできていたりする^^;<br>
*/



class TrigonometricFunction{
protected:
	static float    sintable[DKINGYO_SINTABLESIZE];

public:
	const float *getsintable()const{return sintable;}
	size_t getsintablesize()const{return DKINGYO_SINTABLESIZE;}

	TrigonometricFunction(){
		static bool re=triginit();
	}
	virtual ~TrigonometricFunction()
	{}
#ifdef USE_DKINGYO_SINTABLESIZE_256
	bool triginit(void)
	{
			double  theta;
			for (int i = 0; i < DKINGYO_SINTABLESIZE; ++i)
			{
					theta = (double)i/((float)DKINGYO_SINTABLESIZE / (2.0f * getPAI()));
					sintable[i] = (float)sin(theta);
			}
			return true;
	}
	///@param theta[in] ラジアン単位の角度
	inline float    fsin(float theta)
	{
		int angle = get360to256(RadianToDegree(theta));
		return sintable[angle & DKINGYO_SINTABLEMASK];
	
	}
	///@param theta[in] ラジアン単位の角度
	inline float    fcos(float theta)
	{
		int angle = get360to256(RadianToDegree(theta));
		return sintable[(angle+(DKINGYO_SINTABLESIZE>>2)) & DKINGYO_SINTABLEMASK];
	}
	/*!
	@param angle[in] degreeな角度
	@return sin値
	*/
	inline float AngleToCos( int angle ){
		//angle = get360to256(angle);
		//int a=(angle+(SINTABLESIZE>>2)) & SINTABLEMASK;
		//if(a>254) MB("ERROR");
		return sintable[(get360to256(angle)+(DKINGYO_SINTABLESIZE>>2)) & DKINGYO_SINTABLEMASK];
	}
	///@param angle[in] dgreeな角度 @return cos値
	inline float AngleToSin( int angle ){ return sintable[get360to256(angle)];}

#	else //360度型

	bool triginit(void)
	{
			for (int i = 0; i < DKINGYO_SINTABLESIZE; ++i)
			{
				sintable[i] = (float)::sin(DKINGYO_DTOR * i);
			}
			return true;
	}
	///@param theta[in] ラジアン単位の角度
	inline float    fsin(float theta)
	{
		unsigned int angle = DKINGYO_RTOD * theta;
		return sintable[angle];
	
	}
	///@param theta[in] ラジアン単位の角度
	inline float    fcos(float theta)
	{
		unsigned int angle = DKINGYO_RTOD * theta;
		//360度単位だと、素直にこうするしかないのね･･･
		if(angle < 90){angle + DKINGYO_SINTABLESIZE;}
		return sintable[angle - 90];
		//return sintable[(angle + (DKINGYO_SINTABLESIZE>>2)) ];
	}
	/*!
	@param angle[in] degreeな角度
	@return sin値
	*/
	inline float AngleToCos( int angle ){
		return sintable[(angle < 90) ? angle + DKINGYO_SINTABLESIZE : angle ];
	}
	///@param angle[in] dgreeな角度 @return cos値
	inline float AngleToSin( int angle ){ return sintable[angle];}

#endif


	///360度単位から256度単位に直してくれる
	inline int get360to256( int angle )
	{
		return ((angle * 256 ) / 360);
	}



	///ディグリーな角度？をラジアンな角度にしてくれる！？
	inline double DegreeToRadian(int angle){	return angle * DKINGYO_DTOR;}
	//inline float DegreeToRadian(int angle){	return angle * getPAI() / 180;}
	///ラジアンな角度？をディグリーな角度にしてくれる！？
	inline int RadianToDegree(double radian){ return (int)(radian * DKINGYO_RTOD);}
	//inline int RadianToDegree(float radian){ return (int)(radian * 180 / getPAI());}

	///@return float型のπをゲットする
	inline float getPAI(){return 3.14159265f;}
	///@return double型のπをゲットする
	inline double getDoublePAI(){return 3.1415926535897932f;}	
	///AngleToCosとAngleToSinを両方やってくれるもの。
	inline void SinCos( long angle, float *pSin, float *pCos ){
		*pSin = AngleToSin(angle);
		*pCos = AngleToCos(angle);
	}

};






}//end of dkutil namespace


#endif