#include "../include/sharedIncludes.h"

#define CVector3 CVector

/////////////////////////////////////// CROSS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////	This returns a perpendicular vector from 2 given vectors by taking the cross product.
CVector3 Cross(CVector3 vVector1, CVector3 vVector2)
{
	CVector3 vNormal;									
	vNormal.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
	vNormal.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
	vNormal.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));

	return vNormal;										
}


/////	This returns the magnitude of a normal (or any other vector)
float Magnitude(CVector3 vNormal)
{
	return (float)sqrt( (vNormal.x * vNormal.x) + (vNormal.y * vNormal.y) + (vNormal.z * vNormal.z) );
}


/////	This returns a normalize vector (A vector exactly of length 1)
CVector3 Normalize(CVector3 vNormal)
{
	float magnitude = Magnitude(vNormal);				
	vNormal.x /= magnitude;						
	vNormal.y /= magnitude;						
	vNormal.z /= magnitude;						
	return vNormal;						
}


/////	This returns the normal of a polygon (The direction the polygon is facing)
CVector3 Normal(CVector3 vTriangle[])					
{														
	CVector3 vVector1 = vTriangle[2] - vTriangle[0];
	CVector3 vVector2 = vTriangle[1] - vTriangle[0];
	CVector3 vNormal = Cross(vVector1, vVector2);		
	vNormal = Normalize(vNormal);				
	return vNormal;						
}


/////	This returns the distance between a plane and the origin
float PlaneDistance(CVector3 Normal, CVector3 Point)
{	
	float distance = 0;									
	distance = - ((Normal.x * Point.x) + (Normal.y * Point.y) + (Normal.z * Point.z));
	return distance;									
}


/////	This checks to see if a line intersects a plane
bool IntersectedPlane(CVector3 vPoly[], CVector3 vLine[], CVector3 &vNormal, float &originDistance)
{
	float distance1=0, distance2=0;							
	vNormal = Normal(vPoly);						
	originDistance = PlaneDistance(vNormal, vPoly[0]);
	distance1 = ((vNormal.x * vLine[0].x)  +					
		         (vNormal.y * vLine[0].y)  +					
				 (vNormal.z * vLine[0].z)) + originDistance;		
	distance2 = ((vNormal.x * vLine[1].x)  +					
		         (vNormal.y * vLine[1].y)  +					
				 (vNormal.z * vLine[1].z)) + originDistance;


	if(distance1 * distance2 >= 0)			
	   return false;				
	return true;							
}


/////////////////////////////////// DOT \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This computers the dot product of 2 vectors

float Dot(CVector3 vVector1, CVector3 vVector2) 
{
	return ( (vVector1.x * vVector2.x) + (vVector1.y * vVector2.y) + (vVector1.z * vVector2.z) );
}


/////////////////////////////////// ANGLE BETWEEN VECTORS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This checks to see if a point is inside the ranges of a polygon

double AngleBetweenVectors(CVector3 Vector1, CVector3 Vector2)
{							
	float dotProduct = Dot(Vector1, Vector2);				
	float vectorsMagnitude = Magnitude(Vector1) * Magnitude(Vector2) ;
	return( acos( dotProduct / vectorsMagnitude ) );
}


/////////////////////////////////// INTERSECTION POINT \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This returns the intersection point of the line that intersects the plane
											
CVector3 IntersectionPoint(CVector3 vNormal, CVector3 vLine[], double distance)
{
	CVector3 vPoint, vLineDir;					
	double Numerator = 0.0, Denominator = 0.0, dist = 0.0;
	vLineDir = vLine[1] - vLine[0];		
	vLineDir = Normalize(vLineDir);		
	Numerator = - (vNormal.x * vLine[0].x +		
				   vNormal.y * vLine[0].y +
				   vNormal.z * vLine[0].z + distance);

	Denominator = Dot(vNormal, vLineDir);		
	if( Denominator == 0.0)						
		return vLine[0];					
	dist = Numerator / Denominator;				
	vPoint.x = (float)(vLine[0].x + (vLineDir.x * dist));
	vPoint.y = (float)(vLine[0].y + (vLineDir.y * dist));
	vPoint.z = (float)(vLine[0].z + (vLineDir.z * dist));
	return vPoint;
}


/////////////////////////////////// INSIDE POLYGON \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This checks to see if a point is inside the ranges of a polygon

bool InsidePolygon(CVector3 vIntersection, CVector3 Poly[], long verticeCount)
{
	const double MATCH_FACTOR = 0.99;		
	double Angle = 0.0;				
	CVector3 vA, vB;				
	
	for (int i = 0; i < verticeCount; i++)		
	{	
		vA = Poly[i] - vIntersection;			
		vB = Poly[(i + 1) % verticeCount] - vIntersection;
		Angle += AngleBetweenVectors(vA, vB);	
	}
											
	if(Angle >= (MATCH_FACTOR * (2.0 * MLpi)) )	
		return true;				
	return false;								
}

/////////////////////////////////// INTERSECTED POLYGON \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This checks if a line is intersecting a polygon

bool LinePolyIntersect(CVector3 vPoly[], CVector3 vLine[], int verticeCount)
{
	CVector3 vNormal;
	float originDistance = 0;
	if(!IntersectedPlane(vPoly, vLine,   vNormal,   originDistance))
		return false;
	CVector3 vIntersection = IntersectionPoint(vNormal, vLine, originDistance);
	if(InsidePolygon(vIntersection, vPoly, verticeCount))
		return true;							
	return false;								
}
