/// <summary> /// Initializes a new instance of the <see cref="Face" /> class. /// </summary> /// <param name="generator">The generator of this face (for Voronoi diagram)</param> /// <param name="edge">The half-edge connected to this face.</param> public Face(Point generator, HalfEdge edge) { this.generator = generator; this.edge = edge; this.bounded = true; if (generator != null) { this.id = generator.ID; } }
/// <summary> /// Case 1: edge origin lies inside the domain. /// </summary> private void HandleCase1(HalfEdge edge, TVertex v1, TVertex v2) { //int mark = GetBoundaryMark(v1); // The infinite vertex. var v = (Point)edge.twin.origin; // The half-edge is the bisector of v1 and v2, so the projection onto the // boundary segment is actually its midpoint. v.x = (v1.x + v2.x) / 2.0; v.y = (v1.y + v2.y) / 2.0; // Close the cell connected to edge. var gen = factory.CreateVertex(v1.x, v1.y); var h1 = factory.CreateHalfEdge(edge.twin.origin, edge.face); var h2 = factory.CreateHalfEdge(gen, edge.face); edge.next = h1; h1.next = h2; h2.next = edge.face.edge; gen.leaving = h2; // Let the face edge point to the edge leaving at generator. edge.face.edge = h2; base.edges.Add(h1); base.edges.Add(h2); int count = base.edges.Count; h1.id = count; h2.id = count + 1; gen.id = offset++; base.vertices.Add(gen); }
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; }
/// <summary> /// Enumerates all half-edges of the face boundary. /// </summary> /// <returns></returns> public IEnumerable<HalfEdge> EnumerateEdges() { var edge = this.Edge; int first = edge.ID; do { yield return edge; edge = edge.Next; } while (edge.ID != first); }
/// <summary> /// Case 2: edge origin lies outside the domain. /// </summary> private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2) { // The vertices of the infinite edge. var p1 = (Point)edge.origin; var p2 = (Point)edge.twin.origin; // The two edges leaving p1, pointing into the mesh. var e1 = edge.twin.next; var e2 = e1.twin.next; // Find the two intersections with boundary edge. IntersectionHelper.IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2); IntersectionHelper.IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1); // The infinite edge will now lie on the boundary. Update pointers: e1.twin.next = edge.twin; edge.twin.next = e2; edge.twin.face = e2.face; e1.origin = edge.twin.origin; edge.twin.twin = null; edge.twin = null; // Close the cell. var gen = factory.CreateVertex(v1.x, v1.y); var he = factory.CreateHalfEdge(gen, edge.face); edge.next = he; he.next = edge.face.edge; // Let the face edge point to the edge leaving at generator. edge.face.edge = he; base.edges.Add(he); he.id = base.edges.Count; gen.id = offset++; base.vertices.Add(gen); }
/// <summary> /// Initializes a new instance of the <see cref="Vertex" /> class. /// </summary> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> /// <param name="leaving">A half-edge leaving this vertex.</param> public Vertex(double x, double y, HalfEdge leaving) : base(x, y) { this.leaving = leaving; }
/// <summary> /// Initializes a new instance of the <see cref="Vertex" /> class. /// </summary> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> /// <param name="leaving">A half-edge leaving this vertex.</param> public Vertex(float x, float y, HalfEdge leaving) : base(x, y) { this.leaving = leaving; }