/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
#if !defined(__MGCALC_LINE_H__)
#define __MGCALC_LINE_H__

#include <algorithm>
#include <utility>
#include <vector>
#include "mg/LBRep.h"

class MGCurve;
class MGPosition;
class MGStraight;
class MGVector;

namespace mgcalc{
	/**
	 *  @brief  線分を生成する
	 *  @param  ref       参照点
	 *  @param  end       終点
	 *  @param  bothside  @a ref を線分の中点とみなすかどうか
	 *
	 *
	 *  @a bothside が true のときには、生成される直線は
	 *  始点を 2 * @a end - @a ref, 終点を end に持つ線分を返す。
	 *  false のときには、@a ref を始点、@a end を終点に持つ線分を返す。
	 */
	std::unique_ptr<MGCurve> create_line(
		const MGPosition& ref,
		const MGPosition& end,
		bool              bothside
		);

	/**
	 *  @brief  曲線の端点における直線的延長部分を生成する
	 *  @param  curve     曲線
	 *  @param  param     曲線のパラメータ
	 *  @param  hint      延長部分の終点付近の点
	 *  @param  bothside  端点を生成する線分の中点とするか始点とするか
	 *
	 *  曲線の端点における接線上にある線分を生成する。
	 *  端点の選択は @a param が始点、終点のどちらかに近いかによって決まる。
	 *  
	 *  @a param が @a curve の定義域内にないとき、失敗する。
	 *  @a hint が @a param によって決まる @a curve の端点と一致するとき、失敗する。
	 */
	std::unique_ptr<MGCurve> create_line_by_extension(
		const MGCurve&    curve,
		double            param,
		const MGPosition& hint,
		bool              bothside
		);

	/**
	 *  @brief  曲線の垂線を生成する
	 *  @param  curve  曲線
	 *  @param  pos    曲線外の点
	 *  @param  bothside  @a pos が線分の中点(true)か始点(false)かを示す
	 *
	 *  @a pos が @a curve の上に乗っているとき、この関数は失敗する。
	 */
	std::unique_ptr<MGCurve> create_perp_line(
		const MGCurve&    curve,
		const MGPosition& pos,
		bool              bothside
		);

	/**
	 *  @brief  曲線の垂線と垂線の足における接線を返す
	 *  @param  curve     曲線
	 *  @param  end       曲線外の点
	 *  @param  bothside  垂線の足が線分の中点(true)か始点(false)かを示す
	 *
	 *  @a end が @a curve の上に乗っているとき、この関数は失敗する。
	 *  戻り値のペアの first 成分が垂線、second 成分が接線である。
	 *
	 */
	std::pair<MGCurve*, MGCurve*> create_perp_line_ex(
		const MGCurve&    curve,
		const MGPosition& end,
		bool              bothside
		);

	/**
	 *  @brief  円に外接する正 N 角形を生成
	 *  @param  center  円の中心
	 *  @param  normal  円の乗る平面の法線方向
	 *  @param  N       何角形か
	 *  @param  mid     V[0] と V[N-1] の中点
	 */
	std::unique_ptr<MGCurve> create_polygon_cir(
		const MGPosition& center,
		const MGVector&   normal,
		int               N,
		const MGPosition& mid
		);

	/**
	 *  @brief  ひとつの辺を指定して正 N 角形を生成
	 *  @param  edge0   一辺
	 *  @param  normal  正多角形の乗る平面の法線方向
	 *  @param  N       何角形か
	 */
	std::unique_ptr<MGCurve> create_polygon_edge(
		const MGStraight& edge0,
		const MGVector&   normal,
		int               N
		);

	/**
	 *  @brief  円に内接する正 N 角形を生成
	 *  @param  center  円の中心
	 *  @param  normal  円の乗る平面の法線方向
	 *  @param  N       何角形か
	 *  @param  V0      多角形の最初の頂点
	 */
	std::unique_ptr<MGLBRep> create_polygon_ins(
		const MGPosition& center,
		const MGVector&   normal,
		int               N,
		const MGPosition& V0
		);

	/**
	 *  @brief  星型多角形を生成する
	 *  @param  center     円の中心
	 *  @param  normal     円の乗る平面の法線方向
	 *  @param  N          何角形か
	 *  @param  V0         多角形の最初の頂点
	 *  @param  radius2nd  もうひとつの多角形の乗る円周の半径
	 *
	 *  うまくいけば (2*N) 角形が生成される。
	 */
	std::unique_ptr<MGLBRep> create_polygon_star(
		const MGPosition& center,
		const MGVector&   normal,
		int               N,
		const MGPosition& V0,
		double            radius2nd
		);

	/**
	 *  @brief  ポリライン(折れ線)を生成
	 *  @param  pos  通過点のリスト
	 */
	std::unique_ptr<MGLBRep> create_polyline(const std::vector<MGPosition>& pos);
	
	/**
	 *  @brief same as create_polyline except that create_closed_polyline adds the
	 *  additional line segment from pos[n-1] to pos[0].
	*/
	std::unique_ptr<MGLBRep> create_closed_polyline(const std::vector<MGPosition>& pos);

	/**
	 *  @brief  曲線上の接線を無限直線として生成する
	 *  @param  curve  曲線
	 *  @param  param  曲線のパラメータ
	 *
	 *  @a param が @a curve の定義域外の値であるとき、失敗する。
	 *
	 *  @note  無限直線といっても、実際にはパラメータ域を
	 *  大きくしているだけで、一時描画用に使うためのものである。
	 */
	std::unique_ptr<MGCurve> create_tangent_line(
		const MGCurve& curve,
		double         param
		);

	/**
	 *  @brief  曲線上の接線を、終点に近い点を指定して生成
	 *  @param  curve  曲線
	 *  @param  param  曲線のパラメータ
	 *  @param  hint   曲線上にない点
	 *  @parab  bothside  @a param における点が中点か始点かを示す
	 *
	 *  @param における接線を生成し、@a hint を正射影して切断する。
	 */
	std::unique_ptr<MGCurve> create_tangent_line(
		const MGCurve&    curve,
		double            param,
		const MGPosition& hint,
		bool              bothside
		);

	/**
	 *  @brief  与えられた4点を通過するポリラインを生成する。
	 *  @param  A  位置
	 *  @param  B  位置
	 *  @param  C  位置
	 *  @param  D  位置
	 *
	 *  関数名に 'rectangular' とあるが、別に長方形でなくてもよい。
	 */
	std::unique_ptr<MGLBRep> rectangular_line(
		const MGPosition& A,
		const MGPosition& B,
		const MGPosition& C,
		const MGPosition& D 
		);
	
} // namespace mgcalc

#endif // __MGCALC_LINE_H__
