/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/

/**
 * @file EvalCurveRadius.cpp
 * @brief EvalCurveRadius.h を実装
 */
#include "stdafx.h"
#include "mg/Ellipse.h"
#include "fugenView.h"
#include "Calc/mgcalc.h"
#include "Calc/line.h"
#include "EvalCmd/EvalCurveRadius.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

MGEvalCurveRadiusTool::MGEvalCurveRadiusTool(fugenDoc* pDoc)
: MGLocateState(pDoc, ID_RADIUS, NO_RUBBER, NO_IPDRAW){
	// カーブ系全部
	turn_on_near();
	turn_on_end();
}

///Invoked when command is to terminate as a nomal end.
///display normal end message.
bool MGEvalCurveRadiusTool::OnCommandEnd(
	UINT nIDS,
	bool erase_temporary_display
){
	return MGLocateState::OnCommandEnd(nIDS,false);
}


MGCommandBase* MGEvalCurveRadiusTool::initial_clone(fugenDoc* pDoc)const{
	return new MGEvalCurveRadiusTool(pDoc);
}

bool MGEvalCurveRadiusTool::initiate_tool(){
	MGLocateState::initiate_tool();
	clear_pick_object();
	SetStatusMessage(IDS_PROMPT_EVAL_CURVE_RADIUS);
	return false;
}

bool MGEvalCurveRadiusTool::OnLocated(const MGLocateInfo& info){
	std::unique_ptr<MGEllipse> circle;
	std::unique_ptr<MGCurve> line;
	UpdatePreviewData(circle,line);
	if(!circle.get()){
		return false;
	}
	draw_temporary();

	const double dRadius = circle->radius();
	CString str;
	str.Format(IDS_EVAL_CURVE_RADIUS_RESULT, dRadius);
	putInOutputWindow(str);
	return OnCommandEnd(1,false);
}

/// locate されたcircle と line を求める
void MGEvalCurveRadiusTool::UpdatePreviewData(
		std::unique_ptr<MGEllipse>& circle,
		std::unique_ptr<MGCurve>& line
){
	// いきなりクリア。
	circle.reset(0);
	line.reset(0);

	const MGCurve* pCurve = snappedCurve();
	if(!pCurve){
		return;
	}

	// マウスが最も近い曲線上の点の対応パラメーター
	double dParam = m_located_param[0];

	// 曲率円を計算する。
	MGVector T, N, B;
	double curva, torsion;
	MGPosition pos = pCurve->eval(dParam);
	pCurve->Frenet_frame(dParam, T, N, B, curva, torsion);
	if(MGMZero(curva)){
		return;
	}

	const double dRadius = 1./curva;
	circle.reset(new MGEllipse(pos + N * dRadius, dRadius, B));

	// 接線を作る。
	line.reset(mgcalc::create_line(pos, pos + T * dRadius, true).release());
}

/// マウスカーソル位置の近くに曲線がある場合、
/// 動的に曲線の曲率円を評価し、それを描画する。
void MGEvalCurveRadiusTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	std::unique_ptr<MGEllipse> circle;
	std::unique_ptr<MGCurve> line;
	UpdatePreviewData(circle,line);
	if(!circle.get() || !line.get()){
		return;
	}

	mgcalc::MGDrawObject drawobj(mgcalc::CreateDrawFunctor(sgl));

	// まずは曲率円を描く。
	MGColor::get_instance(MGColor::White).exec(sgl);
	drawobj(circle.get());

	// 次に接線を描く。
	// TODO: ビューの大きさによらず一定の長さとする。
	MGColor::get_instance(MGColor::White).exec(sgl);
	drawobj(line.get());
}
