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

/**
 * @file CPlaneUtil.cpp
 * @brief CPlaneUtil.h の実装
 */
#include "stdafx.h"
#include "mgGL/SysGL.h"
#include "mgGL/ConstructionPlane.h"
#include "Undo/IPlaneActionTarget.h"
#include "Undo/PlaneAction.h"
#include "fugenView.h"
#include "ViewCmd/CPlaneUtil.h"

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

#define AXIS_LENGTH .1
//Draw a temporal construction plane.
//The cplane to draw is the plane whose origin is org, and...
void PreviewCPlane(
	mgSysGL& sgl,
	const MGConstructionPlane& cplane,//Input the old cplane, whose origin and attributes
		//are used to draw the new construction plane.
	const MGPosition& org,
	const MGVector& xDir,
	const MGVector& yDir,
	const MGColor* zColor,
		//Indicates if the normal line from the origin is necessary to draw.
		//If zColor!=nullptr, draw the line with the color zColor.
	bool draw_displacement
		//Indicates if the line from cpl.origin() to org is necessary to draw.
		//If draw_displacement is true, draw the displacement line.
){
	if(draw_displacement){
		// 現在の作業平面原点からカーソル位置までの変位を描画する。
		sgl.Begin(GL_LINES);
			MGColor::get_instance(MGColor::White).exec(sgl);
			sgl.Vertex3dv(cplane.plane().center().data());
			sgl.Vertex3dv(org.data());
		sgl.End();
	}

	double ulen = cplane.uspan() * cplane.unum()*AXIS_LENGTH;
	double vlen = cplane.uspan() * cplane.vnum()*AXIS_LENGTH;
	MGVector U=xDir.normalize();
	MGPosition uend=org+U*ulen;
	MGVector V=yDir.normalize();
	MGPosition vend=org+V*vlen;


// 線分で作業平面のプレビューを表現する。
	// 作業平面の軸の太さを設定
	sgl.LineWidth(2.0);
	MGColor clU, clV, dummy;
	cplane.get_colors(dummy, clU, clV);

	// 作業平面の X 軸を描画する。
	sgl.Begin(GL_LINES);
	clU.exec(sgl);
	sgl.Vertex3dv(org.data());
	sgl.Vertex3dv(uend.data());
	sgl.End();

	// 作業平面の Y 軸を描画する。
	sgl.Begin(GL_LINES);
	clV.exec(sgl);
	sgl.Vertex3dv(org.data());
	sgl.Vertex3dv(vend.data());
	sgl.End();

	if(zColor){
		// Draw the Z axis of the temporal cplane.
		double zlen=(ulen+vlen)*.5;
		MGVector newNormal=U*V;
		MGPosition Z=org+newNormal*zlen;
		zColor->exec(sgl);
		sgl.drawOpenPolyline(&org,&Z,nullptr);
	}
}

/// CPlane 編集用補助関数
/// @param[in,out] pTarget 編集対象の作業平面を持つ何か。
/// @param[in] uderi 作業平面のU方向
/// @param[in] vderi 作業平面のV方向
/// @param[in] origin 作業平面の原点
void ExecPlaneAction(
	IPlaneActionTarget* pTarget,
	const MGVector& uderi,
	const MGVector& vderi,
	const MGPosition& origin
){
	MGPlane plNew(uderi.normalize(), vderi.normalize(), origin);
	CPlaneAction* act = new CPlaneAction(pTarget, plNew);
	act->SetOldPlane(pTarget->GetCPlane().plane());
	act->Do();
}

void ExecPlaneAction(
	IPlaneActionTarget* pTarget,
	const MGPlane& plNew
){
	CPlaneAction* act = new CPlaneAction(pTarget, plNew);
	act->SetOldPlane(pTarget->GetCPlane().plane());
	act->Do();
}

void execCPlaneTranslateAction(
		fugenView* view,
		const MGPosition& toPoint
){
	MGConstructionPlane& cplaneOld=view->cplane();
	MGPlane newPlane=cplaneOld.plane();
	const MGPosition& old = newPlane.center();
	newPlane += (toPoint - old); // translation of the origin

	CPlaneAction* act = new CPlaneAction(view, newPlane);
	act->SetOldPlane(view->GetCPlane().plane());
	act->Do();
}

/// Get the rotation angle from axes[(rotation_axis+1)%3] to the vector
/// (crsr-orign) around the normal axes[rotation_axis].
double getAngleUAxis(
	const MGPosition& crsr,	//Input the cursor position
	const MGPosition origin,
	const MGVector& Xaxis,
	const MGVector& normal
){
	MGVector toCursor=crsr-origin;
	//Obtain the vector projected to the (Xaxis, and Yaxis).
	//Here Xaxis=m_axes[m_rotation_axis+1], Yaxis=m_axes[m_rotation_axis+2].
	toCursor=toCursor.orthogonize(normal);//toCursor is the projected cursor() to (Xaxis, Yaxis) plane.
	return Xaxis.angle2pai(toCursor,normal); //angle of the rotation.
}

/// Get the rotation angle from axes[(rotation_axis+1)%3] to the vector
/// (crsr-orign) around the normal axes[rotation_axis].
double getAngleUAxis(
	const MGPosition& crsr,	//Input the cursor position
	const MGPosition origin,
	int rotation_axis,
	const MGVector axes[3]
){
	const MGVector& Xaxis=axes[(rotation_axis+1)%3];
	const MGVector& normal=axes[rotation_axis];//Rotation axis.
	return getAngleUAxis(crsr,origin,Xaxis,normal);
}
