// From Wikipedia: // One way to triangulate a simple polygon is by using the assertion that any simple polygon // without holes has at least two so called 'ears'. An ear is a triangle with two sides on the edge // of the polygon and the other one completely inside it. The algorithm then consists of finding // such an ear, removing it from the polygon (which results in a new polygon that still meets // the conditions) and repeating until there is only one triangle left. // the algorithm here aims for simplicity over performance. there are other, more performant // algorithms that are much more complex. // convert a triangle to a list of triangles. each triangle is represented by a PointF array of length 3. public static List<PointF[]> Triangulate(Polygon poly) { List<PointF[]> triangles = new List<PointF[]>(); // accumulate the triangles here // keep clipping ears off of poly until only one triangle remains while (poly.PtListOpen.Count > 3) // if only 3 points are left, we have the final triangle { int midvertex = FindEar(poly); // find the middle vertex of the next "ear" triangles.Add(new PointF[] { poly.PtList[midvertex - 1], poly.PtList[midvertex], poly.PtList[midvertex + 1] }); // create a new polygon that clips off the ear; i.e., all vertices but midvertex List<PointF> newPts = new List<PointF>(poly.PtList); newPts.RemoveAt(midvertex); // clip off the ear poly = new Polygon(newPts); // poly now has one less point } // only a single triangle remains, so add it to the triangle list triangles.Add(poly.PtListOpen.ToArray()); return triangles; }
// find the type of a specific vertex in a polygon, either Concave or Convex. public PolygonType VertexType(int vertexNo) { Polygon triangle; if (vertexNo == 0) { triangle = new Polygon(new List<PointF> { PtList[PtList.Count - 2], PtList[0], PtList[1] }); // the polygon is always closed so the last point is the same as the first } else { triangle = new Polygon(new List<PointF> { PtList[vertexNo - 1], PtList[vertexNo], PtList[vertexNo + 1] }); } if (Math.Sign(triangle.Area) == Math.Sign(this.Area)) return PolygonType.Convex; else return PolygonType.Concave; }
// find an ear (always a triangle) of the polygon and return the index of the middle (second) vertex in the ear public static int FindEar(Polygon poly) { for (int i = 0; i < poly.PtList.Count - 2; i++) { if (poly.VertexType(i + 1) == PolygonType.Convex) { // get the three points of the triangle we are about to test PointF a = poly.PtList[i]; PointF b = poly.PtList[i + 1]; PointF c = poly.PtList[i + 2]; bool foundAPointInTheTriangle = false; // see if any of the other points in the polygon are in this triangle for (int j = 0; j < poly.PtListOpen.Count; j++) // don't check the last point, which is a duplicate of the first { if (j != i && j != i+1 && j != i+2 && PointInTriangle(poly.PtList[j], a, b, c)) foundAPointInTheTriangle = true; } if (!foundAPointInTheTriangle) // the middle point of this triangle is convex and none of the other points in the polygon are in this triangle, so it is an ear return i + 1; // EXITING HERE! } } throw new ApplicationException("Improperly formed polygon"); }