public static double ComputeSignedArea(Polygon polygon) { int i; double area = 0; Vertices vertices = polygon.Vertices; for (i = 0; i < vertices.Count; i++) { int j = (i + 1)%vertices.Count; area += vertices[i].X*vertices[j].Y; area -= vertices[i].Y*vertices[j].X; } area /= 2.0; return area; }
/// <summary> /// Winding number test for a point in a polygon. /// </summary> /// See more info about the algorithm here: http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm /// <param name="point">The point to be tested.</param> /// <returns>-1 if the winding number is zero and the point is outside /// the polygon, 1 if the point is inside the polygon, and 0 if the point /// is on the polygons edge.</returns> public static int PointInPolygon(Polygon polygon, Vector2D point) { // Winding number int wn = 0; Vertices polyVertices = polygon.Vertices; // Iterate through polygon's edges for (int i = 0; i < polyVertices.Count; i++) { // Get points Vector2D p1 = polyVertices[i]; Vector2D p2 = polyVertices[polyVertices.NextIndex(i)]; // Test if a point is directly on the edge Vector2D edge = p2 - p1; double area = MathHelper.Area(ref p1, ref p2, ref point); if (Math.Abs(area - 0f) < MathHelper.EpsilonD && Vector2D.Dot(point - p1, edge) >= 0 && Vector2D.Dot(point - p2, edge) <= 0) { return 0; } // Test edge for intersection with ray from point if (p1.Y <= point.Y) { if (p2.Y > point.Y && area > 0) { ++wn; } } else { if (p2.Y <= point.Y && area < 0) { --wn; } } } return wn; }
public static bool PolygonHitTest(Polygon polygon, Vector2D p) { double angle = 0; Vector2D p1 = new Vector2D(); Vector2D p2 = new Vector2D(); for (int i = 0; i < polygon.Vertices.Count; i++) { p1.X = polygon.Vertices[i].X - p.X; p1.Y = polygon.Vertices[i].Y - p.Y; p2.X = polygon.Vertices[(i + 1)%polygon.Vertices.Count].X - p.X; p2.Y = polygon.Vertices[(i + 1)%polygon.Vertices.Count].Y - p.Y; angle += Angle2D(p1.X, p1.Y, p2.X, p2.Y); } if (Math.Abs(angle) < Math.PI) return false; else return true; }
public static Vector2D ComputeCentroid(Polygon polygon) { Vector2D centroid = new Vector2D(0, 0); double signedArea = 0.0f; double x0; // Current vertex X double y0; // Current vertex Y double x1; // Next vertex X double y1; // Next vertex Y double a; // Partial signed area Vector2D[] vertices = polygon.Vertices.ToArray(); // For all vertices except last int i; for (i = 0; i < polygon.Vertices.Count - 1; ++i) { x0 = vertices[i].X; y0 = vertices[i].Y; x1 = vertices[i + 1].X; y1 = vertices[i + 1].Y; a = x0*y1 - x1*y0; signedArea += a; centroid.X += (x0 + x1)*a; centroid.Y += (y0 + y1)*a; } // Do last vertex x0 = vertices[i].X; y0 = vertices[i].Y; x1 = vertices[0].X; y1 = vertices[0].Y; a = x0*y1 - x1*y0; signedArea += a; centroid.X += (x0 + x1)*a; centroid.Y += (y0 + y1)*a; signedArea *= 0.5f; centroid.X /= (6*signedArea); centroid.Y /= (6*signedArea); return centroid; }
public static bool ConvexityTest(Polygon polygon) { if (polygon.Vertices.Count < 3) return false; int xCh = 0, yCh = 0; Vector2D a = polygon.Vertices[0] - polygon.Vertices[polygon.Vertices.Count - 1]; for (int i = 0; i < polygon.Vertices.Count - 1; ++i) { Vector2D b = polygon.Vertices[i] - polygon.Vertices[i + 1]; if (Math.Sign(a.X) != Math.Sign(b.X)) ++xCh; if (Math.Sign(a.Y) != Math.Sign(b.Y)) ++yCh; a = b; } return (xCh <= 2 && yCh <= 2); }
public static ushort[] TriangulateBrute(IList<Vector2D> vertex) { int n = vertex.Count; bool pointValid; List<ushort> indices = new List<ushort>(); for (int i = 0;i < n - 2; i++) { for (int j = i + 1; j < n - 1; j++) { for (int k = j + 1; k < n; k++) { Circle circle = Circle.CircumCircle(vertex[i], vertex[j], vertex[k]); pointValid = true; for (int l = 0; l < n; l++) { if(l == i || l == j || l == k) continue; if(!circle.IsInside(vertex[l])) continue; pointValid = false; break; } if(pointValid) { // Add triangle as graph links Polygon t = new Polygon(new[] {vertex[i],vertex[j], vertex[k]} ); double a = Polygon.ComputeSignedArea(t); if (a > 0) indices.AddRange(new[] { (ushort)k, (ushort)j, (ushort)i }); else indices.AddRange(new[] { (ushort)i, (ushort)j, (ushort)k }); } } } } return indices.ToArray(); }