/// <summary> /// Prepares the polygons. /// </summary> /// <param name="polygon1">The polygon1.</param> /// <param name="polygon2">The polygon2.</param> /// <param name="poly1">The poly1.</param> /// <param name="poly2">The poly2.</param> /// <param name="intersections">The intersections.</param> /// <param name="error">The error.</param> /// <returns></returns> private static int PreparePolygons(Vertices polygon1, Vertices polygon2, out Vertices poly1, out Vertices poly2, out List<EdgeIntersectInfo> intersections, out PolyUnionError error) { error = PolyUnionError.None; // Make a copy of the polygons so that we dont modify the originals, and // force vertices to integer (pixel) values. poly1 = Round(polygon1); poly2 = Round(polygon2); // Find intersection points if (!VerticesIntersect(poly1, poly2, out intersections)) { // No intersections found - polygons do not overlap. error = PolyUnionError.NoIntersections; return -1; } // Add intersection points to original polygons, ignoring existing points. foreach (EdgeIntersectInfo intersect in intersections) { if (!poly1.Contains(intersect.IntersectionPoint)) { poly1.Insert(poly1.IndexOf(intersect.EdgeOne.EdgeStart) + 1, intersect.IntersectionPoint); } if (!poly2.Contains(intersect.IntersectionPoint)) { poly2.Insert(poly2.IndexOf(intersect.EdgeTwo.EdgeStart) + 1, intersect.IntersectionPoint); } } // Find starting point on the edge of polygon1 // that is outside of the intersected area // to begin polygon trace. int startingIndex = -1; int currentIndex = 0; do { if (!PointInPolygonAngle(poly1[currentIndex], poly2)) { startingIndex = currentIndex; break; } currentIndex = poly1.NextIndex(currentIndex); } while (currentIndex != 0); // If we dont find a point on polygon1 thats outside of the // intersect area, the polygon1 must be inside of polygon2, // in which case, polygon2 IS the union of the two. if (startingIndex == -1) { error = PolyUnionError.Poly1InsidePoly2; } return startingIndex; }
/// <summary> /// Prepares the polygons. /// </summary> /// <param name="polygon1">The polygon1.</param> /// <param name="polygon2">The polygon2.</param> /// <param name="poly1">The poly1.</param> /// <param name="poly2">The poly2.</param> /// <param name="intersections">The intersections.</param> /// <param name="error">The error.</param> /// <returns></returns> private static int PreparePolygons(Vertices polygon1, Vertices polygon2, out Vertices poly1, out Vertices poly2, out List <EdgeIntersectInfo> intersections, out PolyUnionError error) { error = PolyUnionError.None; // Make a copy of the polygons so that we dont modify the originals, and // force vertices to integer (pixel) values. poly1 = Round(polygon1); poly2 = Round(polygon2); // Find intersection points if (!VerticesIntersect(poly1, poly2, out intersections)) { // No intersections found - polygons do not overlap. error = PolyUnionError.NoIntersections; return(-1); } // Add intersection points to original polygons, ignoring existing points. foreach (EdgeIntersectInfo intersect in intersections) { if (!poly1.Contains(intersect.IntersectionPoint)) { poly1.Insert(poly1.IndexOf(intersect.EdgeOne.EdgeStart) + 1, intersect.IntersectionPoint); } if (!poly2.Contains(intersect.IntersectionPoint)) { poly2.Insert(poly2.IndexOf(intersect.EdgeTwo.EdgeStart) + 1, intersect.IntersectionPoint); } } // Find starting point on the edge of polygon1 // that is outside of the intersected area // to begin polygon trace. int startingIndex = -1; int currentIndex = 0; do { if (!PointInPolygonAngle(poly1[currentIndex], poly2)) { startingIndex = currentIndex; break; } currentIndex = poly1.NextIndex(currentIndex); } while (currentIndex != 0); // If we dont find a point on polygon1 thats outside of the // intersect area, the polygon1 must be inside of polygon2, // in which case, polygon2 IS the union of the two. if (startingIndex == -1) { error = PolyUnionError.Poly1InsidePoly2; } return(startingIndex); }
/// <summary> /// Finds the intersection between two polygons. /// </summary> /// <param name="polygon1">The first polygon.</param> /// <param name="polygon2">The second polygon.</param> /// <param name="error">The error.</param> /// <returns> /// The intersection of the two polygons, or null if there was an error. /// </returns> public static Vertices Intersect(Vertices polygon1, Vertices polygon2, out PolyUnionError error) { error = PolyUnionError.None; Vertices poly1; Vertices poly2; List<EdgeIntersectInfo> intersections; PolyUnionError gotError; int startingIndex = PreparePolygons(polygon1, polygon2, out poly1, out poly2, out intersections, out gotError); if (startingIndex == -1) { switch (gotError) { case PolyUnionError.NoIntersections: return null; case PolyUnionError.Poly1InsidePoly2: return polygon2; } } Vertices intersectOut = new Vertices(); Vertices currentPoly = poly1; Vertices otherPoly = poly2; // Store the starting vertex so we can refer to it later. int currentIndex = poly1.IndexOf(intersections[0].IntersectionPoint); Vector2 startingVertex = poly1[currentIndex]; do { // Add the current vertex to the final union intersectOut.Add(currentPoly[currentIndex]); foreach (EdgeIntersectInfo intersect in intersections) { // If the current point is an intersection point if (currentPoly[currentIndex] == intersect.IntersectionPoint) { // Make sure we want to swap polygons here. int otherIndex = otherPoly.IndexOf(intersect.IntersectionPoint); // If the next vertex, if we do swap, is inside the current polygon, // then its safe to swap, otherwise, just carry on with the current poly. if (PointInPolygonAngle(otherPoly[otherPoly.NextIndex(otherIndex)], currentPoly)) { // switch polygons if (currentPoly == poly1) { currentPoly = poly2; otherPoly = poly1; } else { currentPoly = poly1; otherPoly = poly2; } // set currentIndex currentIndex = otherIndex; // Stop checking intersections for this point. break; } } } // Move to next index currentIndex = currentPoly.NextIndex(currentIndex); } while ((currentPoly[currentIndex] != startingVertex) && (intersectOut.Count <= (poly1.Count + poly2.Count))); // If the number of vertices in the union is more than the combined vertices // of the input polygons, then something is wrong and the algorithm will // loop forever. Luckily, we check for that. if (intersectOut.Count > (poly1.Count + poly2.Count)) { error = PolyUnionError.InfiniteLoop; } return intersectOut; }
/// <summary> /// Finds the intersection between two polygons. /// </summary> /// <param name="polygon1">The first polygon.</param> /// <param name="polygon2">The second polygon.</param> /// <param name="error">The error.</param> /// <returns> /// The intersection of the two polygons, or null if there was an error. /// </returns> public static Vertices Intersect(Vertices polygon1, Vertices polygon2, out PolyUnionError error) { error = PolyUnionError.None; Vertices poly1; Vertices poly2; List <EdgeIntersectInfo> intersections; PolyUnionError gotError; int startingIndex = PreparePolygons(polygon1, polygon2, out poly1, out poly2, out intersections, out gotError); if (startingIndex == -1) { switch (gotError) { case PolyUnionError.NoIntersections: return(null); case PolyUnionError.Poly1InsidePoly2: return(polygon2); } } Vertices intersectOut = new Vertices(); Vertices currentPoly = poly1; Vertices otherPoly = poly2; // Store the starting vertex so we can refer to it later. int currentIndex = poly1.IndexOf(intersections[0].IntersectionPoint); Vector2 startingVertex = poly1[currentIndex]; do { // Add the current vertex to the final union intersectOut.Add(currentPoly[currentIndex]); foreach (EdgeIntersectInfo intersect in intersections) { // If the current point is an intersection point if (currentPoly[currentIndex] == intersect.IntersectionPoint) { // Make sure we want to swap polygons here. int otherIndex = otherPoly.IndexOf(intersect.IntersectionPoint); // If the next vertex, if we do swap, is inside the current polygon, // then its safe to swap, otherwise, just carry on with the current poly. if (PointInPolygonAngle(otherPoly[otherPoly.NextIndex(otherIndex)], currentPoly)) { // switch polygons if (currentPoly == poly1) { currentPoly = poly2; otherPoly = poly1; } else { currentPoly = poly1; otherPoly = poly2; } // set currentIndex currentIndex = otherIndex; // Stop checking intersections for this point. break; } } } // Move to next index currentIndex = currentPoly.NextIndex(currentIndex); } while ((currentPoly[currentIndex] != startingVertex) && (intersectOut.Count <= (poly1.Count + poly2.Count))); // If the number of vertices in the union is more than the combined vertices // of the input polygons, then something is wrong and the algorithm will // loop forever. Luckily, we check for that. if (intersectOut.Count > (poly1.Count + poly2.Count)) { error = PolyUnionError.InfiniteLoop; } return(intersectOut); }