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

// EvalCurveCont.cpp: MGEvalCurveContTool クラスのインプリメンテーション

#include "stdafx.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "mg/CurveContinuity.h"
#include "EvalCmd/EvalCurveCont.h"

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

// MGEvalCurveContTool

MGEvalCurveContTool::MGEvalCurveContTool(fugenDoc* pDoc)
:MGSelectState(pDoc,ID_EVAL_CURVE_CONT,MULTIPLE_SELECT, mgAll_Curve){}

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

bool MGEvalCurveContTool::initiate_tool(){
	MGSelectState::initiate_tool();

	// 選択要素を曲線のみにフィルターする。
	MGPickObjects curves;
	const MGPickObjects& cobjs=current_objects();
	cobjs.select_curves(curves);

	// 現在の選択曲線の個数を調べる。
	// 既に二本選択されていれば、即計算。
	size_t ncurves=curves.size();
	if(ncurves>=2){
		evaluate(curves);
		return OnCommandEnd(1,false);
	}else if(is_breaking_command()){
		return OnCommandEnd(2);
	}

	// 強制的にクリア
	set_current_object(curves);
	set_add_mode();

	// 最初のメッセージ
	prompt_message();
	return false;
}

bool MGEvalCurveContTool::OnSelected(
	fugenView* window,//The fugenView pointer where point input event took place.
	MGPickObjects&	selected_objects,	//selected objects at this selection operation.
	MGPickObjects&	unselected_objects	//unselected objects at this selection operation.
		//unselected_objects.size()>=1 only when the already selected objects are selected
		//when add mode is set(or when operation is done with a crtl key pressed).
){
	const MGPickObjects& curves=current_objects();
	size_t ncurves=curves.size();
	if(ncurves>=2){
		evaluate(curves);
		return OnCommandEnd(1);
	}
	prompt_message();
	return false;
}

void MGEvalCurveContTool::evaluate(
	const MGPickObjects& curves
){
	const MGCurve* curve1 = static_cast<const MGCurve*>(curves[0].top_object());
	const MGCurve* curve2 = static_cast<const MGCurve*>(curves[1].top_object());
	MGCurveContinuity c(*curve1, *curve2);

	CString result;
	const MGPosition& P1=c.P1();
	const MGPosition& P2=c.P2();
	const MGUnit_vector& tan1=c.tan1();
	const MGUnit_vector& tan2=c.tan2();
	const MGUnit_vector& normal1=c.normal1();
	const MGUnit_vector& normal2=c.normal2();

	double crvtr1=c.curvature1(), crvtr2=c.curvature2();
	double radius1=0., radius2=0.;
	if(!MGMZero(crvtr1))
		radius1=1./crvtr1;
	if(!MGMZero(crvtr2))
		radius2=1./crvtr2;

	result.Format(IDS_EVAL_GCON_RESULT, c.get_continuity(),
		P1[0], P1[1], P1[2],
		P2[0], P2[1], P2[2], c.distance(),
		tan1[0], tan1[1], tan1[2],
		tan2[0], tan2[1], tan2[2], MGCL::radian_to_degree(c.tandiff()),
		normal1[0], normal1[1], normal1[2],
		normal2[0], normal2[1], normal2[2], MGCL::radian_to_degree(c.normaldiff()),
		crvtr1, crvtr2,radius1,radius2
	);

	// 出力ウィンドウに出力する。
	putInOutputWindow(result);
}

void MGEvalCurveContTool::prompt_message() const
{
	const MGPickObjects& curves = current_objects();
	const size_t ncurves = curves.size();
	if(ncurves < 2){
		SetStatusMessage(IDS_PROMPT_CURVE_NTH, ncurves + 1);
	}
}
