// // Line-plane intersection // //2d public static bool LinePlane(Plane2 plane, Edge2 line) { //To avoid floating point precision issues we can add a small value float epsilon = MathUtility.EPSILON; bool areIntersecting = false; MyVector2 lineDir = MyVector2.Normalize(line.p1 - line.p2); float denominator = MyVector2.Dot(-plane.normal, lineDir); //Debug.Log(denominator); //No intersection if the line and plane are perpendicular if (denominator > epsilon || denominator < -epsilon) { MyVector2 vecBetween = plane.pos - line.p1; float t = MyVector2.Dot(vecBetween, -plane.normal) / denominator; MyVector2 intersectionPoint = line.p1 + lineDir * t; //Gizmos.DrawWireSphere(intersectionPoint, 0.5f); if (_Geometry.IsPointBetweenPoints(line.p1, line.p2, intersectionPoint)) { areIntersecting = true; } } return(areIntersecting); }
// // Ray-plane intersection // http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection // //2d public static bool RayPlane(Plane2 plane, Ray2 ray) { //To avoid floating point precision issues we can add a small value float epsilon = MathUtility.EPSILON; bool areIntersecting = false; float denominator = MyVector2.Dot(plane.normal * -1f, ray.dir); //Debug.Log(denominator); //The ray has to point at the surface of the plane //The surface of the plane is determined by the normal if (denominator > epsilon) { //Now we have to figur out of the ray starts "inside" of the plane //meaning on the other side of the normal //If so it can't hit the plane MyVector2 vecBetween = plane.pos - ray.origin; float t = MyVector2.Dot(vecBetween, plane.normal * -1f) / denominator; //Debug.Log(t); if (t >= 0f) { areIntersecting = true; } } return(areIntersecting); }
//If we know two planes are intersecting, what's the point of intersection? //2d public static MyVector2 GetPlanePlaneIntersectionPoint(Plane2 plane_1, Plane2 plane_2) { MyVector2 lineDir = MyVector2.Normalize(new MyVector2(plane_2.normal.y, -plane_2.normal.x)); Ray2 ray = new Ray2(plane_2.pos, lineDir); MyVector2 intersectionPoint = GetIntersectionCoordinate(plane_1, ray); return(intersectionPoint); }
//We know a line plane is intersecting and now we want the coordinate of intersection //2d public static MyVector2 GetLinePlaneIntersectionPoint(Plane2 plane, Edge2 line) { MyVector2 lineDir = MyVector2.Normalize(line.p1 - line.p2); Ray2 ray = new Ray2(line.p1, lineDir); MyVector2 intersectionPoint = GetIntersectionCoordinate(plane, ray); return(intersectionPoint); }
// // Line, plane, ray intersection with plane // //This is a useful method to find the intersection coordinate if we know we are intersecting //Is used for ray-plane, line-plane, plane-plane //2d private static MyVector2 GetIntersectionCoordinate(Plane2 plane, Ray2 ray) { float denominator = MyVector2.Dot(-plane.normal, ray.dir); MyVector2 vecBetween = plane.pos - ray.origin; float t = MyVector2.Dot(vecBetween, -plane.normal) / denominator; MyVector2 intersectionPoint = ray.origin + ray.dir * t; return(intersectionPoint); }
//Find the point which is furthest away from an edge private static MyVector2 FindPointFurthestFromEdge(MyVector2 p1, MyVector2 p2, HashSet <MyVector2> points) { //Just init the third point MyVector2 p3 = new MyVector2(0f, 0f); //Set max distance to something small float maxDistanceToEdge = -Mathf.Infinity; //The direction of the edge so we can create the normal (doesnt matter in which way it points) MyVector2 edgeDir = p2 - p1; //We dont need to normalize this normal MyVector2 edgeNormal = new MyVector2(edgeDir.y, -edgeDir.x); //Find the actual third point foreach (MyVector2 p in points) { //The distance between this point and the edge is the same as the distance between //the point and the plane Plane2 plane = new Plane2(p1, edgeNormal); float distanceToEdge = _Geometry.GetSignedDistanceFromPointToPlane(plane, p); //The distance can be negative if we are behind the plane //and because we just picked a normal out of nowhere, we have to make sure //the distance is positive if (distanceToEdge < 0f) { distanceToEdge *= -1f; } //This point is better if (distanceToEdge > maxDistanceToEdge) { maxDistanceToEdge = distanceToEdge; p3 = p; } } return(p3); }
// // Plane-plane intersection // //2d public static bool PlanePlane(Plane2 plane_1, Plane2 plane_2) { bool areIntersecting = false; float dot = MyVector2.Dot(plane_1.normal, plane_2.normal); //Debug.Log(dot); //No intersection if the planes are parallell //The are parallell if the dot product is 1 or -1 //To avoid floating point precision issues we can add a small value float one = 1f - MathUtility.EPSILON; if (dot < one && dot > -one) { areIntersecting = true; } return(areIntersecting); }
//Assumes the polygons are oriented counter clockwise //poly is the polygon we want to cut //Assumes the polygon we want to remove from the other polygon is convex, so clipPolygon has to be convex //We will end up with the intersection of the polygons public static List <MyVector2> ClipPolygon(List <MyVector2> poly, List <Plane2> clippingPlanes) { //Clone the vertices because we will remove vertices from this list List <MyVector2> vertices = new List <MyVector2>(poly); //Save the new vertices temporarily in this list before transfering them to vertices List <MyVector2> vertices_tmp = new List <MyVector2>(); //Clip the polygon for (int i = 0; i < clippingPlanes.Count; i++) { Plane2 plane = clippingPlanes[i]; for (int j = 0; j < vertices.Count; j++) { int jPlusOne = MathUtility.ClampListIndex(j + 1, vertices.Count); MyVector2 v1 = vertices[j]; MyVector2 v2 = vertices[jPlusOne]; //Calculate the distance to the plane from each vertex //This is how we will know if they are inside or outside //If they are inside, the distance is positive, which is why the planes normals have to be oriented to the inside float dist_to_v1 = _Geometry.DistanceFromPointToPlane(plane.normal, plane.pos, v1); float dist_to_v2 = _Geometry.DistanceFromPointToPlane(plane.normal, plane.pos, v2); //TODO: What will happen if they are exactly 0? Should maybe use a tolerance of 0.001 //Case 1. Both are outside (= to the right), do nothing //Case 2. Both are inside (= to the left), save v2 if (dist_to_v1 >= 0f && dist_to_v2 >= 0f) { vertices_tmp.Add(v2); } //Case 3. Outside -> Inside, save intersection point and v2 else if (dist_to_v1 < 0f && dist_to_v2 >= 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane.pos, plane.normal, v1, rayDir); vertices_tmp.Add(intersectionPoint); vertices_tmp.Add(v2); } //Case 4. Inside -> Outside, save intersection point else if (dist_to_v1 >= 0f && dist_to_v2 < 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane.pos, plane.normal, v1, rayDir); vertices_tmp.Add(intersectionPoint); } } //Add the new vertices to the list of vertices vertices.Clear(); vertices.AddRange(vertices_tmp); vertices_tmp.Clear(); } return(vertices); }
//Get the coordinate if we know a ray-plane is intersecting //2d public static MyVector2 GetRayPlaneIntersectionPoint(Plane2 plane, Ray2 ray) { MyVector2 intersectionPoint = GetIntersectionCoordinate(plane, ray); return(intersectionPoint); }
//The original algorithm calculates the intersection between two polygons, this will instead get the outside //Assumes the polygons are oriented counter clockwise //poly is the polygon we want to cut //Assumes the polygon we want to remove from the other polygon is convex, so clipPolygon has to be convex //We will end up with the !intersection of the polygons public static List <List <MyVector2> > ClipPolygonInverted(List <MyVector2> poly, List <Plane2> clippingPlanes) { //The result may be more than one polygons List <List <MyVector2> > finalPolygons = new List <List <MyVector2> >(); List <MyVector2> vertices = new List <MyVector2>(poly); //The remaining polygon after each cut List <MyVector2> vertices_tmp = new List <MyVector2>(); //Clip the polygon for (int i = 0; i < clippingPlanes.Count; i++) { Plane2 plane = clippingPlanes[i]; //A new polygon which is the part of the polygon which is outside of this plane List <MyVector2> outsidePolygon = new List <MyVector2>(); for (int j = 0; j < vertices.Count; j++) { int jPlusOne = MathUtility.ClampListIndex(j + 1, vertices.Count); MyVector2 v1 = vertices[j]; MyVector2 v2 = vertices[jPlusOne]; //Calculate the distance to the plane from each vertex //This is how we will know if they are inside or outside //If they are inside, the distance is positive, which is why the planes normals have to be oriented to the inside float dist_to_v1 = _Geometry.GetSignedDistanceFromPointToPlane(v1, plane); float dist_to_v2 = _Geometry.GetSignedDistanceFromPointToPlane(v2, plane); //TODO: What will happen if they are exactly 0? //Case 1. Both are inside (= to the left), save v2 to the other polygon if (dist_to_v1 >= 0f && dist_to_v2 >= 0f) { vertices_tmp.Add(v2); } //Case 2. Both are outside (= to the right), save v1 else if (dist_to_v1 < 0f && dist_to_v2 < 0f) { outsidePolygon.Add(v2); } //Case 3. Outside -> Inside, save intersection point else if (dist_to_v1 < 0f && dist_to_v2 >= 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); outsidePolygon.Add(intersectionPoint); vertices_tmp.Add(intersectionPoint); vertices_tmp.Add(v2); } //Case 4. Inside -> Outside, save intersection point and v2 else if (dist_to_v1 >= 0f && dist_to_v2 < 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); outsidePolygon.Add(intersectionPoint); outsidePolygon.Add(v2); vertices_tmp.Add(intersectionPoint); } } //Add the polygon outside of this plane to the list of all polygons that are outside of all planes if (outsidePolygon.Count > 0) { finalPolygons.Add(outsidePolygon); } //Add the polygon which was inside of this and previous planes to the polygon we want to test vertices.Clear(); vertices.AddRange(vertices_tmp); vertices_tmp.Clear(); } return(finalPolygons); }
//2d public static float GetSignedDistanceFromPointToPlane(Plane2 plane, MyVector2 pointPos) { float distance = MyVector2.Dot(plane.normal, pointPos - plane.pos); return(distance); }