/*
	BoundingBox.cpp

	Implementation of BoundingBox class
*/
#include "stdafx.h"
#include <assert.h>
#include "boundingbox.h"

CBoundingBox::CBoundingBox()
{
	// TODO: add one-time construction code here

}

CBoundingBox::~CBoundingBox()
{
}


//return a new bouding box consisting of the union
//of us with the given bounding box
CBoundingBox* CBoundingBox::GetUnionWith(CBoundingBox box)
{
	C3DPoint min = m_minPoint.MinimumWith(box.m_minPoint);
	C3DPoint max = m_maxPoint.MaximumWith(box.m_maxPoint);

	CBoundingBox* newBox = new CBoundingBox;
	newBox->m_minPoint = min;
	newBox->m_maxPoint = max;
	return newBox;
}

//sets up the maximum and minimum points for this bounding
//box from the given list of faces
void CBoundingBox::CreateFrom(CList <CFace *, CFace *>* faces)
{
	int count = 1;
	POSITION pos = faces->GetHeadPosition();
	while (pos != NULL)
	{
		CFace* obj = faces->GetAt(pos);
		//sequence through the points in the face
		POSITION pos2 = obj->m_points.GetHeadPosition();
		while (pos2 != NULL)
		{
			C3DPoint* point = obj->m_points.GetAt(pos2);
			if (count == 1)
			{
				//initialize them
				m_minPoint.m_x = point->m_x; 
				m_minPoint.m_y = point->m_y;
				m_minPoint.m_z = point->m_z;
				m_maxPoint.m_x = point->m_x; 
				m_maxPoint.m_y = point->m_y;
				m_maxPoint.m_z = point->m_z;
				count++;
			}
			else
			{
				//compare it with the previous ones found
				m_minPoint = point->MinimumWith(m_minPoint); 
				m_maxPoint = point->MaximumWith(m_maxPoint); 
			}
			obj->m_points.GetNext(pos2);
		}
		faces->GetNext(pos);
	}

}

//return true if we contain the given point, false otherwise
BOOL CBoundingBox::ContainsPoint(C3DPoint point)
{
	BOOL bxTest = (m_minPoint.m_x <= point.m_x) && (point.m_x <= m_maxPoint.m_x);
	BOOL byTest = (m_minPoint.m_y <= point.m_y) && (point.m_y <= m_maxPoint.m_y);
	BOOL bzTest = (m_minPoint.m_z <= point.m_z) && (point.m_z <= m_maxPoint.m_z);

	return (bxTest && byTest && bzTest);

}

//return true if we contain the given point, false otherwise
BOOL CBoundingBox::ContainsPointXY(C3DPoint point)
{
	BOOL bxTest = (m_minPoint.m_x <= point.m_x) && (point.m_x <= m_maxPoint.m_x);
	BOOL byTest = (m_minPoint.m_y <= point.m_y) && (point.m_y <= m_maxPoint.m_y);
	return (bxTest && byTest);
}

//return true if we contain the given point, false otherwise
BOOL CBoundingBox::ContainsPointXZ(C3DPoint point)
{
	BOOL bxTest = (m_minPoint.m_x <= point.m_x) && (point.m_x <= m_maxPoint.m_x);
	BOOL bzTest = (m_minPoint.m_z <= point.m_z) && (point.m_z <= m_maxPoint.m_z);

	return (bxTest && bzTest);
}

//return true if we contain the given point, false otherwise
BOOL CBoundingBox::ContainsPointYZ(C3DPoint point)
{
	BOOL byTest = (m_minPoint.m_y <= point.m_y) && (point.m_y <= m_maxPoint.m_y);
	BOOL bzTest = (m_minPoint.m_z <= point.m_z) && (point.m_z <= m_maxPoint.m_z);

	return (byTest && bzTest);

}

//tests for intersection
double CBoundingBox::IsInBetween(C3DPoint point1, C3DPoint point2)
{
	double t = 1;
	C3DPoint n1 = point1 - m_minPoint;
	C3DPoint n2 = point1 - m_maxPoint;
	C3DPoint d = point1 - point2;

	//test for each face
	t = TestInsideFace(t, n1.m_x, d.m_x, 1, point1, point2); //left 
	t = TestInsideFace(t, n2.m_x, d.m_x, 1, point1, point2); //right
	
	t = TestInsideFace(t, n1.m_y, d.m_y, 2, point1, point2); //bottom 
	t = TestInsideFace(t, n2.m_y, d.m_y, 2, point1, point2); //top
	
	t = TestInsideFace(t, n1.m_z, d.m_z, 3, point1, point2); //back 
	t = TestInsideFace(t, n2.m_z, d.m_z, 3, point1, point2); //front
	
	//if t < 1.0 that means yes
	return t;
}

double CBoundingBox::TestInsideFace(double t, double a, double b, int nFace, C3DPoint point1, C3DPoint point2)
{
	double tPrime;
	
	if (ContainsPointYZ(point2) && ContainsPointXZ(point2)
		&& ContainsPointXY(point2))
		return 0.1;
	
	if (abs(b) > 0.00001)
	{
		if ((b == 0 && a > 0) || (a / b) > 0)
		{
			tPrime = a / b;
			if (tPrime < t)
			{
				C3DPoint point = point1 + (point2 - point1) * tPrime;
				if (nFace == 1)
				{
					if (ContainsPointYZ(point))
						return tPrime;
				}
				else if (nFace == 2)
				{
					if (ContainsPointXZ(point))
						return tPrime;
				}
				else if (nFace == 3)
				{
					if (ContainsPointXY(point))
						return tPrime;
				}
			}
		}
	}
	return t;

}

double CBoundingBox::GetVolume(void)
{
	//volume is l*w*h
	double dLength = abs(m_maxPoint.m_z * m_minPoint.m_z);
	double dWidth = abs(m_maxPoint.m_x * m_minPoint.m_x);
	double dHeight = abs(m_maxPoint.m_y * m_minPoint.m_y);

	return dLength * dWidth * dHeight;
}

