/*
 *	clipmath.h
 *
 *	固定小数ライブラリを定義します。
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001 Naoyuki Sawa
 *
 *	* Sat Dec  1 07:12:31 JST 2001 Naoyuki Sawa
 *	- 作成開始。
 */
#ifndef __CLIP_MATH_H__
#define __CLIP_MATH_H__

/*****************************************************************************
 *	定数
 *****************************************************************************/

#define PI	3.14159265358979323846F	/* π */
#define PI2	(PI * 2)		/* 2π */
#define PI_2	(PI / 2)		/* π/2 */

/*****************************************************************************
 *	ベクトル
 *****************************************************************************/

/* ベクトルを表します。
 */
typedef struct _VECTOR {
	float x;	/* X成分 */
	float y;	/* Y成分 */
	float z;	/* Z成分 */
} VECTOR;

/* 定義済みのベクトルです。
 */
extern const VECTOR VECTOR_0;	/* ゼロベクトル */
extern const VECTOR VECTOR_X;	/* X軸単位ベクトル */
extern const VECTOR VECTOR_Y;	/* Y軸単位ベクトル */
extern const VECTOR VECTOR_Z;	/* Z軸単位ベクトル */

/* ベクトルを作成します。
 * [in]
 *	o		結果を格納するベクトル。
 *	x,y,z		X,Y,Z成分の値。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_init(VECTOR* o, float x, float y, float z);

/* ベクトルの各成分を符号反転します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a		符号反転するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_neg(VECTOR* o, const VECTOR* a);

/* ベクトルの各成分を加算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a,b		加算するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_add(VECTOR* o, const VECTOR* a, const VECTOR* b);

/* ベクトルの各成分を減算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a,b		減算するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_sub(VECTOR* o, const VECTOR* a, const VECTOR* b);

/* ベクトルの各成分を乗算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a,b		乗算するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_mul(VECTOR* o, const VECTOR* a, const VECTOR* b);

/* ベクトルの各成分を除算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a,b		除算するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_div(VECTOR* o, const VECTOR* a, const VECTOR* b);

/* ベクトルの各成分を同じ値で乗算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a		乗算するベクトル。
 *	s		乗算する値。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_mul1(VECTOR* o, const VECTOR* a, float s);

/* ベクトルの各成分を同じ値で除算します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a		除算されるベクトル。
 *	s		除算する値。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_div1(VECTOR* o, const VECTOR* a, float s);

/* ベクトルの内積(dot product)を求めます。
 * [in]
 *	a,b		内積を求めるベクトル。
 * [out]
 *	戻り値		内積の値。
 * [note]
 * 	* 内積の定義: a・b = |a||b|cosθ
 */
float vector_dot(const VECTOR* a, const VECTOR* b);

/* ベクトルの外積(cross product)を求めます。
 * [in]
 *	o		結果を格納するベクトル。
 *	a,b		外積を求めるベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 * 	* 外積の定義: a×b = |a||b|sinθ*c
 * 	  ただし、cはaとbに垂直な単位ベクトルとする。
 */
VECTOR* vector_cross(VECTOR* o, const VECTOR* a, const VECTOR* b);

/* ベクトルを正規化(normalize)します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a		正規化するベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_normal(VECTOR* o, const VECTOR* a);

/* ベクトルの長さ(magnitude)を求めます。
 * [in]
 *	a		長さを求めるベクトル。
 * [out]
 * 	戻り値		結果の値。
 */
float vector_mag(const VECTOR* a);

/* ベクトルの長さの二乗(square magnitude)を求めます。
 * [in]
 *	a		長さの二乗を求めるベクトル。
 * [out]
 * 	戻り値		結果の値。
 */
float vector_mag2(const VECTOR* a);

/* 反射ベクトルを求めます。
 * [in]
 *	o		結果を格納するベクトル。
 *	N		反射面の法線ベクトル。
 *	E		反射点から光源へのベクトル。
 *			言い換えると、逆向きの光源ベクトルです。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 反射ベクトルの公式は、次の通りです。
 *		R = 2(E・N)N - E
 *	  考え方:
 *	  ベクトルE,Nが同じ原点を持つとして、EからNへ垂線を下ろした場合、
 *	  その垂線がNと交わるP点は
 *		P = (E・N)N
 *	  です。なぜなら、(E・N)はベクトルE,Nのなす角のcos値だからです。
 *	  Rは、Pを基準にEに点対称な位置、すなわち、
 *	  Eから、E->Pの二倍進んだ位置です。
 *		R = E + 2(P - E)
 *		  = 2P - E
 *		  = 2(E・N)N - E
 *	  以上です。
 *	* ベクトルE,Nは、正規化されていなければいけません。
 *	  正規化されていない場合、間違った結果となります。
 *	  ※実際には、Eだけが正規化されていない場合は、
 *	    単に結果のベクトルの大きさがEに等しくなるだけのように思います。
 *	    (未確認)
 *	* ベクトルEは、"逆向きの"光源ベクトルであることに注意してください。
 *	  この関数は、反射ベクトルを求めると言うよりも、
 *	  Nを基準として、Eに線対称なベクトルを求める、と言った方が正確です。
 *	  Eを光源ベクトルと同じ向きに取った方が使いやすいと思うのですが、
 *	  公式として逆向きの方が一般的なようなので、ならってみました。
 */
VECTOR* vector_reflect(VECTOR* o, const VECTOR* N, const VECTOR* E);

/*****************************************************************************
 *	行列
 *****************************************************************************/

/* 行列を表します。
 */
typedef struct _MATRIX {
	/* | a00 a10 a20 |T = 姿勢ベクトルのX成分 */
	/* | a01 a11 a21 |T = 姿勢ベクトルのY成分 */
	/* | a02 a12 a22 |T = 姿勢ベクトルのZ成分 */
	/* | a03 a13 a23 |T = 平行移動成分        */
	float a00, a01, a02, a03;
	float a10, a11, a12, a13;
	float a20, a21, a22, a23;
} MATRIX;

/* 定義済みの行列です。
 */
extern const MATRIX MATRIX_I;	/* 単位(identity)行列 */

/* 行列を作成します。
 * [in]
 *	o		結果を格納する行列。
 *	a00〜a23	行列の成分。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_init(MATRIX* o,
	float a00, float a01, float a02, float a03,
	float a10, float a11, float a12, float a13,
	float a20, float a21, float a22, float a23);
 
/* 転置(transpose)行列を求めます。
 * [in]
 *	o		結果を格納する行列。
 *	a		転置する行列。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 平行移動成分は除去され、常に(0,0,0)となります。
 */
MATRIX* matrix_xpose(MATRIX* o, const MATRIX* a);

/* 逆行列(inverse)を求めます。
 * [in]
 *	o		結果を格納する行列。
 *	a		逆行列を求める行列。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 不可逆な行列を指定した場合の結果は、未定義です。
 */
MATRIX* matrix_inv(MATRIX* o, const MATRIX* a);

/* 正規直交(normalized orthogonal)行列の逆行列を求めます。
 * [in]
 *	o		結果を格納する行列。
 *	a		逆行列を求める行列。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* matrix_inv()よりも、高速です。
 *	* 正規直交でない行列を指定した場合の結果は、未定義です。
 */
MATRIX* matrix_invno(MATRIX* o, const MATRIX* a);

/* ベクトルを変換(transform)します。
 * [in]
 *	o		結果を格納するベクトル。
 *	a		行列。
 *	b		ベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
VECTOR* vector_xform(VECTOR* o, const MATRIX* a, const VECTOR* b);

/* 行列を変換(transform)します。
 * [in]
 *	o		結果を格納する行列。
 *	a,b		行列。
 *	b00〜b23	行列の成分。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_xform(MATRIX* o, const MATRIX* a, const MATRIX* b);
MATRIX* matrix_xform12(MATRIX* o, const MATRIX* a,
	float b00, float b01, float b02, float b03,
	float b10, float b11, float b12, float b13,
	float b20, float b21, float b22, float b23);

/*  平行移動(translate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	x,y,z		X,Y,Z軸の平行移動成分。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_xlate(MATRIX* o, const MATRIX* a, float x, float y, float z);

/* 拡大・縮小(scale)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	x,y,z		X,Y,Z軸の拡大・縮小係数。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_scale(MATRIX* o, const MATRIX* a, float x, float y, float z);

/* X,Y,Z軸とも同じ係数で、拡大・縮小を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	s		拡大・縮小係数。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_scale1(MATRIX* o, const MATRIX* a, float s);

/* 任意軸回転(rotate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	x,y,z		回転軸のベクトル。
 *	d		回転角度。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 回転軸のベクトルは、正規化されていなくても構いません。
 */
MATRIX* matrix_rot(MATRIX* o, const MATRIX* a, float x, float y, float z, float d);

/* 固定一軸回転(rotate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	d		回転角度。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_rotx(MATRIX* o, const MATRIX* a, float d);
MATRIX* matrix_roty(MATRIX* o, const MATRIX* a, float d);
MATRIX* matrix_rotz(MATRIX* o, const MATRIX* a, float d);

/* 固定二軸回転(rotate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	x,y,z		回転角度。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 三つの回転角度指定の効果は逆順です。
 *	  固定三軸回転の[note]を参照してください。
 */
MATRIX* matrix_rotxyx(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotxzx(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotyxy(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotyzy(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotzxz(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotzyz(MATRIX* o, const MATRIX* a, float x, float y, float z);

/* 固定三軸回転(rotate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	x,y,z		回転角度。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 行列を転置したので、逆順の効果になりました。
 *	  例えば、
 *		matrix_rotxyz(o, a, x, y, z)
 *	  は、
 *		matrix_rotz(o, a, z);
 *		matrix_roty(o, o, y);
 *		matrix_rotx(o, o, x);
 *	  と同じ結果となります。
 *	  関数の名前を変えた方がいいのかも知れませんが、
 *	  滅多に使わないので、とりあえずそのままにしておきます。
 */
MATRIX* matrix_rotxyz(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotxzy(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotyxz(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotyzx(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotzxy(MATRIX* o, const MATRIX* a, float x, float y, float z);
MATRIX* matrix_rotzyx(MATRIX* o, const MATRIX* a, float x, float y, float z);

/* 回転軸のベクトルと、回転角度を求めます。
 * [in]
 *	v		回転軸のベクトルを格納するベクトル。
 *	a		調べる行列。
 * [out]
 *	戻り値		回転角度。
 */
float matrix_rotget(VECTOR* o, const MATRIX* a);

/* 姿勢変換(orientate)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	dx,dy,dz	Z軸の姿勢ベクトル。
 *	ux,uy,uz	Y軸の姿勢ベクトル。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 姿勢ベクトルは、正規化されていなくても構いません。
 */
MATRIX* matrix_orient(MATRIX* o, const MATRIX* a,
	float dx, float dy, float dz,
	float ux, float uy, float uz);

/* 視点変換を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	ex,ey,ez	視点座標。
 *	cx,cy,cz	注視点座標。
 *	bank		バンク角度。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_lookat(MATRIX* o, const MATRIX* a,
	float ex, float ey, float ez,
	float cx, float cy, float cz,
	float bank);

/* 透視変換(frustum)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	width		投影面の幅              (実座標系)
 *	height		投影面の高さ            (実座標系)
 *	front		フロントクリッピング距離(実座標系)
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 完全な透視変換ではなく、Z座標は実座標のまま変化しません。
 *	  なぜなら、このライブラリでは行列を3x4で表しているので、
 *	  Z座標の正規化を考慮した透視変換行列を表せないからです。
 *	  しかし、zバッファではなく、zソートを想定しているので、
 *	  実用上問題はないと思います。
 *	* この行列で座標変換しただけでは、X,Y座標は正規化されません。
 *	  x=x/z,y=y/z を行って、x,yを(-1,1)に投影する必要があります。
 */
MATRIX* matrix_frustum(MATRIX* o, const MATRIX* a, float width, float height, float front);

/* 透視変換(perspective)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	fovy		垂直視野角度。
 *	aspect		アスペクト比(幅÷高さ)
 *	front		フロントクリッピング距離(実座標系)
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* matrix_frustum()のコメントを参照してください。
 */
MATRIX* matrix_perspect(MATRIX* o, const MATRIX* a, float fovy, float aspect, float front);

/* ビューポート変換(viewport)を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	left,top	ビューポート原点座標(スクリーン座標系)
 *	width,height	ビューポートサイズ  (スクリーン座標系)
 *			※引数型は固定小数ではなく整数であることに
 *			  注意してください。
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 * [note]
 *	* 透視変換 -> x=x/z,y=y/z -> ビューポート変換
 *	  の順で適用する場合は、matrix_viewport()を使ってください。
 *	* 透視変換 -> ビューポート変換 -> x=x/z,y=y/z
 *	  の順で適用する場合は、matrix_viewportz()を使ってください。
 *	* matrix_viewport()を使った座標変換の手順は、次のとおりです。
 *		1. T = モデル変換 * 視点変換 * 透視変換 による座標変換
 *		2. Zクリッピング
 *		3. x = x / z, y = y / z
 *		4. T = ビューポート変換 による座標変換
 *		5. XYクリッピング
 *	* これに対し、matrix_viewportz()を使った場合は、
 *		1. T = モデル変換 * 視点変換 * 透視変換 * ビューポート変換
 *	  	   による、座標変換
 *		2. Zクリッピング
 *		3. x = x / z, y = y / z
 *		4. XYクリッピング
 *	  となり、手順を一つ減らすことができます。
 */
MATRIX* matrix_viewport(MATRIX* o, const MATRIX* a, int left, int top, int width, int height);
MATRIX* matrix_viewportz(MATRIX* o, const MATRIX* a, int left, int top, int width, int height);

/* 投影変換を行います。
 * [in]
 *	o		結果を格納する行列。
 *	a		行列。
 *	Lx,Ly,Lz	光源ベクトル
 *	Gx,Gy,Gz	投影面上の一点(任意)の座標
 *	Nx,Ny,Nz	投影面の法線ベクトル
 * [out]
 *	戻り値		引数oの値をそのまま返します。
 */
MATRIX* matrix_shadow(MATRIX* o, const MATRIX* a,
	float Lx, float Ly, float Lz,
	float Gx, float Gy, float Gz,
	float Nx, float Ny, float Nz);

/*****************************************************************************
 *	浮動小数演算ユーティリティ
 *****************************************************************************/

/* 点から直線へ垂線を下ろした位置の、直線パラメータを求めます。
 * [in]
 *	p	点の座標。
 *	a	直線の始点座標。
 *	da	直線のベクトル。
 * [out]
 *	戻り値	直線上に垂線が下りた位置を表す、直線パラメータ。
 * [note]
 *	* 直線を半直線と見なす場合、垂線が半直線上に下りたか判定するには:
 *		daを半直線ののびる方向へのベクトルとしてsを求め、
 *			0 <= s
 *		ならば半直線上に垂線が下りる。
 *	* 直線を線分と見なす場合、垂線が線分上に下りたか判定するには:
 *		daを線分の始点から終点へのベクトルとしてsを求め、
 *			0 <= s && s < 1
 *		ならば線分上に垂線が下りる。
 *	* 実際の位置 q を求めるには: q = a + daｓ より、
 *		s = point_to_line_s(p, a, da);
 *		vector_mul_1(das, da, s);
 *		vector_add(q, a, das);
 *	* 点から直線への距離を求めるには: l = |pq| より、
 *		vector_sub(pq, q, p);
 *		l = vector_magnitude(pq);
 */
float point_to_line_s(const VECTOR* p, const VECTOR* a, const VECTOR* da);

/* ベジェ曲線(の一成分)を計算します。
 * [in]
 *	t	パラメトリック変数(0.0〜1.0)。
 *	Q0	コントロールポイント#0の座標。
 *	Q1	                    #1
 *	Q2	                    #2
 * [out]
 *	戻り値	P(t)の座標値。
 * [note]
 *	* コントロールポイント->アンカーポイントと呼ぶのが正しい? (未確認)
 */
float bezier1(float t, float Q0, float Q1, float Q2);

/* エルミート曲線(の一成分)を計算します。
 * [in]
 *	t	パラメトリック変数(0.0〜1.0)。
 *	Q0	コントロールポイント#0の座標。
 *	Q1	                    #1
 *	Q0d	コントロールポイント#0における接点ベクトル。
 *	Q1d	                    #1
 * [out]
 *	戻り値	P(t)の座標値。
 * [note]
 *	* エルミート曲線は、接点ベクトルの大きさによって変化します。
 *	  つまり、接点ベクトルの大きさにも意味があるため、
 *	  無条件に接点ベクトルを正規化してはいけません。
 *	* この関数は、一成分だけを計算します。
 *	  例えば、3次元曲線に適用する場合は、3回使ってください。
 *	* データとしてコントロールポイントの座標だけがあり、
 *	  接点ベクトルがないときは、次のようにして生成してください。
 *		Qnにおける接点ベクトル = Qn' = a * (Q(n+1) - Q(n-1))
 *		aは任意の定数、0.5前後が一般的? (未確認)
 *	  すなわち、前後の点からベクトルを求め、それに一定割合をかけます。
 *	* 座標=補間対象、接点ベクトル=補間対象の変化率 とみなせば、
 *	  曲線以外にも利用できます。
 */
float hermite1(float t, float Q0, float Q1, float Q0d, float Q1d);

/* 点が図形の内側にあるか外側にあるかを調べます。
 * [in]
 *	px, py		調べる点の座標。
 *	points		図形の頂点リスト。
 *	n_points	頂点の数。
 * [out]
 *	戻り値		内側なら、0以外の値を返します。
 *			外側なら、0        を返します。
 * [note]
 *	* 図形は、凸型だけでなく、凹型にも対応しています。
 *	* 図形の辺が交差する場合、中抜きの図形と見なします。
 *	  XSetFillRules()に例えるならば、EvenOddRuleに相当します。
 *	  WindingRuleでのチェック方法は、現在のところ提供していません。
 */
int point_in_polygon(float px, float py, float points[/*n_points*/][2], int n_points);

/* ２線分の交点を求めます。
 * [in]
 *	(x1   ,y1   )	線分1の始点。
 *	(x1end,y1end)	線分1の終点。
 *	(x2   ,y2   )	線分2の始点。
 *	(x2end,y2end)	線分2の終点。
 *	(px   ,py   )	結果の交点座標を受け取る変数へのポインタ。
 * [out]
 *	戻り値		２線分が交差していたら、1を返します。
 *			２線分が交差していなければ、0を返します。
 *	(*px  , *py )	２線分が交差していたら、交点の座標を格納します。
 *			２線分が交差していなければ、そのままの値を維持します。
 * [note]
 *	* ２線分が交差しているかどうかだけを調べ、交点座標が必要ない場合は、
 *	  pxおよびpyにNULLを指定してください。
 */
int cross_point(float x1, float y1, float x1end, float y1end,
		float x2, float y2, float x2end, float y2end,
		float* px, float* py);

/* 点から線分へ垂線を下ろした位置の、交点座標を求めます。
 * [in]
 *	(x1   ,y1   )	点　の座標。
 *	(x2   ,y2   )	線分の始点。
 *	(x2end,y2end)	線分の終点。
 *	(px   ,py   )	結果の交点座標を受け取る変数へのポインタ。
 * [out]
 *	戻り値		交点が線分上にあれば、1を返します。
 *			交点が線分上になければ、0を返します。
 *	(*px  , *py )	交点が線分上にあれば、交点の座標を格納します。
 *			交点が線分上になければ、そのままの値を維持します。
 * [note]
 *	* 交点が線分上にあるかどうかだけを調べ、交点座標が必要ない場合は、
 *	  pxおよびpyにNULLを指定してください。
 */
int ortho_point(float x1, float y1,
		float x2, float y2, float x2end, float y2end,
		float*px, float* py);

/* 図形の記述が右回りか左回りかを調べます。
 * [in]
 *	points		図形の頂点リスト。
 *	n_points	頂点の数。
 * [out]
 *	戻り値		右回りなら0以外の値を返します。
 *			左回りなら0        を返します。
 * [note]
 *	* 凹型ポリゴンにも対応しています。
 *	* 座標系は、右方向にX+、上方向にY+とします。
 *	  そうでない場合、戻り値は逆の意味となります。
 */
int polygon_orient(float points[/*n_points*/][2], int n_points);

/* ｎ乗根を求めます。
 * [in]
 *	x, n		n√x
 * [out]
 *	戻り値		xのｎ乗根を返します。
 * [note]
 *	* 本当は、標準Ｃライブラリのpow()関数を使って「pow(x,1/n)」とするだけで、
 *	  ｎ乗根が求められるのですが、二つの理由により関数を定義しました。
 *	* 理由１：P/ECE付属ライブラリのpow()関数は動作が怪しい。(->clipstd.h参照)
 *	          clipstd.hでpow()を再定義して回避していますが、念のためです。
 *	* 理由２：僕がｎ乗根を計算する方法を忘れないように(^^; こっちが本当の目的。
 *	* 関数名は、
 *	    技術計算用Ｃプログラムソース(http://www5.airnet.ne.jp/tomy/cpro/csource.htm)
 *	    -> 多倍長浮動小数点演算ライブラリ(http://www5.airnet.ne.jp/tomy/cpro/mpa.htm)
 *	    -> 指数・対数・べき乗関数ルーチン(http://www5.airnet.ne.jp/tomy/cpro/mp8.htm)
 *	  に由来します。
 */
float x1n(float x, float n);

/*****************************************************************************
 *	整数演算ユーティリティ
 *****************************************************************************/

/* 32ビット符号なし整数の平方根を求めます。
 * [in]
 *	a		平方根を求める値。
 * [out]
 *	戻り値		平方根。
 * [note]
 *	* 引数aに負値を指定してはいけません。
 *	  引数aに負値を指定した場合の結果は、無意味な値となります。
 *	* 戻り値は、0x0000〜0xffffの範囲です。
 *	  引数aに0xffff^2以上の値を指定しても、結果は0xffffとなります。
 */
int sqrt_32(int a);

/* うるう年を判定します。
 * [in]
 *	year		年(西暦4桁で指定。2002など)
 * [out]
 *	戻り値		指定された年がうるう年なら1、
 *			うるう年でなければ0を返します。
 */
int leapyear(int year);

/* ツェラーの公式を使って、年月日から曜日を求めます。
 * [in]
 *	year		年(1583〜3999)
 *	month		月(1〜12)
 *	day		日(1〜31)
 * [out]
 *	戻り値		曜日(0:日/1:月/2:火/3:水/4:木/5:金/6:土)
 * [note]
 *	* ツェラーの公式の有効範囲は、1583年〜3999年までです。
 *	  (厳密には、1582年10月15日以降です。)
 *	  この範囲外を指定した場合、間違った結果が返されます。
 */
int dayofweek(int year, int month, int day);

/*****************************************************************************
 *	浮動小数演算ユーティリティの整数バージョン
 *****************************************************************************/

/* 浮動小数演算ユーティリティの一部について、整数バージョンも用意しました。
 * 基本的に、元のコードをコピーして、float->intに置き換えただけです。
 * 引数や戻り値については、浮動小数バージョンの説明を参照してください。
 * 浮動小数バージョンを修正した場合は、整数バージョンも追従させてください。
 */

int point_in_polygon_32(int px, int py, int points[/*n_points*/][2], int n_points);

int cross_point_32(int x1, int y1, int x1end, int y1end,
		   int x2, int y2, int x2end, int y2end,
		   int* px, int* py);

int ortho_point_32(int x1, int y1,
		   int x2, int y2, int x2end, int y2end,
		   int*px, int* py);

/****************************************************************************
 *	三角関数の固定小数版（8.8ビット）
 ****************************************************************************/

/* 正弦値を求めます。
 * [in]
 *	dir		角度（-π:-0x80〜0x7f:π）注意！固定小数部はありません！
 *			bit7〜0以外は無視されるので、範囲外の値でも大丈夫です。
 * [out]
 *	戻り値		正弦値（-0x100〜0x100、小数部8ビット）
 */
int sin_16(int dir);

/* 余弦値を求めます。
 * [in]
 *	dir		角度（-π:-0x80〜0x7f:π）注意！固定小数部はありません！
 *			bit7〜0以外は無視されるので、範囲外の値でも大丈夫です。
 * [out]
 *	戻り値		余弦値（-0x100〜0x100、小数部8ビット）
 */
int cos_16(int dir);

/* (0,0)から(x,y)への角度を求めます。
 * [in]
 *	(y,x)		任意の座標値。(x,y)ではなく(y,x)の順であることに注意！
 * [out]
 *	戻り値		角度（-π:-0x80〜0x7f:π）注意！固定小数部はありません！
 */
int atan2_16(int y, int x);

#endif /*__CLIP_MATH_H__*/
