//=======================================================================//
// File:		line.hpp                                                     //
// Project: Architecture                                                 //
// Author:	J.M. Albertson                                               //
//-----------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainments,                //
// PROPRIETARY AND CONFIDENTIAL                                          //
//=======================================================================//

#pragma once

#include "Stuff.hpp"
#include "Point3D.hpp"
#include "UnitVector.hpp"

namespace Stuff {

	class Plane;
	class Sphere;
	class OBB;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Line3D3D ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class Line3D
		#if defined(_ARMOR)
			: public Stuff::Signature
		#endif
	{
	 public:
		Point3D
			m_origin;
		UnitVector3D
			m_direction;
		Scalar
			m_length;

		Line3D()
			{}
		Line3D(
			const Point3D &origin,
			const UnitVector3D &direction,
			Scalar length
		)
		{
			m_origin = origin;
			m_direction = direction;
			m_length = length;
		}

		//
		// projection functions
		//
		void
			Project(
				Scalar length,
				Point3D *result
			)
				{
					Check_Object(this); Check_Object(result);
					Vector3D temp; temp.Multiply(m_direction,length);
					result->Add(m_origin,temp);
				}
		Scalar
			GetLengthToClosestPointTo(const Point3D &point)
				{
					Check_Object(this); Check_Object(&point);
					Vector3D temp; temp.Subtract(point,m_origin);
					Scalar len = temp*m_direction;
					Clamp(len, 0.0f, m_length);
					return len;
				}
		void
			GetClosestPointTo(
				const Point3D &point,
				Point3D *result
			)
				{
					Check_Object(this); Check_Object(result); Check_Object(&point);
					Project(GetLengthToClosestPointTo(point),result);
				}

		//
		// Assignment operators
		//
		Line3D&
			SetDirection(const Vector3D &vector);
		Line3D&
			SetOrigin(const Point3D &point)
				{Check_Pointer(this); m_origin = point; return *this;}

		void
			FindEnd(Point3D *result)
				{Check_Object(this); Check_Pointer(result); Line3D::Project(m_length, result);}
			
		//
		// Intersection functions
		//
		Scalar
			GetDistanceTo(
				const Plane &plane,
				Scalar *product
			) const;
		Scalar
			GetDistanceTo(
				const Sphere &sphere,
				Scalar *penetration
			) const;
		Scalar
			GetDistanceTo(const OBB& box);
		Scalar
			GetDistanceTo(
				const OBB& box,
				int *axis
			);

		//
		// Test support
		//
		void
			TestInstance() const
				{}
	};

	Scalar
		Find_Time_Till_Closest_Approach(
			const Point3D& origin1,
			const Vector3D& velocity1,
			const Point3D& origin2,
			const Vector3D& velocity2
		);

}
