/// <summary> /// Generate the Voronoi diagram from given triangle mesh.. /// </summary> /// <param name="triangleNetMesh"></param> /// <param name="bounded"></param> protected void Generate(TriangleNetMesh triangleNetMesh) { triangleNetMesh.Renumber(); base.edges = new List <HalfEdge>(); this.rays = new List <HalfEdge>(); // Allocate space for Voronoi diagram. var vertices = new Vertex[triangleNetMesh.triangles.Count + triangleNetMesh.hullsize]; var faces = new Face[triangleNetMesh.vertices.Count]; if (factory == null) { factory = new DefaultVoronoiFactory(); } factory.Initialize(vertices.Length, 2 * triangleNetMesh.NumberOfEdges, faces.Length); // Compute triangles circumcenters. var map = ComputeVertices(triangleNetMesh, vertices); // Create all Voronoi faces. foreach (var vertex in triangleNetMesh.vertices.Values) { faces[vertex.id] = factory.CreateFace(vertex); } ComputeEdges(triangleNetMesh, vertices, faces, map); // At this point all edges are computed, but the (edge.next) pointers aren't set. ConnectEdges(map); base.vertices = new List <Vertex>(vertices); base.faces = new List <Face>(faces); }
/// <summary> /// Gets the Voronoi diagram as raw output data. /// </summary> /// <param name="mesh"></param> /// <returns></returns> /// <remarks> /// The Voronoi diagram is the geometric dual of the Delaunay triangulation. /// Hence, the Voronoi vertices are listed by traversing the Delaunay /// triangles, and the Voronoi edges are listed by traversing the Delaunay /// edges. ///</remarks> private void Generate() { _TriangleNetMesh.Renumber(); _TriangleNetMesh.MakeVertexMap(); // Allocate space for voronoi diagram points = new Point[_TriangleNetMesh.triangles.Count + _TriangleNetMesh.hullsize]; regions = new Dictionary <int, VoronoiRegion>(_TriangleNetMesh.vertices.Count); rayPoints = new Dictionary <int, Point>(); rayIndex = 0; bounds = new Rectangle(); // Compute triangles circumcenters and setup bounding box ComputeCircumCenters(); // Add all Voronoi regions to the map. foreach (var vertex in _TriangleNetMesh.vertices.Values) { regions.Add(vertex.id, new VoronoiRegion(vertex)); } // Loop over the mesh vertices (Voronoi generators). foreach (var region in regions.Values) { //if (item.Boundary == 0) { ConstructCell(region); } } }
/// <summary> /// Gets the permutation vector for the Reverse Cuthill-McKee numbering. /// </summary> /// <param name="triangleNetMesh">The mesh.</param> /// <returns>Permutation vector.</returns> public int[] Renumber(TriangleNetMesh triangleNetMesh) { // Algorithm needs linear numbering of the nodes. triangleNetMesh.Renumber(NodeNumbering.Linear); return(Renumber(new AdjacencyMatrix(triangleNetMesh))); }
/// <summary> /// Number the vertices and write them to a .node file. /// </summary> private void WriteNodes(StreamWriter writer, TriangleNetMesh triangleNetMesh) { int outvertices = triangleNetMesh.vertices.Count; int nextras = triangleNetMesh.nextras; Behavior behavior = triangleNetMesh.behavior; if (behavior.Jettison) { outvertices = triangleNetMesh.vertices.Count - triangleNetMesh.undeads; } if (writer != null) { // Number of vertices, number of dimensions, number of vertex attributes, // and number of boundary markers (zero or one). writer.WriteLine("{0} {1} {2} {3}", outvertices, triangleNetMesh.mesh_dim, nextras, behavior.UseBoundaryMarkers ? "1" : "0"); if (triangleNetMesh.numbering == NodeNumbering.None) { // If the mesh isn't numbered yet, use linear node numbering. triangleNetMesh.Renumber(); } if (triangleNetMesh.numbering == NodeNumbering.Linear) { // If numbering is linear, just use the dictionary values. WriteNodes(writer, triangleNetMesh.vertices.Values, behavior.UseBoundaryMarkers, nextras, behavior.Jettison); } else { // If numbering is not linear, a simple 'foreach' traversal of the dictionary // values doesn't reflect the actual numbering. Use an array instead. // TODO: Could use a custom sorting function on dictionary values instead. Vertex[] nodes = new Vertex[triangleNetMesh.vertices.Count]; foreach (var node in triangleNetMesh.vertices.Values) { nodes[node.id] = node; } WriteNodes(writer, nodes, behavior.UseBoundaryMarkers, nextras, behavior.Jettison); } } }
/// <summary> /// Computes the bounded voronoi diagram. /// </summary> private void Generate() { _TriangleNetMesh.Renumber(); _TriangleNetMesh.MakeVertexMap(); // Allocate space for voronoi diagram regions = new List <VoronoiRegion>(_TriangleNetMesh.vertices.Count); points = new Point[_TriangleNetMesh.triangles.Count]; segPoints = new List <Point>(_TriangleNetMesh.subsegs.Count * 4); ComputeCircumCenters(); TagBlindTriangles(); foreach (var v in _TriangleNetMesh.vertices.Values) { // TODO: Need a reliable way to check if a vertex is on a segment if (v.type == VertexType.FreeVertex || v.label == 0) { ConstructCell(v); } else if (includeBoundary) { ConstructBoundaryCell(v); } } // Add the new points on segments to the point array. int length = points.Length; Array.Resize <Point>(ref points, length + segPoints.Count); for (int i = 0; i < segPoints.Count; i++) { points[length + i] = segPoints[i]; } segPoints.Clear(); segPoints = null; }
public static DcelMesh ToDCEL(TriangleNetMesh triangleNetMesh) { var dcel = new DcelMesh(); var vertices = new HVertex[triangleNetMesh.vertices.Count]; var faces = new Face[triangleNetMesh.triangles.Count]; dcel.HalfEdges.Capacity = 2 * triangleNetMesh.NumberOfEdges; triangleNetMesh.Renumber(); HVertex vertex; foreach (var v in triangleNetMesh.vertices.Values) { vertex = new HVertex(v.x, v.y); vertex.id = v.id; vertex.label = v.label; vertices[v.id] = vertex; } // Maps a triangle to its 3 edges (used to set next pointers). var map = new List <HalfEdge> [triangleNetMesh.triangles.Count]; Face face; foreach (var t in triangleNetMesh.triangles) { face = new Face(null); face.id = t.id; faces[t.id] = face; map[t.id] = new List <HalfEdge>(3); } Otri tri = default(Otri), neighbor = default(Otri); TriangleNet.Geometry.Vertex org, dest; int id, nid, count = triangleNetMesh.triangles.Count; HalfEdge edge, twin, next; var edges = dcel.HalfEdges; // Count half-edges (edge ids). int k = 0; // Maps a vertex to its leaving boundary edge. var boundary = new Dictionary <int, HalfEdge>(); foreach (var t in triangleNetMesh.triangles) { id = t.id; tri.tri = t; for (int i = 0; i < 3; i++) { tri.orient = i; tri.Sym(ref neighbor); nid = neighbor.tri.id; if (id < nid || nid < 0) { face = faces[id]; // Get the endpoints of the current triangle edge. org = tri.Org(); dest = tri.Dest(); // Create half-edges. edge = new HalfEdge(vertices[org.id], face); twin = new HalfEdge(vertices[dest.id], nid < 0 ? Face.Empty : faces[nid]); map[id].Add(edge); if (nid >= 0) { map[nid].Add(twin); } else { boundary.Add(dest.id, twin); } // Set leaving edges. edge.origin.leaving = edge; twin.origin.leaving = twin; // Set twin edges. edge.twin = twin; twin.twin = edge; edge.id = k++; twin.id = k++; edges.Add(edge); edges.Add(twin); } } } // Set next pointers for each triangle face. foreach (var t in map) { edge = t[0]; next = t[1]; if (edge.twin.origin.id == next.origin.id) { edge.next = next; next.next = t[2]; t[2].next = edge; } else { edge.next = t[2]; next.next = edge; t[2].next = next; } } // Resolve boundary edges. foreach (var e in boundary.Values) { e.next = boundary[e.twin.origin.id]; } dcel.Vertices.AddRange(vertices); dcel.Faces.AddRange(faces); return(dcel); }