// find the type of a specific vertex in a polygon, either Concave or Convex. public PolygonType VertexType(int vertexNo) { PolygonData triangle; if (vertexNo == 0) { triangle = new PolygonData(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 PolygonData(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); } }
// 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(PolygonData 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 PolygonData(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 an ear (always a triangle) of the polygon and return the index of the middle (second) vertex in the ear public static int FindEar(PolygonData 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"); }
/// <summary> /// This method returns a 3D representation of this area /// </summary> /// <param name="nodesDict">List of all the nodes on the map</param> /// <param name="map">bounds of the map</param> /// <param name="brush">Color of this area</param> /// <returns>ModelUIElement3D of this area</returns> public virtual ModelUIElement3D get3DSurface(Dictionary<long, OsmSharp.Osm.Node> nodesDict, Map map, System.Windows.Media.SolidColorBrush brush) { List<PointF> ptlist = getScaledPointsSurface(nodesDict, map); // Divide the polygons in triangles, this is code (and these two classes) are from: https://polygontriangulation.codeplex.com/ PolygonData poly = new PolygonData(ptlist); List<PointF[]> triangles = Triangulation2D.Triangulate(poly); // Surrounding tags of the mesh ModelUIElement3D model = new ModelUIElement3D(); GeometryModel3D geometryModel = new GeometryModel3D(); // Mesh and his his properties MeshGeometry3D mesh = new MeshGeometry3D(); DiffuseMaterial material = new DiffuseMaterial((System.Windows.Media.Brush)brush); Point3DCollection positions = new Point3DCollection(); Int32Collection indices = new Int32Collection(); // Add points and indices to their collection foreach (PointF[] points in triangles) { foreach (PointF point in points) { positions.Add(new Point3D(point.X, point.Y, height)); } int count = positions.Count; indices.Add(count - 3); indices.Add(count - 2); indices.Add(count - 1); } // Add these collections to the mesh mesh.Positions = positions; mesh.TriangleIndices = indices; // Set the color of front and back of the triangle geometryModel.Material = material; geometryModel.BackMaterial = material; // Add the mesh to the model geometryModel.Geometry = mesh; model.Model = geometryModel; return model; }
// find the type of a specific vertex in a polygon, either Concave or Convex. public PolygonType VertexType(int vertexNo) { PolygonData triangle; if (vertexNo == 0) { triangle = new PolygonData(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 PolygonData(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; }