/* 
* PROJECT: NyARToolkitCPP
* --------------------------------------------------------------------------------
*
* The NyARToolkitCPP is C++ version NyARToolkit class library.
* Copyright (C)2008-2009 Ryo Iizuka
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
* For further information please contact.
*	http://nyatla.jp/nyatoolkit/
*	<airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
* 
*/
#include "NyARCustomSingleDetectMarker.h"
#include "TNyARMatchPattResult.h"
#include "nyarcore.h"

namespace NyARToolkitCPP
{
#define AR_SQUARE_MAX 100

	NyARCustomSingleDetectMarker::NyARCustomSingleDetectMarker()
	{
		//自分でinitInstanceを実行して下さい。
		return;
	}
	NyARCustomSingleDetectMarker::~NyARCustomSingleDetectMarker()
	{
		NyAR_SAFE_DELETE(this->_square_list);
		NyAR_SAFE_DELETE(this->_bin_raster);
		NyAR_SAFE_DELETE(this->_match_patt);
		NyAR_SAFE_DELETE(this->_deviation_data);
		NyAR_SAFE_DELETE(this->_transmat);
		//上からもらったの
		NyAR_SAFE_DELETE(this->_patt);
		NyAR_SAFE_DELETE(this->_square_detect);
		return;
	}
	void NyARCustomSingleDetectMarker::initInstance(
		INyARColorPatt* i_patt_inst,
		INyARSquareDetector* i_sqdetect_inst,
		INyARTransMat* i_transmat_inst,
		const INyARRasterFilter_RgbToBin* i_filter,
		const NyARParam* i_ref_param,
		const NyARCode* i_ref_code,
		double i_marker_width)
	{
		const TNyARIntSize& scr_size=i_ref_param->getScreenSize();		
		// 解析オブジェクトを作る
		this->_square_detect=i_sqdetect_inst;
		this->_transmat=i_transmat_inst;
		this->_tobin_filter=i_filter;
		this->_marker_width = i_marker_width;
		this->_patt = i_patt_inst;
		this->_deviation_data=new NyARMatchPattDeviationColorData(i_ref_code->getWidth(),i_ref_code->getHeight());
		this->_match_patt = new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code);		
		this->_bin_raster=new NyARBinRaster(scr_size.w,scr_size.h);
		this->_square_list=new NyARSquareStack(AR_SQUARE_MAX);
		this->_is_continue = false;
		return;
	}


	bool NyARCustomSingleDetectMarker::detectMarkerLite(const INyARRgbRaster& i_raster)
	{
		//サイズチェック
		if(!this->_bin_raster->getSize().isEqualSize(i_raster.getSize())){
			throw NyARException();
		}

		//ラスタを２値イメージに変換する.
		this->_tobin_filter->doFilter(i_raster,*this->_bin_raster);


		this->_detected_square = NULL;
		NyARSquareStack& l_square_list = *this->_square_list;
		// スクエアコードを探す
		this->_square_detect->detectMarker(*this->_bin_raster, l_square_list);


		int number_of_square = l_square_list.getLength();
		// コードは見つかった？
		if (number_of_square < 1) {
			return false;
		}

		bool result=false;
		TNyARMatchPattResult& mr=this->__detectMarkerLite_mr;
		int square_index = 0;
		int direction = NyARSquare::DIRECTION_UNKNOWN;
		double confidence = 0;
		for(int i=0;i<number_of_square;i++){
			// 評価基準になるパターンをイメージから切り出す
			if (!this->_patt->pickFromRaster(i_raster, *l_square_list.getItem(i))){
				continue;
			}
			//取得パターンをカラー差分データに変換して評価する。
			this->_deviation_data->setRaster(*this->_patt);
			if(!this->_match_patt->evaluate(*this->_deviation_data,mr)){
				continue;
			}
			const double c2 = mr.confidence;
			if (confidence > c2) {
				continue;
			}
			// もっと一致するマーカーがあったぽい
			square_index = i;
			direction = mr.direction;
			confidence = c2;
			result=true;
		}

		// マーカー情報を保存
		this->_detected_square = l_square_list.getItem(square_index);
		this->_detected_direction = direction;
		this->_detected_confidence = confidence;
		return result;
	}


	void NyARCustomSingleDetectMarker::getTransmationMatrix(NyARTransMatResult &o_result)const
	{
		// 一番一致したマーカーの位置とかその辺を計算
		if (this->_is_continue) {
			this->_transmat->transMatContinue(*this->_detected_square,this->_detected_direction,this->_marker_width, o_result);
		} else {
			this->_transmat->transMat(*this->_detected_square,this->_detected_direction,this->_marker_width, o_result);
		}
		return;
	}
	/**
	* 画面上のマーカ頂点情報を配列へ取得します。
	* @param o_point
	* 4要素以上の配列を指定して下さい。先頭の4要素に値がコピーされます。
	*/
	void NyARCustomSingleDetectMarker::getSquarePosition(TNyARIntPoint2d o_point[])const
	{
		for(int i=0;i<4;i++)
		{
			o_point[i]=this->_detected_square->imvertex[i];
		}
		return;
	}
	/**
	* 画面上のマーカ頂点情報を配列へのリファレンスを返します。
	* 返されたオブジェクトはクラスに所有し続けられています。クラスのメンバ関数を実行すると内容が書き変わります。
	* 外部でデータをストックする場合は、getSquarePositionで複製して下さい。
	* @return
	*/
	const TNyARIntPoint2d& NyARCustomSingleDetectMarker::refSquarePosition()const
	{
		return *(this->_detected_square->imvertex);
	}


	/**
	* 検出したマーカーの一致度を返します。
	* 
	* @return マーカーの一致度を返します。0〜1までの値をとります。 一致度が低い場合には、誤認識の可能性が高くなります。
	* @throws NyARException
	*/
	double NyARCustomSingleDetectMarker::getConfidence()const
	{
		return this->_detected_confidence;
	}

	/**
	* 検出したマーカーの方位を返します。
	* 
	* @return 0,1,2,3の何れかを返します。
	*/
	int NyARCustomSingleDetectMarker::getDirection()const
	{
		return this->_detected_direction;
	}

	/**
	* getTransmationMatrixの計算モードを設定します。 初期値はTRUEです。
	* 
	* @param i_is_continue
	* TRUEなら、transMatCont互換の計算をします。 FALSEなら、transMat互換の計算をします。
	*/
	void NyARCustomSingleDetectMarker::setContinueMode(bool i_is_continue)
	{
		this->_is_continue = i_is_continue;
	}


}
