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

class MGFSurface;
class MGPoint;

namespace mgcalc{
	/**
	 *  @brief 投影演算の処理結果オブジェクトにアクセスするクラス
	 *
	 *  注意点は投影によって生成されたオブジェクトの取得方法について
	 *  だけである。内部的に new されたオブジェクトを管理しているため、
	 *  利用者がそれらを他に回すには、result() 使用後 release() を呼ぶ
	 *  必要がある。
	 */
	class MGProject{
	public:
		using MYELM=std::unique_ptr<MGGel>;
		using MYLST=std::list<MYELM>;

		/**
		 *  @brief  投影データをセットする
		 *  @param  objective  投影先のオブジェクト
		 *  @param  subjective  投影するオブジェクト
		 *  @param  direction  投影方向
		 *
		 *  投影演算に用いる各種データをセットするだけである。
		 *  実際の計算は @c calculate() を呼ぶことで開始する。
		 *
		 *  @note direction を指定しない場合、面直投影を行うことを意味する。
		 *  これは、MGCL の慣習によるものである。
		 */
		MGProject(
			const MGObject* objective,
			const MGObject* subjective,
			const MGVector& direction = mgNULL_VEC
			);

		/**
		 *  @brief  投影計算を行う
		 *
		 *  成功すれば true が戻ってくる。
		 *  投影による生成物を @c result() で参照することができる。
		 */
		bool calculate();

		/// もしあれば、投影方向を返す
		/// なければ零ベクトルを返す
		const MGVector& direction() const{ return m_direction;}

		/// 投影先のオブジェクトを返す
		const MGObject* objective() const{ return m_objective;}

		/// 投影をするオブジェクトを返す
		const MGObject* subjective() const{ return m_subjective;}
		
		///@name 投影結果オブジェクト
		//@{
		MYLST& result(){ return m_result;}
		const MYLST& result() const{ return m_result;}
		//@}

	private:

		// ここから3つのメンバの間には次の関係がある
		// m_result == m_objective->project(m_subjective, m_direction);
		const MGObject* m_objective;
		const MGObject* m_subjective;
		MGVector        m_direction;

		MYLST m_result; // 投影結果

		/// メモリ管理を要するメンバデータを持つため
		/// このメンバ関数は使用禁止
		MGProject(const MGProject&)=delete;
		MGProject& operator=(const MGProject&)=delete;

		//@{
		/// タイプ判明後の投影計算関数
		bool calc_hc(const MGShell* shell, const MGCurve* curve);
		bool calc_sc(const MGFSurface* surf, const MGCurve* curve);
		bool calc_hp(const MGShell* shell, const MGPoint* point);
		bool calc_sp(const MGFSurface* surf, const MGPoint* point);
		//@}

	};
} // mgcalc

#endif //__MGPROJECT_H__
