/* Sample implementation of the line segment—triangle intersection test
 * presented in the paper:
 *
 *   Fast 3D Line Segment—Triangle Intersection Test
 *   Nick Chirkov
 *   journal of graphics tools 10(3):13-18, 2005
 *
 */

struct RAYTRI
{
	double org[3];
	double end[3];
	double dir[3];
	double v0[3],v1[3],v2[3];

	struct PLANE
	{
		double x, y, z, d;
		enum MAIN_AXIS { X, Y, Z };
		MAIN_AXIS type;
	};
	PLANE plane;
};

int c2005(const RAYTRI* rt)
{
	double signSrc = rt->plane.x*rt->org[0] + rt->plane.y*rt->org[1] + rt->plane.z*rt->org[2] - rt->plane.d;
	double signDst = rt->plane.x*rt->end[0] + rt->plane.y*rt->end[1] + rt->plane.z*rt->end[2] - rt->plane.d;
	if(signSrc*signDst > 0.0)	return 0;

	double d = signSrc - signDst;

	if(rt->plane.type==RAYTRI::PLANE::X)
	{
		double e0y = rt->v1[1] - rt->v0[1];
		double e0z = rt->v1[2] - rt->v0[2];
		double e1y = rt->v2[1] - rt->v0[1];
		double e1z = rt->v2[2] - rt->v0[2];
		double basey = rt->org[1] - rt->v0[1];
		double basez = rt->org[2] - rt->v0[2];

		double adelx = signSrc*(e0y * rt->dir[2] - e0z * rt->dir[1]);
		if( (adelx + d*(e0y*basez - e0z*basey)) * ( signSrc*(rt->dir[1]*e1z - rt->dir[2]*e1y) + d*(basey*e1z - basez*e1y)) > 0.0)
		{
			double e2y = rt->v1[1] - rt->v2[1];
			double e2z = rt->v1[2] - rt->v2[2];
			basey = rt->org[1] - rt->v1[1];
			basez = rt->org[2] - rt->v1[2];
			if( (adelx + d*(e0y*basez - e0z*basey)) * ( signSrc*(rt->dir[1]*e2z - rt->dir[2]*e2y) + d*(basey*e2z - basez*e2y)) > 0.0)	return 1;
		}
	}
	else
		if(rt->plane.type==RAYTRI::PLANE::Y)
		{
			double e0x = rt->v1[0] - rt->v0[0];
			double e0z = rt->v1[2] - rt->v0[2];
			double e1x = rt->v2[0] - rt->v0[0];
			double e1z = rt->v2[2] - rt->v0[2];
			double basex = rt->org[0] - rt->v0[0];
			double basez = rt->org[2] - rt->v0[2];
			double adely = signSrc*(e0z * rt->dir[0] - e0x * rt->dir[2]);
			if( (adely + d*(e0z*basex - e0x*basez)) * ( signSrc*(rt->dir[2]*e1x - rt->dir[0]*e1z) + d*(basez*e1x - basex*e1z)) > 0.0)
			{
				double e2x = rt->v1[0] - rt->v2[0];
				double e2z = rt->v1[2] - rt->v2[2];
				basex = rt->org[0] - rt->v1[0];
				basez = rt->org[2] - rt->v1[2];
				if( (adely + d*(e0z*basex - e0x*basez)) * ( signSrc*(rt->dir[2]*e2x - rt->dir[0]*e2z) + d*(basez*e2x - basex*e2z)) > 0.0)	return 1;
			}
		}
		else
		{
			double e0x = rt->v1[0] - rt->v0[0];
			double e0y = rt->v1[1] - rt->v0[1];
			double e1x = rt->v2[0] - rt->v0[0];
			double e1y = rt->v2[1] - rt->v0[1];
			double basex = rt->org[0] - rt->v0[0];
			double basey = rt->org[1] - rt->v0[1];
			double adelz = signSrc*(e0x * rt->dir[1] - e0y * rt->dir[0]);

			if( (adelz + d*(e0x*basey - e0y*basex)) * ( signSrc*(rt->dir[0]*e1y - rt->dir[1]*e1x) + d*(basex*e1y - basey*e1x)) > 0.0)
			{
				double e2x = rt->v1[0] - rt->v2[0];
				double e2y = rt->v1[1] - rt->v2[1];
				basex = rt->org[0] - rt->v1[0];
				basey = rt->org[1] - rt->v1[1];
				if( (adelz + d*(e0x*basey - e0y*basex)) * ( signSrc*(rt->dir[0]*e2y - rt->dir[1]*e2x) + d*(basex*e2y - basey*e2x)) > 0.0)	return 1;
			}
		}

	return 0;
}