/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
// distance.h
// declaraion for functions about distance measure
#if !defined( __DISTANCE_H__)
#define __DISTANCE_H__

class MGPoint;
class MGPosition;
class MGCurve;
class MGSurface;
class MGFace;
class MGShell;
class MGObject;

namespace mgcalc{
	namespace detail{
		// Measures the distance between two points.
		// lp : point on lhs
		// rp : point on rhs
		// that d(lhs, rhs) == d(lp, rp).
		bool distance_aux(const MGPoint& lhs, const MGPoint& rhs, MGPosition& lp, MGPosition& rp);

		// Measures the distance between a point and a curve.
		// pos1 : equal to p
		// pos2 : point on c
		// that d(p, c) == d(pos1, pos2).
		bool distance_aux(const MGPoint& p, const MGCurve& c, MGPosition& pos1, MGPosition& pos2);

		// Measures the distance between two curves.
		// lp : point on lhs
		// rp : point on rhs
		// that d(lhs, rhs) == d(lp, rp).
		bool distance_aux(const MGCurve& lhs, const MGCurve& rhs, MGPosition& lp, MGPosition& rp);

		// Measures the distance between a curve and a surface.
		bool distance_aux(const MGCurve& c, const MGSurface& surf, MGPosition& pos1, MGPosition& pos2);

		// Measures the distance between a curve and a surface.
		bool distance_aux(const MGCurve& c, const MGFace& f, MGPosition& pos1, MGPosition& pos2);

		// Measures the distance between a point and a shell.
		// pos1 : equal to pnt
		// pos2 : point on she
		// that d(pnt, she) == d(pos1, pos2).
		bool distance_aux(const MGPoint& pnt, const MGShell& she, MGPosition& pos1, MGPosition& pos2);

		// Measures the distance between a point and a surface or face.
		// pos1 : equal to pnt
		// pos2 : point on surface or face
		// that d(pnt, srf) == d(pos1, pos2).
		template<typename T>
		bool distance_aux(const MGPoint& pnt, const T& srf, MGPosition& pos1, MGPosition& pos2){
			pos1 = pnt.position();
			pos2 = srf.eval(srf.closest(pos1));
			return true;
		}

		// 片方は点オブジェクトとわかっているときの
		// 距離計測関数呼び出しの振り分け
		bool distance_dispatch(const MGPoint& p, const MGObject& o, MGPosition& pos1, MGPosition& pos2);

		template<typename T>
		bool distance_dispatch(const T& other, const MGObject& o, MGPosition& pos1, MGPosition& pos2){
			if(const MGPoint* p = o.point()){
				return distance_aux(*p, other, pos2, pos1);
			}else{
				return false;
			}
		}
	}

	// Measures the distance between obj1 and obj2.
	bool distance(
		const MGObject& obj1,
		const MGObject& obj2,
		double& d,             // the distance is output
		MGPosition& pos1,      // the position on obj1
		MGPosition& pos2       // the position on obj2 that d(obj1, obj2) == d(pos1, pos2).
		);

	// distance() 関数はMGObjectの最短距離を計算する関数である
	// 距離とオブジェクト上の位置を返す
	//
	// そのために内部では型キャストを2回行うが
	// キャストする部分を関数化したものが distance_dispatch() ファミリーである
	//
	// キャストして型が判明した後、適切な distance_aux() が呼び出される
}

#endif //__DISTANCE_H__
