/// <summary> /// Generate the Voronoi diagram from given triangle mesh.. /// </summary> /// <param name="mesh"></param> /// <param name="bounded"></param> protected void Generate(Mesh mesh) { mesh.Renumber(); base.edges = new List <HalfEdge>(); this.rays = new List <HalfEdge>(); // Allocate space for Voronoi diagram. var vertices = new Vertex[mesh.triangles.Count + mesh.hullsize]; var faces = new Face[mesh.vertices.Count]; if (factory == null) { factory = new DefaultVoronoiFactory(); } factory.Initialize(vertices.Length, 2 * mesh.NumberOfEdges, faces.Length); // Compute triangles circumcenters. var map = ComputeVertices(mesh, vertices); // Create all Voronoi faces. foreach (var vertex in mesh.vertices.Values) { faces[vertex.id] = factory.CreateFace(vertex); } ComputeEdges(mesh, 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> /// Generate the Voronoi diagram from given triangle mesh.. /// </summary> /// <param name="mesh"></param> /// <param name="bounded"></param> protected void Generate(Mesh mesh) { mesh.Renumber(); base.edges = new List<HalfEdge>(); this.rays = new List<HalfEdge>(); // Allocate space for Voronoi diagram. var vertices = new Vertex[mesh.triangles.Count + mesh.hullsize]; var faces = new Face[mesh.vertices.Count]; if (factory == null) { factory = new DefaultVoronoiFactory(); } factory.Initialize(vertices.Length, 2 * mesh.NumberOfEdges, faces.Length); // Compute triangles circumcenters. var map = ComputeVertices(mesh, vertices); // Create all Voronoi faces. foreach (var vertex in mesh.vertices.Values) { faces[vertex.id] = factory.CreateFace(vertex); } ComputeEdges(mesh, 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); }
/** * Iterate over every edge in the voronoi graph building edge objects and connecting centers and corners. * This method is very important to complete the graph to be used for all later stages! */ internal static List <Edge> createEdges(VoronoiBase voronoi, List <Center> centers, List <Corner> corners) { List <Edge> edges = new List <Edge>(); List <HalfEdge> halfEdges = voronoi.HalfEdges; foreach (HalfEdge e0 in halfEdges) { HalfEdge e1 = e0.Twin; if (e1.ID < e0.ID) { continue; } TriangleNet.Topology.DCEL.Vertex v0 = e0.Origin; TriangleNet.Topology.DCEL.Vertex v1 = e1.Origin; Corner corner0 = corners[v0.ID]; Corner corner1 = corners[v1.ID]; Face face0 = e0.Face; Face face1 = e1.Face; Center center0 = face0.ID < 0 ? null : centers[face0.ID]; Center center1 = face1.ID < 0 ? null : centers[face1.ID]; bool isBorder = center0 == null || center1 == null; edges.Add(makeEdge(isBorder, corner0, corner1, center0, center1)); } return(edges); }
internal static List <Corner> createCorners(List <TriangleNet.Topology.DCEL.Vertex> vertices) { List <Corner> idCorners = new List <Corner>(vertices.Count); for (int i = 0; i < vertices.Count; i++) { TriangleNet.Topology.DCEL.Vertex vertex = vertices[i]; idCorners.Add(new Corner(new Coord((float)vertex.X, 0, (float)vertex.Y))); } return(idCorners); }
/// <summary> /// Generate the Voronoi diagram from given triangle mesh.. /// </summary> /// <param name="mesh"></param> protected void Generate(Mesh mesh) { base.edges = new List <HalfEdge>(); this.rays = new List <HalfEdge>(); // Undead vertices cannot be Voronoi cell generators. int count = mesh.vertices.Count - mesh.undeads; // Allocate space for Voronoi diagram. var vertices = new Vertex[mesh.triangles.Count + mesh.hullsize]; var faces = new Face[count]; if (factory == null) { factory = new DefaultVoronoiFactory(); } factory.Initialize(vertices.Length, 2 * mesh.NumberOfEdges, faces.Length); // Compute triangles circumcenters. var map = ComputeVertices(mesh, vertices); // Ensure linear numbering of vertices (excluding undeads). int vid = 0; // Create all Voronoi faces, skipping undead vertices. foreach (var vertex in mesh.vertices.Values) { if (vertex.type == VertexType.UndeadVertex) { vertex.id = count++; } else { vertex.id = vid++; faces[vertex.id] = factory.CreateFace(vertex); } } ComputeEdges(mesh, 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> /// Compute the Voronoi vertices (the circumcenters of the triangles). /// </summary> /// <returns>An empty map, which will map all vertices to a list of leaving edges.</returns> protected List<HalfEdge>[] ComputeVertices(Mesh mesh, Vertex[] vertices) { Otri tri = default(Otri); double xi = 0, eta = 0; Vertex vertex; Point pt; int id; // Maps all vertices to a list of leaving edges. var map = new List<HalfEdge>[mesh.triangles.Count]; // Compue triangle circumcenters foreach (var t in mesh.triangles) { id = t.id; tri.tri = t; pt = predicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta); vertex = factory.CreateVertex(pt.x, pt.y); vertex.id = id; vertices[id] = vertex; map[id] = new List<HalfEdge>(); } return map; }
/// <summary> /// Compute the edges of the Voronoi diagram. /// </summary> /// <param name="mesh"></param> /// <param name="vertices"></param> /// <param name="faces"></param> /// <param name="map">Empty vertex map.</param> protected void ComputeEdges(Mesh mesh, Vertex[] vertices, Face[] faces, List<HalfEdge>[] map) { Otri tri, neighbor = default(Otri); TriangleNet.Geometry.Vertex org, dest; double px, py; int id, nid, count = mesh.triangles.Count; Face face, neighborFace; HalfEdge edge, twin; Vertex vertex, end; // Count infinte edges (vertex id for their endpoints). int j = 0; // Count half-edges (edge ids). int k = 0; // To loop over the set of edges, loop over all triangles, and look at the // three edges of each triangle. If there isn't another triangle adjacent // to the edge, operate on the edge. If there is another adjacent triangle, // operate on the edge only if the current triangle has a smaller id than // its neighbor. This way, each edge is considered only once. foreach (var t in mesh.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) { // Get the endpoints of the current triangle edge. org = tri.Org(); dest = tri.Dest(); face = faces[org.id]; neighborFace = faces[dest.id]; vertex = vertices[id]; // For each edge in the triangle mesh, there's a corresponding edge // in the Voronoi diagram, i.e. two half-edges will be created. if (nid < 0) { // Unbounded edge, direction perpendicular to the boundary edge, // pointing outwards. px = dest.y - org.y; py = org.x - dest.x; end = factory.CreateVertex(vertex.x + px, vertex.y + py); end.id = count + j++; vertices[end.id] = end; edge = factory.CreateHalfEdge(end, face); twin = factory.CreateHalfEdge(vertex, neighborFace); // Make (face.edge) always point to an edge that starts at an infinite // vertex. This will allow traversing of unbounded faces. face.edge = edge; face.bounded = false; map[id].Add(twin); rays.Add(twin); } else { end = vertices[nid]; // Create half-edges. edge = factory.CreateHalfEdge(end, face); twin = factory.CreateHalfEdge(vertex, neighborFace); // Add to vertex map. map[nid].Add(edge); map[id].Add(twin); } vertex.leaving = twin; end.leaving = edge; edge.twin = twin; twin.twin = edge; edge.id = k++; twin.id = k++; this.edges.Add(edge); this.edges.Add(twin); } } } }
public static DcelMesh ToDCEL(Mesh mesh) { var dcel = new DcelMesh(); var vertices = new HVertex[mesh.vertices.Count]; var faces = new Face[mesh.triangles.Count]; dcel.HalfEdges.Capacity = 2 * mesh.NumberOfEdges; mesh.Renumber(); HVertex vertex; foreach (var v in mesh.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>[mesh.triangles.Count]; Face face; foreach (var t in mesh.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 = mesh.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 mesh.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; }
public static DcelMesh ToDCEL(Mesh mesh) { var dcel = new DcelMesh(); var vertices = new HVertex[mesh.vertices.Count]; var faces = new Face[mesh.triangles.Count]; dcel.HalfEdges.Capacity = 2 * mesh.NumberOfEdges; mesh.Renumber(); HVertex vertex; foreach (var v in mesh.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> [mesh.triangles.Count]; Face face; foreach (var t in mesh.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 = mesh.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 mesh.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); }
public HalfEdge CreateHalfEdge(Vertex origin, Face face) { return new HalfEdge(origin, face); }