/*
 *	cliprgnm.c
 *
 *	領域マップ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Mon Apr 24 21:59:40 JST 2017 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "clip.h"
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
//レジストリから符号無し24bitを読み出す。
static int RgnMap_GetUnsignedValue(const void* pKey, int iName) {
	int iValue = REG_get_value(pKey, iName);
	if(iValue == -1) { DIE(); }	//値が存在しなければエラー停止する。
	return iValue;
}
/*--------------------------------------------------------------------------*/
//レジストリから符号付き24bitを読み出す。
static int RgnMap_GetSignedValue(const void* pKey, int iName) {
	int iValue = RgnMap_GetUnsignedValue(pKey, iName);
	return iValue << 8 >> 8;	//取得した値のbit23を符号拡張して元の値に戻す。
}
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
//座標(x,y)を含む図形を持つ、最初の領域を取得する。
//[in]
//	pIter		イテレータへのポインタ。	RgnMap_FindNext()を使わない場合は、NULLを指定しても構いません。
//	pRgnKey		領域マップのレジストリキー。	=REG_open_key(TBL_RegTbl,RegKey_RgnMap)
//	iRgnMap		領域マップ番号。		RgnMap_*
//	x,y		調べる座標。
//[out]
//	戻り値		領域の名前。(0〜)
//			該当する領域が無ければ-1を返す。
int RgnMap_FindFirst(ST_RgnMap_Iter* pIter/*NULL可*/, const void* pRgnKey, int iRgnMap, int x, int y) {
	//イテレータが指定されていなければ、ダミーのイテレータを使用する。
	ST_RgnMap_Iter _Iter;
	if(!pIter) { pIter = &_Iter; }
	//イテレータを初期化する。
	pIter->pRgnMap = REG_open_key(pRgnKey, iRgnMap);	//調べるRgnMapのレジストリキーを格納する。
	if(!pIter->pRgnMap) { DIE(); }				//調べるRgnMapのレジストリキーが無ければ、エラー停止する。
	pIter->x = x;						//┬調べる座標を格納する。
	pIter->y = y;						//┘
	pIter->iRgnDef = 0;					//次に調べるRgnDefのインデクスを格納する。
	//最初にヒットしたRgnDefの名前,又は,-1を返す。
	return RgnMap_FindNext(pIter);
}
/*--------------------------------------------------------------------------*/
//座標(x,y)を含む図形を持つ、次の領域を取得する。
//[in]
//	pIter		イテレータへのポインタ。	RgnMap_FindNext()を使わない場合は、NULLを指定しても構いません。
//[out]
//	戻り値		領域の名前。(0〜)
//			該当する領域が無ければ-1を返す。
int RgnMap_FindNext(ST_RgnMap_Iter* pIter) {
	int iRgnDefName, iRgnFig, x, y, w, h;
	double dx, dy, dw, dh;
	for(;;) {
		//次に調べるRgnDefを取得する。
		const void* pRgnDef = REG_open_nth_key(pIter->pRgnMap, pIter->iRgnDef, &iRgnDefName);
		if(!pRgnDef) { return -1; }	//もうRgnDefが無ければ-1を返す。
		//↑この順番を逆にしないように注意せよ。
		//↓RgnMap_FindNext()が-1を返した後は何度呼び出されても-1を返し続けたいが、もしこの順番を逆にすると-1を返す度にpIter->iRgnDefが増えてしまい、(まず起こらないとは思うが)pIter->iRgnDefがオーバーフローする危険が有る。
		pIter->iRgnDef++;	//次回のために、次に調べるRgnDefのインデクスを進めておく。もし上で取得したRgnDefに複数のRgnFigが含まれており、その途中のRgnFigにヒットしたとしても、次回は残りのRgnFigは処理しないからです。
		//このRgnDefの各RgnFigについて…
		iRgnFig = 0;
		for(;;) {
			//次に調べるRgnFigを取得する。
			const void* pRgnFig = REG_open_nth_key(pRgnDef, iRgnFig++, NULL);	//ここでは上記のpIter->iRgnDefのような心配は無いので、すぐにiRgnFig++して構わない。
			if(!pRgnFig) { break; }	//もうRgnFigが無ければループを抜ける。
			//このRgnFigのtypeによって…
			switch(REG_get_value(pRgnFig, RgnFig_type)) {
			default:DIE();
			//矩形
			case RgnFigType_rect:
				x = RgnMap_GetSignedValue(  pRgnFig, RgnFig_x);		//┬矩形の左上		符号付き24bit
				y = RgnMap_GetSignedValue(  pRgnFig, RgnFig_y);		//┘
				w = RgnMap_GetUnsignedValue(pRgnFig, RgnFig_w);		//┬矩形の幅と高さ	符号無し24bit
				h = RgnMap_GetUnsignedValue(pRgnFig, RgnFig_h);		//┘
				x = pIter->x - x;					//┬調べる座標を矩形の左上からの相対座標とする。
				y = pIter->y - y;					//┘
				if(((unsigned)x < (unsigned)w) && ((unsigned)y < (unsigned)h)) { return iRgnDefName; }
				break;
			//楕円
			case RgnFigType_oval:
				dx = RgnMap_GetSignedValue(  pRgnFig, RgnFig_x);	//┬楕円の左上		符号付き24bit
				dy = RgnMap_GetSignedValue(  pRgnFig, RgnFig_y);	//┘
				dw = RgnMap_GetUnsignedValue(pRgnFig, RgnFig_w);	//┬楕円の幅と高さ	符号無し24bit
				dh = RgnMap_GetUnsignedValue(pRgnFig, RgnFig_h);	//┘
				dw /= 2.0;						//┬楕円の直径⇒楕円の半径
				dh /= 2.0;						//┘
				dx += dw;						//┬楕円の左上⇒楕円の中心
				dy += dh;						//┘
				dx = pIter->x - dx;					//┬調べる座標を楕円の中心からの相対座標とする。
				dy = pIter->y - dy;					//┘
			//{{幅,又は,高さが0の場合でもゼロ除算にならないようにするために、両辺に((dw*dw)*(dh*dh))を掛けて除算を無くした。
			//	if((((dx * dx) / (dw * dw)) + ((dy * dy) / (dh * dh))) < 1.0) { return iRgnDefName; }	//□参考資料:「円体の内側かどうかの判別」(https://oshiete.goo.ne.jp/qa/8723074.html)
			//↓幅,又は,高さが0の場合でもゼロ除算にならないようにするために、両辺に((dw*dw)*(dh*dh))を掛けて除算を無くした。
				if((((dx * dx) * (dh * dh)) + ((dy * dy) * (dw * dw))) < ((dw * dw) * (dh * dh))) { return iRgnDefName; }
			//}}幅,又は,高さが0の場合でもゼロ除算にならないようにするために、両辺に((dw*dw)*(dh*dh))を掛けて除算を無くした。
				break;
			//多角形
			case RgnFigType_poly:
				DIE();//※未実装
				break;
			}
		}
	}
}
