/// <summary> /// Create a simple shallow copy of these mesh faces /// </summary> /// <returns></returns> public MeshFaceCollection FastDuplicate() { var result = new MeshFaceCollection(); foreach (MeshFace face in this) { result.Add(new MeshFace(face)); } return(result); }
/// <summary> /// Initialise a mesh with the specified vertices and faces. /// The vertices used should not already form part of any other geometry definition. /// </summary> /// <param name="verts"></param> /// <param name="faces"></param> public Mesh(VertexCollection verts, MeshFaceCollection faces) : this() { foreach (Vertex v in verts) { Vertices.Add(v); } foreach (MeshFace f in faces) { Faces.Add(f); } }
/// <summary> /// Get all mesh faces in this collection that contain any vertices /// shared with the specified vertex collection /// </summary> /// <param name="vertices"></param> /// <returns></returns> public MeshFaceCollection AllWithVertices(VertexCollection vertices) { var result = new MeshFaceCollection(); foreach (MeshFace face in this) { if (face.ContainsAnyVertex(vertices)) { result.Add(face); } } return(result); }
/// <summary> /// Refine and subdivide the faces in this collection to /// reduce the maximum edge length below the specified /// </summary> /// <param name="maxEdgeLength"></param> /// <returns></returns> public MeshFaceCollection Refine(double maxEdgeLength) { MeshFaceCollection result = new MeshFaceCollection(); ExtractVertices().AssignVertexIndices(1); var edges = new MeshDivisionEdgeCollection(this); edges.SubDivideAll(maxEdgeLength); foreach (var face in this) { var faceEdges = edges.GetEdgesForFace(face); face.Refine(faceEdges, result); } return(result); }
/// <summary> /// Trim this collection of faces to only those which fit within the specified boundary polygon /// on the XY plane /// </summary> /// <param name="boundary"></param> /// <param name="vertices">Optional. The collection of vertices to which new vertices created during /// this process should be added.</param> /// <returns></returns> public MeshFaceCollection TrimToPolygonXY(IList <Vertex> boundary, IList <Vertex> vertices = null) { MeshFaceCollection result = new MeshFaceCollection(); foreach (MeshFace face in this) { IList <MeshFace> splitFaces = Intersect.PolygonOverlapXY <MeshFace>(face, boundary, vertices); if (splitFaces != null) { foreach (MeshFace sFace in splitFaces) { result.Add(sFace); } } } return(result); }
/// <summary> /// Convert a set of mesh faces generated via delaunay triangulation into its dual - /// the voronoi diagram of the vertices. /// </summary> /// <param name="triangles"></param> /// <returns></returns> public static Dictionary <Vertex, MeshFace> VoronoiFromDelaunay(VertexCollection vertices, MeshFaceCollection faces, bool weighted = false) { var cells = new Dictionary <Vertex, MeshFace>(); //The generated voronoi cells foreach (Vertex v in vertices) { cells.Add(v, new MeshFace()); //Create empty cells } foreach (MeshFace face in faces) { Vertex newVert; if (weighted) { face.WeightedVoronoiPoints(cells); } else { newVert = new Vertex(face.XYCircumcentre); foreach (Vertex v in face) { if (cells.ContainsKey(v)) { MeshFace cell = cells[v]; cell.Add(newVert); } } } } //TODO: Deal with cells on the edge //Sort cell vertices anticlockwise around vertex foreach (KeyValuePair <Vertex, MeshFace> kvp in cells) { kvp.Value.SortVerticesAntiClockwise(kvp.Key.Position); } return(cells); }
/// <summary> /// Generate a set of mesh faces that represent a delaunay triangulation in the XY plane of the /// specified set of vertices. /// Based on the algorithm described here: http://paulbourke.net/papers/triangulate/ /// </summary> /// <param name="vertices">The vertices to mesh between</param> /// <param name="faces">Optional. The face collection to which to add the triangles. /// If null or ommitted, a new MeshFaceCollection will be created.</param> /// <param name="bounds">The bounding box that contains the triangulation. Should encompass all vertices /// and, for later voronoi generation, any bounding geometry. If null, the bounding box of the vertices /// themselves will be used.</param> /// <param name="clean">Clean up construction Super Triangle. If true, any remaining fragments of the /// initial generating supertriangle will be removed from the output face list. Set this to false /// if planning on using this mesh for subsequent voronoi generation so that the edge cells can be extended.</param> /// <param name="outerVerts">Optional. If input and non-null, this collection will be populated with the exterior vertices - those connected /// to the original supertriangle. If 'clean' is false, this will instead return the supertriangle vertices.</param> public static MeshFaceCollection DelaunayTriangulationXY(VertexCollection vertices, MeshFaceCollection faces = null, BoundingBox bounds = null, bool clean = true, VertexCollection outerVerts = null) { List <Vertex> vertexList = vertices.ToList(); vertexList.Sort(); if (faces == null) { faces = new MeshFaceCollection(); } if (bounds == null) { bounds = new BoundingBox(vertexList); } else { bounds = new BoundingBox(bounds); } bounds.Scale(5); //Provide a little wriggle room! // Meshing starts with one 'super triangle' that encloses all vertices. // This will be removed at the end MeshFace superTriangle = DelaunayTriangle.GenerateSuperTriangleXY(bounds); faces.Add(superTriangle); // Include each vertex in the meshing one at a time foreach (Vertex v in vertexList) { //for (int k = 0; k < 8; k++) //{ // Vertex v = vertexList[k]; // if (k == 7) // { // bool bum = true; // } IList <MeshEdge> edges = new List <MeshEdge>(); //The edges of replaced triangles for (int i = faces.Count - 1; i >= 0; i--) { MeshFace face = faces[i]; if (face.XYCircumcircleContainmentQuickCheck(v)) //The vertex lies within the circumcircle of this face { //The edges of the triangle are added to the current edge set... for (int j = 0; j < face.Count; j++) { edges.Add(face.GetEdge(j)); } //...and the triangle is removed. faces.RemoveAt(i); } } //Remove duplicate edges to retain only the convex hull of edges. //edges.RemoveDuplicates(); //Replaced with bespoke version for (int i = edges.Count - 2; i >= 0; i--) { MeshEdge itemA = edges[i]; for (int j = edges.Count - 1; j > i; j--) { if (itemA.Equals(edges[j])) { edges.RemoveAt(j); edges.RemoveAt(i); j--; continue; } } } // Add triangle fan between all remaining edges and the new vertex foreach (MeshEdge edge in edges) { faces.Add(new DelaunayTriangle(edge, v)); } } // Extract outer vertices if (outerVerts != null) { if (clean) { var outerFaces = faces.AllWithVertices(new VertexCollection(superTriangle)); foreach (Vertex v in outerFaces.ExtractVertices()) { outerVerts.Add(v); } } else { foreach (Vertex v in superTriangle) { outerVerts.Add(v); } } } // Remove the super triangle and any triangles still attached to it if (clean) { faces.RemoveAllWithVertices(new VertexCollection(superTriangle)); } return(faces); }