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

/**
 * @file Rect3PTool.cpp
 * @brief MGRect3PTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/LBRep.h"
#include "mgGL/SysGL.h"
#include "topo/Face.h"
#include "Calc/surface.h"
#include "Calc/line.h"
#include "fugenView.h"
#include "SurfCmd/Rect3PTool.h"

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

// MGRect3PToolBase

MGRect3PToolBase::MGRect3PToolBase(fugenDoc* pDoc, int nCmdID)
: MGLocateState(pDoc,nCmdID,LINE_RUBBER,POINT_IPDRAW){
}

//Build rectangle's 4 corner points in corners.
void buildRectPointsFrom3Points(
	const MGPosition& P0,///< 1st corner data
	const MGPosition& P1,///< 2nd corner data
	const MGPosition& P2,///< 3rd point data
	MGPosition corners[4]
){
	corners[0] = P0;
	corners[1] = P1;

	MGVector P01 = P1-P0, P02 = P2-P0;
	MGVector HP = P02 - ((P02 % P01) / (P01 % P01)) * P01;
	corners[2] = P1 + HP;
	corners[3] = P0 + HP;
}

void MGRect3PToolBase::do_make_temporary_display(mgSysGL& sgl,fugenView*){
	const LInfoVec& linfos=locates();
	size_t n=linfos.size();
	if(n == 2){
		const MGPosition& A = linfos[0]->point_world();
		const MGPosition& B = linfos[1]->point_world();
		const MGPosition& P = cursor();
		if(B == P || A == P) return;

		MGPosition corners[4];
		buildRectPointsFrom3Points(A,B,P,corners);

		MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
		sgl.drawPolyline(4,corners,true);
	}
}

bool MGRect3PToolBase::OnLocated(const MGLocateInfo& info){
	const LInfoVec& linfos=locates();
	switch(linfos.size()){
		case 1:setDrawerRubber(LINE_RUBBER); break;
		case 2:setDrawerRubber(NO_RUBBER); break;
		case 3:{
			const MGPosition& P0 = linfos[0]->point_world();
			const MGPosition& P2 = linfos[2]->point_world();
			if(P0 == P2){
				cancel_last_locate();
				setDrawerRubber(NO_RUBBER);
				break;
			}
			make_model();
			return OnCommandEnd(1); // コマンド終了
		}
		default:;
	}
	return false;
}

void MGRect3PToolBase::prompt_message() const{
	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_RECT_EDGE_START);
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_RECT_EDGE_END);
		break;
	case 2:
		SetStatusMessage(IDS_PROMPT_RECT_EDGE_BEYOND);
		break;
	}
}

/////////////////////////////////////////////////////////////////////////
// class MGRectFace3PTool

MGRectFace3PTool::MGRectFace3PTool(fugenDoc* pDoc)
: MGRect3PToolBase(pDoc, ID_SURFACE_RECT_3POINTS){
}

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

void MGRectFace3PTool::make_model(){
	const LInfoVec& linfos=locates();
	const MGPosition& A = linfos[0]->point_world();
	const MGPosition& B = linfos[1]->point_world();
	const MGPosition& P = linfos[2]->point_world();
	if(A == B || B == P || A == P){
		// cancel
		return;
	}

	MGPosition corners[4];
	buildRectPointsFrom3Points(A,B,P,corners);

	std::unique_ptr<MGFace> f = mgcalc::rectangular_face(corners);
	add_object_to_current_group(f.release());
}

/////////////////////////////////////////////////////////////////////////
// class MGPlane3PTool

MGPlane3PTool::MGPlane3PTool(fugenDoc* pDoc)
: MGRect3PToolBase(pDoc, ID_SURFACE_PLANE_3POINTS){
}

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

void MGPlane3PTool::make_model(){
	const LInfoVec& linfos=locates();
	const MGPosition& A = linfos[0]->point_world();
	const MGPosition& B = linfos[1]->point_world();
	const MGPosition& P = linfos[2]->point_world();
	if(A == B || B == P || A == P){
		// failed
		return;
	}

	MGPosition corners[4];
	buildRectPointsFrom3Points(A,B,P,corners);

	const MGPosition& C=corners[2];
	MGUnit_vector U(B-A),V,W;
	U.orthonormal(C-B,V,W);
	std::unique_ptr<MGPlane> rect(new MGPlane(U,V,(A+C)*.5));
	add_object_to_current_group(rect.release());
}
