/// <summary> /// Check and return polygon intersections /// </summary> /// <param name="polygon1"></param> /// <param name="polygon2"></param> /// <param name="intersections"></param> /// <returns></returns> private bool VerticesIntersect(Point2DList polygon1, Point2DList polygon2, out List<EdgeIntersectInfo> intersections) { intersections = new List<EdgeIntersectInfo>(); double epsilon = Math.Min(polygon1.Epsilon, polygon2.Epsilon); // Iterate through polygon1's edges for (int i = 0; i < polygon1.Count; i++) { // Get edge vertices Point2D p1 = polygon1[i]; Point2D p2 = polygon1[polygon1.NextIndex(i)]; // Get intersections between this edge and polygon2 for (int j = 0; j < polygon2.Count; j++) { Point2D point = new Point2D(); Point2D p3 = polygon2[j]; Point2D p4 = polygon2[polygon2.NextIndex(j)]; // Check if the edges intersect if (TriangulationUtil.LinesIntersect2D(p1, p2, p3, p4, ref point, epsilon)) { // Rounding is not needed since we compare using an epsilon. //// Here, we round the returned intersection point to its nearest whole number. //// This prevents floating point anomolies where 99.9999-> is returned instead of 100. //point = new Point2D((float)Math.Round(point.X, 0), (float)Math.Round(point.Y, 0)); // Record the intersection intersections.Add(new EdgeIntersectInfo(new Edge(p1, p2), new Edge(p3, p4), point)); } } } // true if any intersections were found. return (intersections.Count > 0); }
/// <summary> /// * ref: http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/ - Solution 2 /// * Compute the sum of the angles made between the test point and each pair of points making up the polygon. /// * If this sum is 2pi then the point is an interior point, if 0 then the point is an exterior point. /// </summary> public bool PointInPolygonAngle(Point2D point, Point2DList polygon) { double angle = 0; // Iterate through polygon's edges for (int i = 0; i < polygon.Count; i++) { // Get points Point2D p1 = polygon[i] - point; Point2D p2 = polygon[polygon.NextIndex(i)] - point; angle += VectorAngle(p1, p2); } if (Math.Abs(angle) < Math.PI) { return false; } return true; }
public bool Init(PolygonUtil.PolyOperation operations, Point2DList polygon1, Point2DList polygon2) { Clear(); mOperations = operations; mOriginalPolygon1 = polygon1; mOriginalPolygon2 = polygon2; // Make a copy of the polygons so that we dont modify the originals, and // force vertices to integer (pixel) values. mPoly1 = new Point2DList(polygon1); mPoly1.WindingOrder = Point2DList.WindingOrderType.Default; mPoly2 = new Point2DList(polygon2); mPoly2.WindingOrder = Point2DList.WindingOrderType.Default; // Find intersection points if (!VerticesIntersect(mPoly1, mPoly2, out mIntersections)) { // No intersections found - polygons do not overlap. mError = PolygonUtil.PolyUnionError.NoIntersections; return false; } // make sure edges that intersect more than once are updated to have correct start points int numIntersections = mIntersections.Count; for (int i = 0; i < numIntersections; ++i) { for (int j = i + 1; j < numIntersections; ++j) { if (mIntersections[i].EdgeOne.EdgeStart.Equals(mIntersections[j].EdgeOne.EdgeStart) && mIntersections[i].EdgeOne.EdgeEnd.Equals(mIntersections[j].EdgeOne.EdgeEnd)) { mIntersections[j].EdgeOne.EdgeStart = mIntersections[i].IntersectionPoint; } if (mIntersections[i].EdgeTwo.EdgeStart.Equals(mIntersections[j].EdgeTwo.EdgeStart) && mIntersections[i].EdgeTwo.EdgeEnd.Equals(mIntersections[j].EdgeTwo.EdgeEnd)) { mIntersections[j].EdgeTwo.EdgeStart = mIntersections[i].IntersectionPoint; } } } // Add intersection points to original polygons, ignoring existing points. foreach (EdgeIntersectInfo intersect in mIntersections) { if (!mPoly1.Contains(intersect.IntersectionPoint)) { mPoly1.Insert(mPoly1.IndexOf(intersect.EdgeOne.EdgeStart) + 1, intersect.IntersectionPoint); } if (!mPoly2.Contains(intersect.IntersectionPoint)) { mPoly2.Insert(mPoly2.IndexOf(intersect.EdgeTwo.EdgeStart) + 1, intersect.IntersectionPoint); } } mPoly1VectorAngles = new List<int>(); for (int i = 0; i < mPoly2.Count; ++i) { mPoly1VectorAngles.Add(-1); } mPoly2VectorAngles = new List<int>(); for (int i = 0; i < mPoly1.Count; ++i) { mPoly2VectorAngles.Add(-1); } // Find starting point on the edge of polygon1 that is outside of // the intersected area to begin polygon trace. int currentIndex = 0; do { bool bPointInPolygonAngle = PointInPolygonAngle(mPoly1[currentIndex], mPoly2); mPoly2VectorAngles[currentIndex] = bPointInPolygonAngle ? 1 : 0; if (bPointInPolygonAngle) { mStartingIndex = currentIndex; break; } currentIndex = mPoly1.NextIndex(currentIndex); } while (currentIndex != 0); // If we don't 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 (mStartingIndex == -1) { mError = PolygonUtil.PolyUnionError.Poly1InsidePoly2; return false; } return true; }