//
//	cliprgnm.cs
//
//	領域マップ
//
//	CLiP - Common Library for P/ECE
//	Copyright (C) 2017 Naoyuki Sawa
//
//	* Wed Apr 26 21:33:29 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数、構造体
		//*****************************************************************************
		//RgnFigに属する値の名前
		public const int RgnFig_type		= 1;	//RgnFigの種類		RgnFigType_*
		public const int RgnFig_x		= 2;	//┬RgnFigの左上の座標	符号付き24bit	┐
		public const int RgnFig_y		= 3;	//┘					│RgnFigの種類によって、使用するフィールドや解釈を変えて構いません。
		public const int RgnFig_w		= 4;	//┬RgnFigの幅と高さ	符号無し24bit	│現在の所はrectとovalしか無いので同じですが、今後は上記の通りです。
		public const int RgnFig_h		= 5;	//┘					┘
		//RgnFig_typeの値
		public const int RgnFigType_rect	= 1;	//矩形{x,y,w,h}
		public const int RgnFigType_oval	= 2;	//楕円{x,y,w,h}
		public const int RgnFigType_poly	= 3;	//多角形		※未対応
		//-----------------------------------------------------------------------------
		//イテレータ
		public struct ST_RgnMap_Iter {
			public VoidPtr		pRgnMap;	//調べるRgnMapのレジストリキー
			public int		x, y;		//調べる座標
			public int		iRgnDef;	//次に調べるRgnDefのインデクス
		}
		//*****************************************************************************
		//	ローカル関数
		//*****************************************************************************
		//レジストリから符号無し24bitを読み出す。
		private static int RgnMap_GetUnsignedValue(VoidPtr pKey, int iName) {
			int iValue = REG_get_value(pKey, iName);
			if(iValue == -1) { throw new ApplicationException(); }	//値が存在しなければエラー停止する。
			return iValue;
		}
		//-----------------------------------------------------------------------------
		//レジストリから符号付き24bitを読み出す。
		private static int RgnMap_GetSignedValue(VoidPtr pKey, int iName) {
			int iValue = RgnMap_GetUnsignedValue(pKey, iName);
			return iValue << 8 >> 8;	//取得した値のbit23を符号拡張して元の値に戻す。
		}
		//*****************************************************************************
		//	グローバル関数
		//*****************************************************************************
		//座標(x,y)を含む図形を持つ、最初の領域を取得する。
		public static int RgnMap_FindFirst(out ST_RgnMap_Iter pIter, VoidPtr pRgnKey, int iRgnMap, int x, int y) {
			//イテレータを初期化する。
			pIter.pRgnMap = REG_open_key(pRgnKey, iRgnMap);			//調べるRgnMapのレジストリキーを格納する。
			if(!pIter.pRgnMap) { throw new ApplicationException(); }	//調べるRgnMapのレジストリキーが無ければ、エラー停止する。
			pIter.x = x;							//┬調べる座標を格納する。
			pIter.y = y;							//┘
			pIter.iRgnDef = 0;						//次に調べるRgnDefのインデクスを格納する。
			//最初にヒットしたRgnDefの名前,又は,-1を返す。
			return RgnMap_FindNext(ref pIter);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static int RgnMap_FindFirst(VoidPtr pRgnKey, int iRgnMap, int x, int y) {
			ST_RgnMap_Iter pIter;	//ダミー
			return RgnMap_FindFirst(out pIter, pRgnKey, iRgnMap, x, y);
		}
		//-----------------------------------------------------------------------------
		//座標(x,y)を含む図形を持つ、次の領域を取得する。
		public static int RgnMap_FindNext(ref ST_RgnMap_Iter pIter) {
			int iRgnDefName, iRgnFig, x, y, w, h;
			double dx, dy, dw, dh;
			for(;;) {
				//次に調べるRgnDefを取得する。
				VoidPtr pRgnDef = REG_open_nth_key(pIter.pRgnMap, pIter.iRgnDef, out 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を取得する。
					VoidPtr pRgnFig = REG_open_nth_key(pRgnDef, iRgnFig++);		//ここでは上記のpIter.iRgnDefのような心配は無いので、すぐにiRgnFig++して構わない。
					if(!pRgnFig) { break; }	//もうRgnFigが無ければループを抜ける。
					//このRgnFigのtypeによって…
					switch(REG_get_value(pRgnFig, RgnFig_type)) {
					default:throw new ApplicationException();
					//矩形
					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(((uint)x < (uint)w) && ((uint)y < (uint)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:
						throw new ApplicationException();//※未実装
					}
				}
			}
		}
	}
}
