public static PolygonUtil.PolyUnionError PolygonOperation(PolygonOperationContext ctx) { if ((ctx.mOperations & PolygonUtil.PolyOperation.Union) == PolygonUtil.PolyOperation.Union) { PolygonUtil.PolygonUnionInternal(ctx); } if ((ctx.mOperations & PolygonUtil.PolyOperation.Intersect) == PolygonUtil.PolyOperation.Intersect) { PolygonUtil.PolygonIntersectInternal(ctx); } if ((ctx.mOperations & PolygonUtil.PolyOperation.Subtract) == PolygonUtil.PolyOperation.Subtract) { PolygonUtil.PolygonSubtractInternal(ctx); } return ctx.mError; }
/// <summary> /// Performs one or more polygon operations on the 2 provided polygons /// </summary> /// <param name="polygon1">The first polygon.</param> /// <param name="polygon2">The second polygon</param> /// <param name="subtract">The result of the polygon subtraction</param> /// <returns>error code</returns> public static PolygonUtil.PolyUnionError PolygonOperation(PolygonUtil.PolyOperation operations, Point2DList polygon1, Point2DList polygon2, out Dictionary<uint, Point2DList> results) { PolygonOperationContext ctx = new PolygonOperationContext(); ctx.Init(operations, polygon1, polygon2); results = ctx.mOutput; return PolygonUtil.PolygonOperation(ctx); }
public static void PolygonSubtractInternal(PolygonOperationContext ctx) { Point2DList subtract = ctx.Subtract; if (ctx.mStartingIndex == -1) { switch (ctx.mError) { case PolygonUtil.PolyUnionError.NoIntersections: case PolygonUtil.PolyUnionError.InfiniteLoop: case PolygonUtil.PolyUnionError.Poly1InsidePoly2: return; } } Point2DList currentPoly = ctx.mPoly1; Point2DList otherPoly = ctx.mPoly2; List<int> currentPolyVectorAngles = ctx.mPoly1VectorAngles; // Store the starting vertex so we can refer to it later. Point2D startingVertex = ctx.mPoly1[ctx.mStartingIndex]; int currentIndex = ctx.mStartingIndex; subtract.Clear(); // Trace direction bool forward = true; do { // Add the current vertex to the final union subtract.Add(currentPoly[currentIndex]); foreach (EdgeIntersectInfo intersect in ctx.mIntersections) { // If the current point is an intersection point if (currentPoly[currentIndex].Equals(intersect.IntersectionPoint, currentPoly.Epsilon)) { // Make sure we want to swap polygons here. int otherIndex = otherPoly.IndexOf(intersect.IntersectionPoint); //Point2D otherVertex; if (forward) { // 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. int compareIndex = otherPoly.PreviousIndex(otherIndex); Point2D compareVertex = otherPoly[compareIndex]; bool bPointInPolygonAngle = false; if (currentPolyVectorAngles[compareIndex] == -1) { bPointInPolygonAngle = ctx.PointInPolygonAngle(compareVertex, currentPoly); currentPolyVectorAngles[compareIndex] = bPointInPolygonAngle ? 1 : 0; } else { bPointInPolygonAngle = (currentPolyVectorAngles[compareIndex] == 1) ? true : false; } if (bPointInPolygonAngle) { // switch polygons if (currentPoly == ctx.mPoly1) { currentPoly = ctx.mPoly2; currentPolyVectorAngles = ctx.mPoly2VectorAngles; otherPoly = ctx.mPoly1; } else { currentPoly = ctx.mPoly1; currentPolyVectorAngles = ctx.mPoly1VectorAngles; otherPoly = ctx.mPoly2; } // set currentIndex currentIndex = otherIndex; // Reverse direction forward = !forward; // Stop checking ctx.mIntersections for this point. break; } } else { // If the next vertex, if we do swap, is outside the current polygon, // then its safe to swap, otherwise, just carry on with the current poly. int compareIndex = otherPoly.NextIndex(otherIndex); Point2D compareVertex = otherPoly[compareIndex]; bool bPointInPolygonAngle = false; if (currentPolyVectorAngles[compareIndex] == -1) { bPointInPolygonAngle = ctx.PointInPolygonAngle(compareVertex, currentPoly); currentPolyVectorAngles[compareIndex] = bPointInPolygonAngle ? 1 : 0; } else { bPointInPolygonAngle = (currentPolyVectorAngles[compareIndex] == 1) ? true : false; } if (!bPointInPolygonAngle) { // switch polygons if (currentPoly == ctx.mPoly1) { currentPoly = ctx.mPoly2; currentPolyVectorAngles = ctx.mPoly2VectorAngles; otherPoly = ctx.mPoly1; } else { currentPoly = ctx.mPoly1; currentPolyVectorAngles = ctx.mPoly1VectorAngles; otherPoly = ctx.mPoly2; } // set currentIndex currentIndex = otherIndex; // Reverse direction forward = !forward; // Stop checking intersections for this point. break; } } } } if (forward) { // Move to next index currentIndex = currentPoly.NextIndex(currentIndex); } else { currentIndex = currentPoly.PreviousIndex(currentIndex); } } while ((currentPoly[currentIndex] != startingVertex) && (subtract.Count <= (ctx.mPoly1.Count + ctx.mPoly2.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 (subtract.Count > (ctx.mPoly1.Count + ctx.mPoly2.Count)) { ctx.mError = PolygonUtil.PolyUnionError.InfiniteLoop; } return; }
/// <summary> /// Subtracts one polygon from another. /// </summary> /// <param name="polygon1">The base polygon.</param> /// <param name="polygon2">The polygon to subtract from the base.</param> /// <param name="subtract">The result of the polygon subtraction</param> /// <returns>error code</returns> public static PolygonUtil.PolyUnionError PolygonSubtract(Point2DList polygon1, Point2DList polygon2, out Point2DList subtract) { PolygonOperationContext ctx = new PolygonOperationContext(); ctx.Init(PolygonUtil.PolyOperation.Subtract, polygon1, polygon2); PolygonSubtractInternal(ctx); subtract = ctx.Subtract; return ctx.mError; }
protected static void PolygonIntersectInternal(PolygonOperationContext ctx) { Point2DList intersectOut = ctx.Intersect; if (ctx.mStartingIndex == -1) { switch (ctx.mError) { case PolygonUtil.PolyUnionError.NoIntersections: case PolygonUtil.PolyUnionError.InfiniteLoop: return; case PolygonUtil.PolyUnionError.Poly1InsidePoly2: intersectOut.AddRange(ctx.mOriginalPolygon2); return; } } Point2DList currentPoly = ctx.mPoly1; Point2DList otherPoly = ctx.mPoly2; List<int> currentPolyVectorAngles = ctx.mPoly1VectorAngles; // Store the starting vertex so we can refer to it later. int currentIndex = ctx.mPoly1.IndexOf(ctx.mIntersections[0].IntersectionPoint); Point2D startingVertex = ctx.mPoly1[currentIndex]; int firstPoly1Index = currentIndex; int firstPoly2Index = -1; intersectOut.Clear(); do { // Add the current vertex to the final intersection if (intersectOut.Contains(currentPoly[currentIndex])) { // This can happen when the two polygons only share a single edge, and neither is inside the other break; } intersectOut.Add(currentPoly[currentIndex]); foreach (EdgeIntersectInfo intersect in ctx.mIntersections) { // If the current point is an intersection point if (currentPoly[currentIndex].Equals(intersect.IntersectionPoint, currentPoly.Epsilon)) { // 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. int comparePointIndex = otherPoly.NextIndex(otherIndex); Point2D comparePoint = otherPoly[comparePointIndex]; bool bPointInPolygonAngle = false; if (currentPolyVectorAngles[comparePointIndex] == -1) { bPointInPolygonAngle = ctx.PointInPolygonAngle(comparePoint, currentPoly); currentPolyVectorAngles[comparePointIndex] = bPointInPolygonAngle ? 1 : 0; } else { bPointInPolygonAngle = (currentPolyVectorAngles[comparePointIndex] == 1) ? true : false; } if (bPointInPolygonAngle) { // switch polygons if (currentPoly == ctx.mPoly1) { currentPoly = ctx.mPoly2; currentPolyVectorAngles = ctx.mPoly2VectorAngles; otherPoly = ctx.mPoly1; if (firstPoly2Index < 0) { firstPoly2Index = otherIndex; } } else { currentPoly = ctx.mPoly1; currentPolyVectorAngles = ctx.mPoly1VectorAngles; otherPoly = ctx.mPoly2; } // set currentIndex currentIndex = otherIndex; // Stop checking intersections for this point. break; } } } // Move to next index currentIndex = currentPoly.NextIndex(currentIndex); if (currentPoly == ctx.mPoly1) { if (currentIndex == firstPoly1Index) { break; } } else { if (firstPoly2Index >= 0 && currentIndex == firstPoly2Index) { break; } } } while ((currentPoly[currentIndex] != startingVertex) && (intersectOut.Count <= (ctx.mPoly1.Count + ctx.mPoly2.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 > (ctx.mPoly1.Count + ctx.mPoly2.Count)) { ctx.mError = PolygonUtil.PolyUnionError.InfiniteLoop; } return; }
/// Merges two polygons, given that they intersect. /// </summary> /// <param name="polygon1">The first polygon.</param> /// <param name="polygon2">The second polygon.</param> /// <param name="union">The union of the two polygons</param> /// <returns>The error returned from union</returns> public static PolygonUtil.PolyUnionError PolygonUnion(Point2DList polygon1, Point2DList polygon2, out Point2DList union) { PolygonOperationContext ctx = new PolygonOperationContext(); ctx.Init(PolygonUtil.PolyOperation.Union, polygon1, polygon2); PolygonUnionInternal(ctx); union = ctx.Union; return ctx.mError; }