/******************************************************************************
 * aigeom.h
 *
 * (c) 2000 Leonid Taycher. MIT AI Lab.
 *
 ******************************************************************************/

#ifndef __AIGEOM_H__
#define __AIGEOM_H__

#include <math.h>

/******************************************************************************
 * 
 * This class defines a vector in a 2d space, with all appropricate operators
 *
 ******************************************************************************/
class aic2Vect
{
public:
	aic2Vect()
		: _x(0.0), _y(0.0) {};
	aic2Vect(double x, double y)
		: _x(x), _y(y) {};

	// Defaulb dtor copy ctor, assignment ok
	
	// Accessors 
	double x() const { return _x; };
	double y() const { return _y; };

	void x(double v) { _x = v; };
	void y(double v) { _y = v; };
	
	// Attributes	
	double r() const { return sqrt(_x * _x + _y * _y); };
	double angle() const { return atan2(_y, _x); };
	
	// Operations
	aic2Vect& operator+= (const aic2Vect& rhs) 
		{ _x += rhs._x; _y += rhs._y; return *this; };
	aic2Vect& operator-= (const aic2Vect& rhs) 
		{ _x -= rhs._x; _y -= rhs._y; return *this; };
	aic2Vect& operator*= (double v) 
		{ _x *= v; _y *= v; return *this; };
	aic2Vect& operator/= (double v) 
		{ _x /= v; _y /= v; return *this; };

	// 
	void rotate(double alpha)
	{
		double x = cos(alpha) * _x - sin(alpha) * _y;
		double y = sin(alpha) * _x + cos(alpha) * _y;
		
		_x = x;
		_y = y;
	}
	// Debugging 
	void print() const;
private:
	double _x;
	double _y;
};

inline aic2Vect operator-(const aic2Vect& rhs) 
{ 
	return aic2Vect(-rhs.x(), -rhs.y()); 
};

	inline aic2Vect operator+ (const aic2Vect& lhs, const aic2Vect& rhs)
{
	aic2Vect v = lhs;
	
	v += rhs;
	return v;
};

inline aic2Vect operator- (const aic2Vect& lhs, const aic2Vect& rhs)
{
	aic2Vect v = lhs;
	
	v -= rhs;
	return v;
};

inline aic2Vect operator* (const aic2Vect& lhs, double rhs)
{
	aic2Vect v = lhs;
	
	v *= rhs;
	return v;
};

inline aic2Vect operator* (double lhs, const aic2Vect& rhs)
{
	aic2Vect v = rhs;
	
	v *= lhs;
	return v;
};

inline aic2Vect operator/ (const aic2Vect& lhs, double rhs)
{
	aic2Vect v = lhs;
	
	v /= rhs;
	return v;
};

inline bool operator == (const aic2Vect& lhs, const aic2Vect& rhs)
{
	return (lhs.x() == rhs.x()) && (lhs.y() == rhs.y());
}

inline bool operator != (const aic2Vect& lhs, const aic2Vect& rhs)
{
	return (lhs.x() != rhs.x()) || (lhs.y() != rhs.y());
}
/******************************************************************************
 * 
 * This is the base class for all of the geometric figures.
 *
 ******************************************************************************/

class aic2Figure
{
public:
	aic2Figure() {};
	virtual ~aic2Figure() {};
	
	virtual bool inside(const aic2Vect& pnt) const = 0;
	// Returns  	Whether the point if inside the figure
	virtual bool hit(const aic2Vect& from, const aic2Vect& vel, 
										double& time, double& angle) const = 0;
	// Returns		Whether a point travelling from 'from' with velocity 'vel'
	//						will hit the boundary of the figure, and with what angle with 
	//						the normal
	
	virtual void print() const = 0;
};

class aic2Rect : public aic2Figure
{
public:
	aic2Rect();
	aic2Rect(const aic2Vect& lb, const aic2Vect& rt);
	aic2Rect(const aic2Vect& lb, double width, double height);
	aic2Rect(double left, double top, double width, double height);
	
	// Defaulb copy ctor, dtor and assignment OK
	
	// Accessors
	const aic2Vect& lb() const { return _lb; };
	const aic2Vect& rt() const { return _rt; };

	double left() const { return _lb.x(); };
	double top() const { return _lb.y(); };
	double right() const { return _rt.x(); };
	double bottom() const { return _rt.y(); };
	
	double width() const { return _rt.x() - _lb.x(); };
	double height() const { return _rt.y() - _lb.y(); };
	
	void lb(const aic2Vect& v) 
			{ _rt = aic2Vect(v.x() + width(), v.y() + height()); _lb = v; };
	void width(double v)
			{ _rt.x(left() + v); };
	void height(double v)
			{ _rt.y(top() + v); };
	
	virtual bool inside(const aic2Vect& pnt) const
		{return (pnt.x() >= _lb.x()) && (pnt.x() <= _rt.x()) && 
						 (pnt.y() >= _lb.y()) && (pnt.y() <= _rt.y()); };
	
	virtual bool hit(const aic2Vect& from, const aic2Vect& vel, 
											double& time, double& angle) const;

	virtual void print() const;

private:
		
	void _norm();

	aic2Vect _lb;
	aic2Vect _rt;
};

#endif
