#include <stdio.h>
#include <eggx.h>

// ============================ EGGX

int win;

#define WW (600)
#define HH (600)


// ========================== 二線分の交差チェック
/*
 http://www.hiramine.com/programming/graphics/2d_segmentintersection.html
 を参考に。
 線分 AB (ax,ay)-(bx,by) と CD (cx,cy)-(dx,dy) が交差しているかどうかを調べる
 r, s が共に 0-1 の間にあれば衝突と判定
 ただし、
 戻り値は衝突時は r そのもの。範囲は 0.0 <= r <= 1.0 である。
 非衝突時は 9.0 を返す。
 ただし、二線分が並行な場合は 99.0 であり、
 二線分が同一（重なっている）の場合は 999.0 を返す
 この r を用いて交差座標位置を求める
 */

#define NOCROSS  9.0
#define PARALLEL 99.0
#define DOUBLE   999.0

float colCheck(float ax, float ay,
			   float bx, float by,
			   float cx, float cy,
			   float dx, float dy)
{
	float denom; // 途中計算における分母(denominator)
	float acx, acy; // ベクター AC を表現する
	float r, s;
	
	denom = (bx - ax) * (dy - cy) - (by - ay) * (dx - cx);
	if( denom == 0.0 ) return PARALLEL; // 二線は並行である

	// ベクター AC を得る（C - A にあたる） 
	acx = cx - ax; acy = cy - ay;
	
	r=( ( dy - cy ) * acx - ( dx - cx ) * acy ) / denom;
	s=( ( by - ay ) * acx - ( bx - ax ) * acy ) / denom;
	
	if( (r == 0.0)&&(s == 0.0)) return DOUBLE; // 二線は同一である
	
	if( (0.0 <= r) && (r <= 1.0) && (0.0 <= s) && (s <= 1.0)) {
		return r; // 交差した
	} else {
		return NOCROSS; // 交差しない
	}
		
}

// ========================== 補助サブルーチン群

// 初期設定
void setup(void)
{
	win=gopen(WW, HH);
	winname(win, "Collision test");
	
}

// 終了処理
void closeall(void)
{
	// ggetch(); // quit 関数があるので外す
	gclose(win);
}

// ======================== 座標位置を指定して、交差点を計算させる

#define QUITX (WW*0.3)
#define QUITY (40.0)
#define QUITW (35.0)
#define QUITH (20.0)

int crossPoint(void)
{
	float ax, ay, bx, by, cx, cy, dx, dy;
	float r, isx, isy;
	int code, type;

	// 最初に終了ボタンを出しておく
	newpen(win, 4);
	fillrect(win, QUITX, QUITY, QUITW, QUITH);
	newpen(win, 1);
	drawstr(win, QUITX+2.0, QUITY+2.0, 16, 0.0, "QUIT");

	// まず A, B, C, D の四点の座標位置を指定する
	// A を指定
	do {
		ggetxpress(&type, &code, &ax, &ay);
	} while(type!=ButtonPress);
	//	A ではなく QUIT ボタンを押したかどうかチェック
	if ((QUITX<ax)&&(ax<(QUITX+QUITW))
		&&(QUITY<ay)&&(ay<(QUITY+QUITH))) {
		return 1; // 当該枠内をクリックすれば 1 を返して return
	}
	// 問題なければ画面を消去（終了ボタンを消す）
	gclr(win);
	
	// B を指定
	do {
		ggetxpress(&type, &code, &bx, &by);
	} while(type!=ButtonPress); 
	// 線分 AB を描画
	newpen(win, 1);
	drawline(win, ax, ay, bx, by);

	// C, D を指定して線分 CD を描画
	do {
		ggetxpress(&type, &code, &cx, &cy);
	} while(type!=ButtonPress);
	do {
		ggetxpress(&type, &code, &dx, &dy);
	} while(type!=ButtonPress); 
	newpen(win, 2);
	drawline(win, cx, cy, dx, dy);
	
	// A,B,C,D の位置が決定できたので、交差チェック
	r=colCheck(ax, ay, bx, by, cx, cy, dx, dy);
	if(r >= NOCROSS) { // 交差しなかった
		drawstr(win, 10.0, 10.0, 16, 0.0, "NO CROSS");
		return 0;
	}
	
	// 交差した：交点を AB から求める（A から r ぶんだけ AB 方向に進んだ位置）
	isx = ax + r * ( bx - ax );
	isy = ay + r * ( by - ay );
	// 交点を描画
	newpen(win, 3);
	drawcirc(win, isx, isy, 3.0, 3.0);
	
	return 0;
}

// ============================================ メインルーチン

int main (int argc, const char * argv[]) {
	setup();
	
	gclr(win);
	while(1) {
		if(crossPoint()==1) break;
	}
	
	closeall();
    return 0;
}
