/// <summary> /// Replace the vertices in the faces in this collection with /// new fresh copies. Allows these faces to be added to a new /// mesh. /// </summary> /// <returns></returns> public VertexCollection FreshVertices() { var result = new VertexCollection(); var vDict = new Dictionary <Guid, Vertex>(); foreach (MeshFace face in this) { for (int i = 0; i < face.Count; i++) { Vertex vOld = face[i]; if (vDict.ContainsKey(vOld.GUID)) { face[i] = vDict[vOld.GUID]; } else { Vertex vNew = new Vertex(vOld); result.Add(vNew); vDict.Add(vOld.GUID, vNew); face[i] = vNew; } } } return(result); }
/// <summary> /// Remove from this collection all faces which contain any vertices /// shared with the specified vertex collection /// </summary> /// <param name="vertices"></param> public void RemoveAllWithVertices(VertexCollection vertices) { for (int i = Count - 1; i >= 0; i--) { if (this[i].ContainsAnyVertex(vertices)) { RemoveAt(i); } } }
/// <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> /// Get a collection containing all of the vertices belonging to the geometry in this collection /// </summary> /// <returns></returns> public VertexCollection AllVertices() { var result = new VertexCollection(); foreach (VertexGeometry geom in this) { foreach (Vertex v in geom.Vertices) { if (!result.Contains(v.GUID)) { result.Add(v); } } } return(result); }
/// <summary> /// Extract all vertices belonging to the faces in this collection /// </summary> /// <returns></returns> public VertexCollection ExtractVertices() { var result = new VertexCollection(); foreach (MeshFace face in this) { foreach (Vertex v in face) { if (!result.Contains(v.GUID)) { result.Add(v); } } } 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> /// Default constructor. Initialises an empty line with /// no geometry. The line will not be valid until its vertices /// are populated. /// </summary> public Line() { _Vertices = new VertexCollection(this); }
/// <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); }
/// <summary> /// Default constructor /// </summary> public Mesh() { _Vertices = new VertexCollection(this); }
/// <summary> /// Default constructor /// </summary> public Cloud(GeometryAttributes attributes = null) { _Vertices = new VertexCollection(this); Attributes = attributes; }
/// <summary> /// Default constructor. Initialises an invalid arc with no geometry. /// Will not be valid. /// </summary> public Arc() { _Vertices = new VertexCollection(this); }