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

#include <stdio.h>
#include <math.h>

#include <aigeom.h>
#include <aiutils.h>

//=============================================================================

void aic2Vect::print() const
{
	printf (" 2D Vector (%lf, %lf)\n", _x, _y);
}

//-----------------------------------------------------------------------------

aic2Rect::aic2Rect()
	:
	aic2Figure(),
	_lb(0.0, 0.0), 
	_rt(0.0, 0.0)
{
} 

aic2Rect::aic2Rect(const aic2Vect& lb, const aic2Vect& rt)
	:
	aic2Figure(),
	_lb(lb), 
	_rt(rt)
{
	_norm();
} 

aic2Rect::aic2Rect(const aic2Vect& lb, double width, double height)
	:
	aic2Figure(),
	_lb(lb), 
	_rt(lb.x() + width, lb.y() + height)
{
	_norm();
} 

aic2Rect::aic2Rect(double left, double top, double width, double height)
	:
	aic2Figure(),
	_lb(left, top), 
	_rt(left + width, top + height)
{
	_norm();
} 

void aic2Rect::_norm() 
{
	if (width() < 0)
	{
		double v = _lb.x();
		_lb.x(_rt.x());
		_rt.x(v);
	}

	if (height() < 0)
	{
		double v = _lb.y();
		_lb.y(_rt.y());
		_rt.y(v);
	}

}
void aic2Rect::print() const
{
	printf (" 2D Rectangle [(%lf, %lf)<->(%lf, %lf)] width : %lf, height : %lf\n", 
			lb().x(), lb().y(), rt().x(), rt().y(), width(), height());
}

/*
 * This function determines whether the line from --> from + vel has a common
 * point with a rectangle, and if yes, returns the angle between vel and 
 * the normal to the corresponding side and the time of intersection. 
 * Assumes that from is outside of the rectangle.
 * 
 * The angle returned is the angle from normal to the reverse of the 
 * vel
 */
bool aic2Rect::hit(const aic2Vect& from, const aic2Vect& vel, 
						double& time, double& angle) const
{
	double tt = 0;

	time = 1.0;	// A real hit may occur at 0 < time < 1
	angle = 0;
	
	// There is a chance of intersecting vertical sides of the rectangle
	if (vel.x() != 0.0) 	
	{
		double y;
		double tempT;
		
		// Left side
		tt = (lb().x() - from.x()) / vel.x();
		y = from.y() + vel.y() * tt;
		
		if ((tt >= 0) && (tt < 1) && (y > top()) && (y < bottom()))
		{
			if (tt < time) // This is the closer intersection than before
			{
				time = tt;
				angle = vel.angle(); 
			}
		}
		
		// Right
		tt = (rt().x() - from.x()) / vel.x();
		y = from.y() + vel.y() * tt;
		
		if ((tt >= 0) && (tt < 1) && (y > top()) && (y < bottom()))
		{
			if (tt < time) // This is the closer intersection than before
			{
				time = tt;
				angle = vel.angle() - M_PI; 
			}
		}
	}

	// There is a chance of intersecting horizontal sides of the rectangle
	if (vel.y() != 0.0) 	
	{
		double x;
		
		// bottom side <--- min Y
		tt = (lb().y() - from.y()) / vel.y();
		x = from.x() + vel.x() * tt;
		
		if ((tt >= 0) && (tt < 1) && (x > left()) && (x < right()))
		{
			if (tt < time) // This is the closer intersection than before
			{
				time = tt;
				angle = vel.angle() - M_PI / 2.0;
			}
		}
		
		// Top side <--- max Y
		tt = (rt().y() - from.y()) / vel.y();
		x = from.x() + vel.x() * tt;
		
		if ((tt >= 0) && (tt < 1) && (x > left()) && (x < right()))
		{
			if (tt < time) // This is the closer intersection than before
			{
				time = tt;
				angle = M_PI / 2.0 + vel.angle();
			}
		}
	}
	
	angle = angleToZeroCtr(angle);
	return (time < 1.0);
}
