/* $Id: BBox.h,v 1.1 2011/01/06 22:29:07 samn Exp $ */
#ifndef BBOX_H
#define BBOX_H

//struct to represent bounding box
//in a coord. system where top is 0
//and bottom of image is h

template <class T>
struct BBox
{

	//data
	T left,top,right,bottom;

	//functions
	BBox()
	{
		left=top=right=bottom=T(0);
	}
	BBox(const T& left_,const T& top_,const T& right_,const T& bottom_)
	{
		left = left_;
		top = top_;
		right = right_;
		bottom = bottom_;
	}
	template<class T2>
	BBox(const BBox<T2>& B)
	{
		left = B.left;
		top = B.top;
		right = B.right;
		bottom = B.bottom;
	}
	int area() const
	{
		return ( right - left + 1 ) * ( bottom - top + 1 );
	}
	int width() const
	{
		return right - left + 1;
	}
	//assumes bottom has higher value than top
	int height() const
	{
		return bottom - top + 1;
	}
	bool operator==(const BBox& oBox) const
	{
		return left==oBox.left &&
			   right==oBox.right &&
			   top==oBox.top &&
			   bottom==oBox.bottom;
	}
	bool operator!=(const BBox& oBox)
	{
		return !(*this == oBox);
	}
	BBox& operator/=(int i)
	{
		if(i)
		{
			left /= i;
			top /= i;
			right /= i;
			bottom /= i;
		}
		return *this;
	}
	BBox operator/(int i)
	{
		BBox tmp = *this;
		if(i)
		{
			tmp /= i;
		}
		return tmp;
	}
	//make sure coords are valid
	bool valid() const
	{
		return left >= 0 && right >= 0 &&
			   top >= 0 && bottom >= 0 &&
			   left <= right && bottom >= top;
	}

	template<class T2>
	BBox<T>& operator=(const BBox<T2>& B2)
	{
		left = B2.left;
		right = B2.right;
		top = B2.top;
		bottom = B2.bottom;
		return *this;
	}

	T MidX()
	{
		return left + width() / 2;
	}

	T MidY()
	{
		return top + height() / 2;
	}
};

//true iff box1 above box2
template <class T1, class T2>
inline bool Above(const BBox<T1>& box1,const BBox<T2>& box2)
{
	return box1.bottom < box2.top;
}

//true iff box1 below box2
template <class T1, class T2>
inline bool Below(const BBox<T1>& box1,const BBox<T2>& box2)
{
	return box1.top > box2.bottom;
}

template <class T1, class T2>
inline bool Left(const BBox<T1>& box1,const BBox<T2>& box2)
{
	return box1.right < box2.left;
}

template <class T1, class T2>
inline bool Right(const BBox<T1>& box1,const BBox<T2>& box2)
{
	return box1.left > box2.right;
}

template <class T>
inline int MidHeight(BBox<T>& box)
{
	return box.top + ( box.bottom - box.top ) / 2;
}


//do the two bounding boxes intersect?
template <class T1,class T2>
inline bool Intersect(const BBox<T1>& box1, const BBox<T2>& box2)
{
	return !( (box1.top		> box2.bottom) ||
			  (box1.bottom	< box2.top) ||
			  (box1.right	< box2.left) ||
			  (box1.left	> box2.right));
}

//get intersection of bounding boxes , assumes they intersect
template <class T>
inline BBox<T> GetIntersection(const BBox<T>& b1, const BBox<T>& b2)
{
	BBox<T> ret;
	ret.left = b1.left > b2.left ? b1.left : b2.left;
	ret.right = b1.right < b2.right ? b1.right : b2.right;
	ret.top = b1.top > b2.top ? b1.top : b2.top;
	ret.bottom = b1.bottom < b2.bottom ? b1.bottom : b2.bottom;
	return ret;
}

//get union of bounding boxes
template <class T>
inline BBox<T> GetUnion(const BBox<T>& b1, const BBox<T>& b2)
{
	BBox<T> ret;
	ret.left = b1.left < b2.left ? b1.left : b2.left;
	ret.right = b1.right > b2.right ? b1.right : b2.right;
	ret.top = b1.top < b2.top ? b1.top : b2.top;
	ret.bottom = b1.bottom > b2.bottom ? b1.bottom : b2.bottom;
	return ret;
}

template <class T>
inline bool Zero(BBox<T>& oB)
{
	return !(oB.left || oB.right ||
		     oB.top || oB.bottom);
}

typedef BBox<int> IBBox;
typedef BBox<unsigned int> UBBox;

struct BBoxD
{
	int left, top, right, bottom, rotate;

	BBoxD()
	{
		left = top = right = bottom = 1;
		rotate = 0;
	}

	BBoxD(int l, int t, int r, int b)
	{
		left = l;
		top = t;
		right = r;
		bottom = b;
		rotate = 0;
	}

	BBoxD(int l, int t, int r, int b, int rot)
	{
		left = l;
		top = t;
		right = r;
		bottom = b;
		rotate = rot;
	}
};

#endif