std::list<WCIntersectionResult> __WILDCAT_NAMESPACE__::GeometricIntersection(WCGeometricLine *left,
	WCGeometricLine *right, const WPFloat &tol, unsigned const int &flags) {
	std::list<WCIntersectionResult> results;
	//Check if self intersecting
	if (left == right) return results;

	//Evaluate both lines at both ends
	WCVector4 p1 = left->Begin();
	WCVector4 p2 = left->End();
	WCVector4 p3 = right->Begin();
	WCVector4 p4 = right->End();
	
	//Get length vectors
	WCVector4 p21(p2 - p1);
	WCVector4 p43(p4 - p3);
	WPFloat dist;
	
	//Check for parallel
	WCVector4 cross = p43.CrossProduct(p21);
	WPFloat denom = cross.Magnitude();
	WPFloat onePlusTol = 1.0 + tol;
	if (denom < 0.001) {
		//Determine perpendicular distance
		WPFloat p21mag = p21.Magnitude();
		WCVector4 p13(p1 - p3);
		WCVector4 num = p21.CrossProduct(p13);
		dist = num.Magnitude() / p21mag;
		//If outside of tolerance, no intersection
		if (dist <= tol) {
			//Project all four points onto opposite lines
			p21 /= p21mag;
			WPFloat p43mag = p43.Magnitude();
			p43 /= p43mag;
			WCVector4 p31(p3 - p1);
			WCVector4 p41(p4 - p1);
			WCVector4 p23(p2 - p3);
			WPFloat p1Proj = p43.DotProduct(p13) / p43mag;
			WPFloat p2Proj = p43.DotProduct(p23) / p43mag;
			WPFloat p3Proj = p21.DotProduct(p31) / p21mag;
			WPFloat p4Proj = p21.DotProduct(p41) / p21mag;

			//See if each point is in 0.0 to 1.0 +- tolerance
			bool p1In = (p1Proj > -tol) && (p1Proj < onePlusTol);
			bool p2In = (p2Proj > -tol) && (p2Proj < onePlusTol);
			bool p3In = (p3Proj > -tol) && (p3Proj < onePlusTol);
			bool p4In = (p4Proj > -tol) && (p4Proj < onePlusTol);
			//If none are in then no overlap, return
			if ( p1In || p2In || p3In || p4In) {
				//Bounds check all of the projections
				p1Proj = STDMAX(0.0, STDMIN(1.0, p1Proj));
				p2Proj = STDMAX(0.0, STDMIN(1.0, p2Proj));
				p3Proj = STDMAX(0.0, STDMIN(1.0, p3Proj));
				p4Proj = STDMAX(0.0, STDMIN(1.0, p4Proj));
				//Create hit result
				WCIntersectionResult hit;
				hit.type = IntersectLine;
				WCVector4 pStart, pEnd;
				//Case 1 - Left is completely within Right
				if (p1In && p2In) {
					//Set the start and end points
					pStart = p1;
					pEnd = p2;
					//Set the param values
					hit.leftParam.I( 0.0 );
					hit.leftParam.J( 1.0 );
					hit.rightParam.I( STDMIN(p1Proj,p2Proj) );
					hit.rightParam.J( STDMAX(p1Proj,p2Proj) );
					//Set boundary values
					hit.leftBoundary = true;
					hit.rightBoundary = false;
				}
				//Case 2 - Right is completely within Left
				else if (p3In && p4In) {
					//Set the start and end points
					pStart = p3;
					pEnd = p4;
					//Set the param values
					hit.leftParam.I( STDMIN(p3Proj,p4Proj) );
					hit.leftParam.J( STDMAX(p3Proj,p4Proj) );
					hit.rightParam.I( 0.0 );
					hit.rightParam.J( 1.0 );
					//Set boundary values
					hit.leftBoundary = false;
					hit.rightBoundary = true;
				}
				//Remaining Cases
				else {
					//Simple sets
					if (p1In) { hit.leftParam.I(0.0); pStart = p1; }
					if (p2In) { hit.leftParam.J(1.0); pStart = p2; }
					if (p3In) { hit.rightParam.I(0.0); pEnd = p3; }
					if (p4In) { hit.rightParam.J(1.0); pEnd = p4; }
					//Double sets
					if (p1In && p3In) { hit.leftParam.J(p3Proj); hit.rightParam.J(p1Proj); }
					if (p1In && p4In) { hit.leftParam.J(p4Proj); hit.rightParam.I(p1Proj); }
					if (p2In && p3In) { hit.leftParam.I(p3Proj); hit.rightParam.J(p2Proj); }
					if (p2In && p4In) { hit.leftParam.I(p4Proj); hit.rightParam.I(p2Proj); }
					
					//Check to see if intersection is a point (think of two lines end to end)
					if (pStart.Distance(pEnd) < tol) hit.type = IntersectPoint;

					//This is not the best way to check for CULL BOUNDARY, but if pStart and pEnd distance < tol, must be end-to-end
					if ((flags & INTERSECT_CULL_BOUNDARY) && (hit.type == IntersectPoint))
						return results;

					//Set boundary values
					hit.leftBoundary = true;
					hit.rightBoundary = true;
				}
				//Overlap forces boundarys to false

				//See if genObj
				if ((hit.type == IntersectPoint) && (flags & INTERSECT_GEN_POINTS)) {
					//Create new point
					WCGeometricPoint *newPoint = new WCGeometricPoint(pStart);
					//Add to result struct
					hit.object = newPoint;					
				}
				else if ((hit.type == IntersectLine) && (flags & INTERSECT_GEN_LINES)) {
					//Create new line
					WCGeometricLine *newLine = new WCGeometricLine(pStart, pEnd);
					//Add to result struct
					hit.object = newLine;
				}
				else hit.object = NULL;
				//Add the hit to the list
				results.push_back(hit);
			}
		}
	}
	//Non-Parallel Case
	else {
		//Many dot products
		WPFloat d121 = p1.DotProduct(p21);			// L
		WPFloat d2121 = p21.DotProduct(p21);		// M
		WPFloat d321 = p3.DotProduct(p21);			// N
		WPFloat d4321 = p43.DotProduct(p21);		// O
		WPFloat d143 = p1.DotProduct(p43);			// Q
		WPFloat d343 = p3.DotProduct(p43);			// R
		WPFloat d4343 = p43.DotProduct(p43);		// S
		denom = (d4343 * d2121) - (d4321 * d4321);
		//What does this correspond to?
		if (denom == 0.0) {
			CLOGGER_WARN(WCLogManager::RootLogger(), "GeometricIntersection::LineLine -  Denominator == 0.0.");
		}
		//Otherwise
		else {
			//Calculate parametric intersection values
			WPFloat numer = d4343 * (d321 - d121) + d4321 * (d143 - d343);
			WPFloat mua = numer / denom;
			WPFloat mub = (d143 + d4321 * mua - d343) / d4343;
			//Make sure mua and mub are (0.0 +- tol, 1.0 +- tol)
			if ( (mua < onePlusTol) && (mua > -tol) && (mub < onePlusTol) && (mub > -tol) ) {
				//Bound mua and mub [0, 1]
				mua = STDMAX(0.0, STDMIN(1.0, mua));
				mub = STDMAX(0.0, STDMIN(1.0, mub));
				//Calculate points and distance between them
				WCVector4 pointOnFirst = p1 + p21 * mua;
				WCVector4 pointOnSecond = p3 + p43 * mub;
				//Make sure lines are not > tol apart
				dist = pointOnFirst.Distance(pointOnSecond);
				if (dist < tol) {
					//Create intersection result
					WCIntersectionResult hit;
					hit.type = IntersectPoint;
					hit.leftParam.I(mua);
					hit.rightParam.I(mub);
					hit.leftBoundary = (fabs(mua) < tol) || (fabs(mua-1.0) < tol);
					hit.rightBoundary = (fabs(mub) < tol) || (fabs(mub-1.0) < tol);

					//Check for culling end-point intersections
					if (!(flags & INTERSECT_CULL_BOUNDARY) || (!hit.leftBoundary && !hit.rightBoundary)) {
						//See if genObj
						if (flags & INTERSECT_GEN_POINTS) {
							//Create new point
							WCGeometricPoint *newPoint = new WCGeometricPoint(pointOnFirst);
							//Add to result struct
							hit.object = newPoint;
						}
						else hit.object = NULL;
						//Add the intersection to the list
//						std::cout << hit << pointOnFirst << std::endl;
						results.push_back(hit);
					}
				}
			}
		}
	}
	//Return result
	return results;
}
int main(int argc, char* argv[])
{
	CS325Graphics window(argc, argv);

	float delta = 0.1;

	Point2D p1(CS325Graphics::X_MIN, CS325Graphics::Y_MAX / 4.5);
	Point2D p2(CS325Graphics::X_MAX, CS325Graphics::Y_MAX / 4.5);
	Point2D p3(CS325Graphics::X_MIN, CS325Graphics::Y_MIN);
	Point2D p4(CS325Graphics::X_MAX, CS325Graphics::Y_MAX);

	//Points 41, 42, 45, 46 control the sandbox. DON"T MESS WITH THEM!

	Point3D p30(0.5,  0.5,-3.5);
	Point3D p31(0.5, -0.5,-3.5);
	Point3D p32(-0.5,-0.5,-3.5);
	Point3D p33(-0.5, 0.5,-3.5);
	Point3D p34(0.5,  0.5,-1.5);
	Point3D p35(0.5, -0.5,-1.5);
	Point3D p36(-0.5,-0.5,-1.5);
	Point3D p37(-0.5, 0.5,-1.5);

	Point3D p40( -70.8, 28.8, -50.8);
	Point3D p41( 50.8,-2.8,  50.8);
	Point3D p42(-50.8,-2.8,  50.8);
	Point3D p43(-58.8, 25.8,  50.8);
	Point3D p44( 50.8, 50.8, -50.8);
	Point3D p45( 50.8,-2.8, -50.8);
	Point3D p46(-50.8,-2.8, -50.8);
	Point3D p47(-84.8,-2.8, -50.8);
	Point3D p49(-8.5,22.0, 50.8);
	Point3D p48(70,20,50.8);

	Point3D p50(3.5,  0.5,-3.5);
	Point3D p51(3.5, -0.5,-3.5);
	Point3D p52(2.5,-0.5,-3.5);
	Point3D p53(2.5, 0.5,-3.5);
	Point3D p54(3.5,  0.5,-1.5);
	Point3D p55(3.5, -0.5,-1.5);
	Point3D p56(2.5,-0.5,-1.5);
	Point3D p57(2.5, 0.5,-1.5);

	Point3D p60(3.5,  0.5, 13.5);
	Point3D p61(3.5, -0.5, 13.5);
	Point3D p62(2.5,-0.5,  13.5);
	Point3D p63(2.5, 0.5,  13.5);
	Point3D p64(3.5,  0.5, 16.5);
	Point3D p65(3.5, -0.5, 16.5);
	Point3D p66(2.5,-0.5,  16.5);
	Point3D p67(2.5, 0.5,  16.5);

	

	Point2D viewPos;
	Vector2D viewDir;
	Vector3D deltaV;
	viewDir.setAngle(0);


	// move view position

	for(int i = 0; i < MOVE_TEST; i){
		/*window.DrawLineOnScreen(p1, p2);*/
		//window.DrawLineOnScreen(p4, p3);

		window.DrawLineInSpace(p30, p31);
		window.DrawLineInSpace(p31, p32);
		window.DrawLineInSpace(p32, p33);
		window.DrawLineInSpace(p33, p30);
		window.DrawLineInSpace(p34, p35);
		window.DrawLineInSpace(p35, p36);
		window.DrawLineInSpace(p36, p37);
		window.DrawLineInSpace(p37, p34);
		window.DrawLineInSpace(p30, p34);
		window.DrawLineInSpace(p31, p35);
		window.DrawLineInSpace(p32, p36);
		window.DrawLineInSpace(p33, p37);

		window.DrawLineInSpace(p50, p51);
		window.DrawLineInSpace(p51, p52);
		window.DrawLineInSpace(p52, p53);
		window.DrawLineInSpace(p53, p50);
		window.DrawLineInSpace(p54, p55);
		window.DrawLineInSpace(p55, p56);
		window.DrawLineInSpace(p56, p57);
		window.DrawLineInSpace(p57, p54);
		window.DrawLineInSpace(p50, p54);
		window.DrawLineInSpace(p51, p55);
		window.DrawLineInSpace(p52, p56);
		window.DrawLineInSpace(p53, p57);

		window.DrawLineInSpace(p60, p61);
		window.DrawLineInSpace(p61, p62);
		window.DrawLineInSpace(p62, p63);
		window.DrawLineInSpace(p63, p60);
		window.DrawLineInSpace(p64, p65);
		window.DrawLineInSpace(p65, p66);
		window.DrawLineInSpace(p66, p67);
		window.DrawLineInSpace(p67, p64);
		window.DrawLineInSpace(p60, p64);
		window.DrawLineInSpace(p61, p65);
		window.DrawLineInSpace(p62, p66);
		window.DrawLineInSpace(p63, p67);


		//window.DrawLineInSpace(p40, p41);
		window.DrawLineInSpace(p41, p42);
		window.DrawLineInSpace(p42, p43);
		//window.DrawLineInSpace(p43, p40);
		//window.DrawLineInSpace(p44, p45);
		window.DrawLineInSpace(p45, p46);
		//window.DrawLineInSpace(p46, p47);
		//window.DrawLineInSpace(p47, p44);
		window.DrawLineInSpace(p40, p45);
		window.DrawLineInSpace(p41, p45);
		window.DrawLineInSpace(p42, p46);
		window.DrawLineInSpace(p43, p47);
		window.DrawLineInSpace(p40, p47);
		window.DrawLineInSpace(p41, p49);
		window.DrawLineInSpace(p42, p49);
		window.DrawLineInSpace(p41, p48);
		window.DrawLineInSpace(p45, p48);


				if(GetAsyncKeyState(VK_DOWN)) // the DOWN arrow was pressed, let's do something
		{
		delta = -.1;
		viewPos.setY(viewPos.getY() + cos(-viewDir.getAngle())*delta);
		viewPos.setX(viewPos.getX() + sin(-viewDir.getAngle())*delta);
		window.SetViewPosition(viewPos);
		cout << "view pos: " << viewPos.toString() << endl;

		window.DisplayNow();
		Sleep(50);
				}

			if(GetAsyncKeyState(VK_UP)) // the UP arrow was pressed, let's do something
		{
		delta = .1;
		viewPos.setY(viewPos.getY() + cos(-viewDir.getAngle())*delta);
		viewPos.setX(viewPos.getX() + sin(-viewDir.getAngle())*delta);
		window.SetViewPosition(viewPos);
		cout << "view pos: " << viewPos.toString() << endl;

		window.DisplayNow();
		Sleep(50);
				}
				if(GetAsyncKeyState(VK_RIGHT)) // the RIGHT arrow was pressed, let's do something
		{
	
		delta = .1;

		viewDir.setAngle(viewDir.getAngle()+delta);
		window.SetViewDirection(viewDir);
		cout << "view dir: " << viewDir.getAngle() << endl;

		window.DisplayNow();
		Sleep(50);	
			}
			
			if(GetAsyncKeyState(VK_LEFT)) // the LEFT arrow was pressed, let's do something
		{
	
		delta = -.1;

		viewDir.setAngle(viewDir.getAngle()+delta);
		window.SetViewDirection(viewDir);
		cout << "view dir: " << viewDir.getAngle() << endl;

		window.DisplayNow();
		Sleep(50);	
			}

		if(GetAsyncKeyState(VK_ESCAPE))
		{
			return 1;
		}
	}


		
	
}