/****************************************************************************************

		TBBox.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Yann
		Date:	4/30/99

		Revision History

		when		who			what & why
		==========	==========	======================================================
		4/30/99		Yann		Creation. Extracted TBBox3D and TBBox2D from PublicUtilities.h/.cpp
								to avoid getting zillions of unneeded stuff

****************************************************************************************/


#ifndef __TBBOX__
#define __TBBOX__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"

/// \addtogroup Data
///
/// \{

///	TBBox2D defines a two dimentional bounding box.
///	It uses two TVector2 to store the lower (#fMin) and the upper (#fMax) corners of the rectangle
///
class TBBox2D : public TMCObject
{
public:

	// ****************************************************************************
	//								TBBox2D
	// 
	/// Default constructor:
	/// #fMin is initialized with kRealMax, #fMax with kRealMin
	/// 
				TBBox2D			();

	// ****************************************************************************
	//								TBBox2D
	// 
	/// Init constructor
	/// 
	/// \param min  initial value for #fMin.
	/// \param max  initial value for #fMax.
	/// 
				TBBox2D			(const TVector2& min, const TVector2& max);

	// ****************************************************************************
	//								TBBox2D
	// 
	/// Init constructor
	/// 
	/// \param max  initial value for #fMax. #fMin is initialized with -max
	/// 
				TBBox2D			(const TVector2& max);

	
	/// Setter function for #fMax
	void		SetMax			(const TVector2& max) {fMax = max;}


	/// Setter function for #fMin
	void		SetMin			(const TVector2& min) {fMin = min;}
	

	// ****************************************************************************
	//								GetCenter
	// 
	/// Computes the center of the box
	/// 
	/// \param center  the return value for the center of the box
	/// 
	void		GetCenter		(TVector2& center) const;
	
	// ****************************************************************************
	//								GetDelta
	// 
	/// Computes the main diagonal of the box (#fMax - #fMin)
	/// 
	/// \param delta  the return value
	/// 
	void		GetDelta		(TVector2& delta) const;

	// ****************************************************************************
	//								GetMax
	// 
	/// Returns the bigger coordinate of the diagonal
	/// 
	real		GetMax			() const;

	// ****************************************************************************
	//								GetMin
	// 
	/// Returns the smaller coordinate of the diagonal
	/// 
	real		GetMin			() const;

	// ****************************************************************************
	//								IsEmpty
	// 
	/// Returns true if the box is empty
	/// 
	boolean		IsEmpty			() const;

	// ****************************************************************************
	//								AddPoint
	// 
	/// Expands the box to encompass the given point
	/// 
	/// \param PP  the point to add to the box
	/// 
	void		AddPoint		(const TVector2 &PP);

	// ****************************************************************************
	//								Inset
	// 
	/// Shrinks the box by adding PP to #fMin, and substracting it from #fMax
	/// 
	/// \param PP  the amount to shrink the box with
	/// 
	void		Inset			(const TVector2 &PP);
	
	// ****************************************************************************
	//								operator[]
	// 
	/// Returns one of the corners of the box
	/// 
	/// \param ii  the corner index (0 => #fMin, 1 => TVector2(#fMax[0], #fMin[1]), 2 => TVector2(#fMin[0], #fMax[1]),
	/// 3 => #fMax, 4 => (#fMax + #fMin)/2. For any other value, returns 0
	/// 
	TVector2	operator[]		(int16 ii) const;


	// ****************************************************************************
	//								FixInvertedFields
	// 
	/// if (#fMin .x > #fMax .x) {#fMin .x = #fMax .x = kRealZero;} and same for y
	/// 
	void		FixInvertedFields();

	
	// ****************************************************************************
	//								IsInside
	// 
	/// Returns true if the point is inside the box.
	/// 
	/// \param point  the point to intersect with the box
	/// 
	boolean		IsInside		(const TVector2& point) const;

	/// Returns true if every coordinate of #fMin is smaller than its #fMax counterpart
	inline boolean Valid		() const 				{ return ((fMin.x <= fMax.x) && (fMin.y <= fMax.y)); }

	// ****************************************************************************
	//								ClipBy
	// 
	/// Clips the box by another box
	/// 
	/// \param clipBounds  the bounds that this box should not cross
	/// 
	void		ClipBy			(const TBBox2D& clipBounds);

	/// Union
	void		Union			(const TBBox2D& box);

	// ****************************************************************************
	//								Intersect
	// 
	/// Returns true if the two boxes intersect
	/// 
	/// \param boundingBox  the box to test for intersection with this box
	/// 
	boolean		Intersect		(const TBBox2D& boundingBox) const;
	
	/// Returns the width (in x) of the box
	inline real GetWidth		( void ) const 			{ return fMax.x - fMin.x; }

	/// Returns the height (in y) of the box
	inline real GetHeight		( void ) const			{ return fMax.y - fMin.y; }

	/// Returns true if the two boxes are equal
	inline boolean  operator==	(const TBBox2D& rhs)	{ return ((fMin==rhs.fMin)&&(fMax==rhs.fMax)); }

public:
	TVector2 fMin;	///< The lower corner of the box
	TVector2 fMax;	///< The upper corner of the box
};

/// \}

/// \addtogroup Data
///
/// \{

///	TBBox3D defines a three dimentional bounding box.
///	It uses two TVector3 to store the lower (#fMin) and the upper (#fMax) corners of the rectangle
///
class TBBox3D : public TMCObject
{
public:
	// ****************************************************************************
	//								TBBox3D
	// 
	/// Default constructor:
	/// #fMin is initialized with kRealMax, #fMax with kRealMin
	///
				TBBox3D			();

	// ****************************************************************************
	//								TBBox3D
	// 
	/// Init constructor
	/// 
	/// \param min  initial value for #fMin.
	/// \param max  initial value for #fMax.
	/// 
				TBBox3D			(const TVector3& min, const TVector3& max);

	// ****************************************************************************
	//								TBBox3D
	// 
	/// Init constructor
	/// 
	/// \param max  initial value for #fMax. #fMin is initialized with -max
	///
				TBBox3D			(const TVector3& max);

	/// Sets #fMin and #fMax to TVector3::kZero
	void		Init			()						{ fMin=TVector3::kZero; fMax=TVector3::kZero; }

	/// Setter function for #fMax
	void		SetMax			(const TVector3& max)	{ fMax = max; }

	/// Setter function for #fMin
	void		SetMin			(const TVector3& min)	{ fMin = min; }

	// ****************************************************************************
	//								GetCenter
	// 
	/// Computes the center of the box
	/// 
	/// \param center  the return value for the center of the box
	/// 
	void		GetCenter		(TVector3& center) const;

	// ****************************************************************************
	//								GetDelta
	// 
	/// Computes the main diagonal of the box (#fMax - #fMin)
	/// 
	/// \param delta  the return value
	///
	void		GetDelta		(TVector3& delta) const;


	// ****************************************************************************
	//								GetMax
	// 
	/// Returns the bigger coordinate of the diagonal
	/// 
	real		GetMax			() const;

	/// Returns the volume of the box
	real		GetVolume		() const;

	// ****************************************************************************
	//								IsEmpty
	// 
	/// Returns true if the box is empty
	/// 
	boolean		IsEmpty			() const;

	// ****************************************************************************
	//								IsEmpty
	// 
	/// Returns true if the box is flat
	/// 
	boolean		IsFlat			() const;

	// ****************************************************************************
	//								AddPoint
	// 
	/// Expands the box to encompass the given point
	/// 
	/// \param PP  the point to add to the box
	///
	void		AddPoint		(const TVector3 &PP);

	// ****************************************************************************
	//								Inset
	// 
	/// Shrinks the box by adding PP to #fMin, and substracting it from #fMax
	/// 
	/// \param PP  the amount to shrink the box with
	/// 
	void		Inset			(const TVector3 &PP);

	// ****************************************************************************
	//								operator[]
	// 
	/// Returns one of the corners of the box (or its center)<BR>
	///	\code
	///     2_____6      Z
	///   3/|___7/|      ^
	///   | |   | |      |-->Y
	///   |/0---|/4     /
	///   1_____5      X
	/// \endcode
	/// 
	/// \param ii  the corner index. For values between 0 and 7 retruns the point shown in the diagram above.
	/// For 8 returns the center. Otherwise zero is returned.
	/// 
	TVector3	operator[]		(int16 ii) const;

	// ****************************************************************************
	//								operator +=
	// 
	/// Expands the box to encompass the given box
	/// 
	/// \param box  the box to add to this box
	/// 
	void		operator+=		(const TBBox3D& box);

	// ****************************************************************************
	//								FixInvertedFields
	// 
	/// if (#fMin .x > #fMax .x) {#fMin .x= #fMax .x= kRealZero;} and same for y
	///
	void		FixInvertedFields();

	
	// ****************************************************************************
	//								GetPoint
	// 
	/// Returns the coordinates of one of the corners of the box
	/// 
	/// \param index  the corner index ( 0<=index<8 )
	/// \param PP     the returned corner coordinates
	/// 
	void		GetPoint		(int16 index,TVector3 &PP) const;

	///	Returns true if the point is inside the box
	boolean		IsInside		(const TVector3& point) const;

	/// Returns true if every coordinate of #fMin is smaller than its #fMax counterpart
	inline boolean Valid		() const 				{ return ((fMin.x <= fMax.x) && (fMin.y <= fMax.y) && (fMin.z <= fMax.z)); }
	
	// ****************************************************************************
	//								Intersect
	// 
	/// Returns true if the two boxes intersect
	/// 
	/// \param boundingBox  the box to test for intersection with this box
	/// 
	boolean		Intersect		(const TBBox3D& boundingBox) const;
	
	/// Returns the width (in x) of the box
	inline real GetWidth		() const				{ return fMax.x - fMin.x; }

	/// Returns the height (in y) of the box
	inline real GetHeight		() const				{ return fMax.y - fMin.y; }

	/// Returns the depth (in z) of the box
	inline real GetDepth( void ) const					{ return fMax.z - fMin.z; }

public:
	TVector3 fMin;	///< The lower corner of the box
	TVector3 fMax;	///< The upper corner of the box
};

/// \}




#endif
