// __author__ = Juan Carlos De Abreu (jcabreur@gmail.com)

#include "Plane.h"

//////////// Def plane ////////////
BEGIN_TEG_NAMESPACE();

namespace math {

// Plane constructors
Plane::Plane() : a(0), b(0), c(0), d(0) { }

// Constructor a plane out of a triangle.
Plane::Plane(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3) {
	// Calculate normal of the plane and then to calculate d we take the
	// dot product of the triangle normal with the first triangle.
	Vec3f normal = cross(v2 - v1, v3 - v1); normal.normalize();
	a = normal.x; b = normal.y; c = normal.z;
	d = - (normal.x * v1.x + normal.y * v1.y + normal.z * v1.z);
}

Plane::Plane(const float& a_, const float& b_, const float& c_, const float& d_)
	: a(a_), b(b_), c(c_), d(d_) { }

Plane::Plane(const Vec3f& n, const float& d_) : a(n.x), b(n.y), c(n.z), d(d_) { }

// Plane destructor
Plane::~Plane() { }

// This function will create a plane out of a triangle.
Plane createPlaneFromTri(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3) {
	// Calculate normal of the plane and then to calculate d we take the
	// dot product of the triangle normal with the first triangle.
	Vec3f normal = cross(v2 - v1, v3 - v1); normal.normalize();
	return Plane(normal, - (normal.x * v1.x + normal.y * v1.y + normal.z * v1.z));
}

// This will find the interection of 3 planes and store it in the vector intersectPoint.
bool Intersect(Plane p1, Plane p2, Plane p3, Vec3f &intersectPoint) {
	// First we are just placing all data in temp CVector4 objects.
	Vec3f p1Normal(p1.a, p1.b, p1.c);
	Vec3f p2Normal(p2.a, p2.b, p2.c);
	Vec3f p3Normal(p3.a, p3.b, p3.c);

	// Get cross product of p2 and p3.
	Vec3f temp = cross(p2Normal, p3Normal);

	// Get the dot product of this plane with the cross product of p2 and p3.
	float dp = dot(p1Normal, temp);

	// If dp is 0 then it is safe to return right away.
	if (dp == 0.0f) return false;

	// Else we must find intersect point.
	intersectPoint = temp * p1.d;

	temp = cross(p3Normal, p1Normal);
	intersectPoint += temp * p2.d;

	temp = cross(p1Normal, p2Normal);
	intersectPoint += temp * p3.d;

	intersectPoint /= -dp;
	
	return true;
}

// This function will determine if a point is on, in front of, or behind the plane.
int Plane::ClassifyPoint(Vec3f v) {
	// First we store the dot product of the plane and the point.
	const float distance = a * v.x + b * v.y + c * v.z + d;

	// Simply put if the dot product is greater than 0 then it is infront of it.
	// If it is less than 0 then it is behind it.  And if it is 0 then it is on it.
	if(distance > 0.001) return FRONT_PLANE;
	if(distance < -0.001) return BEHIND_PLANE;
	return ON_PLANE;
}

// This function will perform a linear interpolation between two planes
Plane Lerp(Plane p1, Plane p2, float amount) {
	// First calculate a, b, c, d.
	Plane p(p1.a * (1.0f - amount) + p2.a * amount,
			p1.b * (1.0f - amount) + p2.b * amount,
			p1.c * (1.0f - amount) + p2.c * amount,
			p1.d * (1.0f - amount) + p2.d * amount);

	// Next we will normalize the plane.
	p.normalize();
	
	return p;
}

}; // Namespace math

END_TEG_NAMESPACE();
