/*
 * Author: Paul Koshevoy
 * CDetector.java  Wed, Jan 14 1998, 11:30:00 1998
 */

public class CDetector
{
public static Triangle the_hit;
    
public static Ray test_hit(Plane plane, Ray light)
    {
	if(light == null)
	    return null;
	
	Ray refl;
	
	refl = TriRay2(plane.T1, light);
	if(refl != null)
	    return refl;
	
	refl = TriRay2(plane.T2, light);
	if(refl != null)
	    return refl;
	
	return null;
    }
    
private static Ray TriRay2(Triangle tri, Ray ray)
    {
	// test ray against tri
	v3x1 v0 = tri.v0;
	v3x1 v1 = tri.v1;
	v3x1 v2 = tri.v2;
	v3x1 p0 = ray.o;
	v3x1 p1 = ray.o.plus(ray.d);
	double t = LineTriangle(p0, p1, v0, v1, v2);
	if(t >= 0)
	    {
//		System.out.println(t);
		v3x1 ref = new v3x1(ray.d);		
		v3x1 hit = p0.plus(v3x1.mult(ray.d, t));
//		ray.o.dump();
//		hit.dump();
		
		the_hit = tri;
		return (new Ray(hit, ref));
	    }
	return null;
    }
    
public static Ray collision(Plane plane, Ray light)
    {
	if(light == null)
	    return null;
	
	Ray refl;
	
	refl = TriRay(plane.T1, light);
	if(refl != null)
	    return refl;
	
	refl = TriRay(plane.T2, light);
	if(refl != null)
	    return refl;
	
	return null;
    }
    
private static Ray TriRay(Triangle tri, Ray ray)
    {
	// test ray against tri
	v3x1 v0 = tri.v0;
	v3x1 v1 = tri.v1;
	v3x1 v2 = tri.v2;
	v3x1 p0 = ray.o;
	v3x1 p1 = ray.o.plus(ray.d);
	double t = LineTriangle(p0, p1, v0, v1, v2);
//	System.out.println("dotproduct: " + v3x1.dot(tri.N, ray.d));
	if(t >= 0)
	    {
		double dotp = v3x1.dot(tri.N, ray.d);
		if(dotp > 0)
		    return null;

		v3x1 ref = v3x1.unit(ray.d.plus(tri.N.times(((double)(2))*Math.abs(dotp))));
		v3x1 hit = p0.plus(v3x1.mult(ray.d, t));
//		tri.dump();
		the_hit = tri;
		return (new Ray(hit, ref));
	    }
	return null;
    }
    
private static double LineTriangle(v3x1 p0, v3x1 p1, v3x1 v0, v3x1 v1, v3x1 v2)
    {
	double j = p0.x - v0.x;
	double k = p0.y - v0.y;
	double l = p0.z - v0.z;
	
	double M[][] = new double[3][3];
	M[0][0] = v1.x - v0.x;
	M[0][1] = v2.x - v0.x;
	M[0][2] = p0.x - p1.x;
	
	M[1][0] = v1.y - v0.y;
	M[1][1] = v2.y - v0.y;
	M[1][2] = p0.y - p1.y;
	
	M[2][0] = v1.z - v0.z;
	M[2][1] = v2.z - v0.z;
	M[2][2] = p0.z - p1.z;
	
	double detM = v3x1.det3x3(M);
//	dump(M);
//	System.out.print("detM:  ");
//	System.out.println(detM);
	if(detM==0)
	    return -1; // parallel
	
	double M_beta[][] = new double[3][3];
	copy(M, M_beta);
	M_beta[0][0] = j;
	M_beta[1][0] = k;
	M_beta[2][0] = l;
	double detM_beta = v3x1.det3x3(M_beta);
	double beta = detM_beta/detM;
//	System.out.println("beta:  "+beta);
	if(beta<0 || beta>1)
	    return -1;
	
	double M_gamma[][] = new double[3][3];
	copy(M, M_gamma);
	M_gamma[0][1] = j;
	M_gamma[1][1] = k;
	M_gamma[2][1] = l;
	double detM_gamma = v3x1.det3x3(M_gamma);
	double gamma = detM_gamma/detM;
//	System.out.println("gamma: "+gamma);
	if(gamma<0 || (beta+gamma)>1)
	    return -1;
	
	double M_t[][] = new double[3][3];
	copy(M, M_t);
	M_t[0][2] = j;
	M_t[1][2] = k;
	M_t[2][2] = l;
	double detM_t = v3x1.det3x3(M_t);
	double t = detM_t/detM;
//	System.out.println("t:     "+t);
	if(t>=0)
	    return t;
	return -1;
    }

private static void copy(double from[][], double to[][])
    {
	for(int i=0; i<3; i++)
	    for(int j=0; j<3; j++)
		to[i][j] = from[i][j];
    }
    
private static void dump(double M[][])
    {
	for(int i=0; i<3; i++)
	    {
		for(int j=0; j<3; j++)
		    {
			System.out.print(M[i][j]);
			System.out.print(" ");
		    }
		System.out.println();
	    }
    }
}

