/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 *  @file curve.h
 */
#if !defined(__MGCALC_CURVE_H__)
#define __MGCALC_CURVE_H__

class MGCurve;
class MGFSurface;
class MGLBRep;
class MGLBRepEndC;
class MGLoop;
class MGPlane;
class MGPosition;
class MGRLBRep;
class MGSSisects;
class MGStraight;
class MGVector;

namespace mgcalc{

	/**
	 *  @brief  2曲線の端点間を結ぶ曲線をブレンドによって生成する。
	 *          curve1のparameter t1に近い端点とcurve2のparameter t2に近い端点を結ぶ
	 *  @param  curve1  start point side
	 *  @param  curve2  end point side
	 *  @param  t1      // parameter of curve1 that is near to the blend point
	 *  @param  t2      // parameter of curve2 that is near the end point
	 *  @param  r1      // tangent magnitude at the curve1 point
	 *  @param  r2      // tangent magnitude at the curve2 point
	 */
	std::unique_ptr<MGCurve> blend(
		const MGCurve& curve1, 
		const MGCurve& curve2, 
		double t1,   // parameter of curve1 that is near to the blend point
		double t2,   // parameter of curve2 that is near the end point
		double r1,   // tangent magnitude at the curve1 point
		double r2    // tangent magnitude at the curve2 point
	);

	/**
	 *  @brief  2曲線の3次元合成
	 *  @param  curve1  曲線その1
	 *  @param  curve2  曲線その2
	 *
	 *  どちらかの曲線が平面曲線ではないとき、スイープできないため失敗する。
	 */
	MGSSisects compose_3D(const MGCurve& curve1, const MGCurve& curve2);

	/**
	 *  @brief  曲線を端点で接続する
	 *  @param  curve1  曲線その1
	 *  @param  curve2  曲線その2
	 *
	 *  composite curve は極力返さないようにしてある。
	 */
	std::unique_ptr<MGCurve> connect(const MGCurve& curve1, const MGCurve& curve2);

	/**
	 *  @brief  曲線をポリラインに変換する
	 *  @param  curve  コンバートする曲線
	 *  @param  azero  角度許容誤差
	 *  @param  lzero  許容誤差
	 */
	std::unique_ptr<MGCurve> convert_to_polyline(
		const MGCurve& curve,
		double         azero,
		double         lzero
		);

	/**
	 *  @brief  ループのワールドカーブをオブジェクト化する
	 *  @param  loop  既存の face の ループ
	 */
	std::unique_ptr<MGCurve> create_curve(const MGLoop& loop);

	/**
	 *  @brief  制御点を与えて曲線を生成
	 *  @param  cv      制御点列
	 *  @param  degree  次数
	 *  @param  close   閉曲線にするかどうか, close=trueが入力されたとき終点＝始点と
	 *  @param  sharp   close == true のとき、閉曲線の端点を尖らせてもよいか。
	 *                  要するに内部的には開曲線になる。
	 *  される。
	 */
	std::unique_ptr<MGCurve> create_curve_from_cv(
		const std::vector<MGPosition>& cv,
		int                            degree,
		bool                           close,
		bool                           sharp = false
		);

	// LBRep を作成する際のノットベクトルの対応指定用。
	// Note: uniform は提供しない。
	enum KnotType
	{
		CHORD, ///< 0: 弦
		CHORD_SQRT ///< 1: 弦の平方根
	};

	/**
	 *  @brief Extends a curve.
	 *  @param  curve   original curve
	 *  @param  param   parameter on curve
	 *  @param  length  length of chord
	 *  @param  dk      curvature variation
	 */
	MGCurve* extend(
		const MGCurve& curve,
		double         param,
		double         length,
		double         dk
		);

	/**
	 *  @brief  曲線の一方の端点方向から直線を引く
	 *  @param  curve       曲線オブジェクト
	 *  @param  hint_param  曲線パラメータ
	 *
	 *  @a hint_param が定義域の始点側に近ければ
	 *  始点から伸びる直線を返す。そうでなければ終点から
	 *  伸びる直線を返す。
	 */
	MGStraight* extension(
		const MGCurve& curve,
		double         hint_param
		);

	/**
	 *  @brief  曲線が有限かどうかを判定する。
	 *  @param  curve  テストする曲線
	 *
	 *  curve.param_range() を見るだけ。
	 */
	bool is_finite(const MGCurve& curve);

	/**
	 *  @brief  Returns whether curve is Jordan-curve or not.
	 *  @param  curve  テストする曲線
	 *
	 *  Jordan curve is defined as follows:
	 *  - curve is closed
	 *  - is C2 continuous
	 *  - is planar
	 *  - and does not intersect itself.
	 */
	bool is_jordan(const MGCurve& curve);

	/**
	 *  @brief 曲線が自己交差しているかどうか
	 *  @param  curve  曲線オブジェクト
	 *
	 *  Returns whether curve intersects itself or not.
	 *
	 *  @note  この関数はまだ実装しきれていない。
	 */
	bool is_self_isect(const MGCurve& curve);
	
} // namespace mgcalc

#endif // __MGCALC_CURVE_H__
