From 6ef7aa8c98e8f1de2c31fda3c0593eaec5c632b6 Mon Sep 17 00:00:00 2001 From: "SND\\wo80_cp" Date: Tue, 8 Jul 2014 20:11:58 +0000 Subject: [PATCH] Fix bug in Triangle constructor (static triangle init); Add bounded Voronoi code (needs testing) git-svn-id: https://triangle.svn.codeplex.com/svn@75134 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5 --- Triangle.NET/TestApp/FormMain.cs | 14 +- Triangle.NET/Triangle/Data/Triangle.cs | 28 +-- .../Triangle/Voronoi/BoundedVoronoi.cs | 203 ++++++++++++++++++ Triangle.NET/Triangle/Voronoi/VoronoiBase.cs | 2 +- 4 files changed, 220 insertions(+), 27 deletions(-) diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs index 04adb1c..2586b67 100644 --- a/Triangle.NET/TestApp/FormMain.cs +++ b/Triangle.NET/TestApp/FormMain.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms; @@ -9,10 +8,9 @@ using TriangleNet; using TriangleNet.Geometry; using TriangleNet.Meshing; using TriangleNet.Meshing.Algorithm; -using TriangleNet.Tools; -using TriangleNet.Smoothing; using TriangleNet.Rendering; -using TriangleNet.Voronoi.Legacy; +using TriangleNet.Smoothing; +using TriangleNet.Voronoi; namespace MeshExplorer { @@ -22,7 +20,7 @@ namespace MeshExplorer Mesh mesh; IPolygon input; - IVoronoi voronoi; + VoronoiBase voronoi; FormLog frmLog; FormGenerator frmGenerator; @@ -612,14 +610,14 @@ namespace MeshExplorer if (mesh.IsPolygon) { - this.voronoi = new BoundedVoronoiLegacy(mesh); + this.voronoi = new BoundedVoronoi(mesh); } else { - this.voronoi = new SimpleVoronoi(mesh); + this.voronoi = new StandardVoronoi(mesh); } - renderManager.Set(voronoi.Points, voronoi.Edges, false); + renderManager.Set(voronoi.Vertices, voronoi.Edges, false); } private void ShowLog() diff --git a/Triangle.NET/Triangle/Data/Triangle.cs b/Triangle.NET/Triangle/Data/Triangle.cs index ca676a6..7f4d04a 100644 --- a/Triangle.NET/Triangle/Data/Triangle.cs +++ b/Triangle.NET/Triangle/Data/Triangle.cs @@ -81,30 +81,22 @@ namespace TriangleNet.Data public Triangle() { + // Three NULL vertices. + vertices = new Vertex[3]; + + // Initialize the three adjoining subsegments to be the omnipresent subsegment. + subsegs = new Osub[3]; + subsegs[0].seg = Segment.Empty; + subsegs[1].seg = Segment.Empty; + subsegs[2].seg = Segment.Empty; + // Initialize the three adjoining triangles to be "outer space". neighbors = new Otri[3]; neighbors[0].triangle = Empty; neighbors[1].triangle = Empty; neighbors[2].triangle = Empty; - // Three NULL vertices. - vertices = new Vertex[3]; - - // TODO: if (Behavior.UseSegments) - { - // Initialize the three adjoining subsegments to be the - // omnipresent subsegment. - subsegs = new Osub[3]; - subsegs[0].seg = Segment.Empty; - subsegs[1].seg = Segment.Empty; - subsegs[2].seg = Segment.Empty; - } - - // TODO: - //if (Behavior.VarArea) - //{ - // area = -1.0; - //} + // area = -1.0; } #region Public properties diff --git a/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs b/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs index 5af7591..f7cb81f 100644 --- a/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs @@ -6,19 +6,222 @@ namespace TriangleNet.Voronoi { + using System; + using System.Collections.Generic; + using TriangleNet.Geometry; + public class BoundedVoronoi : VoronoiBase { + int offset; + public BoundedVoronoi(Mesh mesh) : base(mesh, true) { // We explicitly told the base constructor to call the Generate method, so // at this point the basic Voronoi diagram is already created. + offset = base.vertices.Length; + + // Each vertex of the hull will be part of a Voronoi cell. + Array.Resize(ref base.vertices, offset + mesh.hullsize); + + // Create bounded Voronoi diagram. PostProcess(); + + Array.Resize(ref base.vertices, offset); } private void PostProcess() { // Compute edge intersections with mesh boundary edges. + ProcessBoundaryEdges(); + } + + private void ProcessBoundaryEdges() + { + var infEdges = new List(); + + // TODO: save the half-infinite boundary edge in base class + // so we don't have to process the complete list here. + foreach (var edge in base.edges) + { + if (edge.next == null) + { + infEdges.Add(edge); + } + } + + foreach (var edge in infEdges) + { + var v1 = (Vertex)edge.face.generator; + var v2 = (Vertex)edge.twin.face.generator; + + double dir = RobustPredicates.CounterClockwise(v1, v2, edge.origin); + + if (dir <= 0) + { + HandleCase1(edge, v1, v2); + } + else + { + HandleCase2(edge, v1, v2); + } + } + } + + private void HandleCase1(DCEL.HalfEdge edge, Vertex v1, Vertex 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 = new DCEL.Vertex(v1.x, v1.y); + + var h1 = new DCEL.HalfEdge(edge.twin.origin, edge.face); + var h2 = new DCEL.HalfEdge(gen, edge.face); + + h1.next = h2; + h2.next = edge.face.edge; + + // 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; + + base.vertices[offset] = gen; + gen.id = offset++; + } + + private void HandleCase2(DCEL.HalfEdge e1, Vertex v1, Vertex v2) + { + var e2 = e1.twin.next; + var ei = e2.twin.next; + + // The vertices of the infinite edge. + var p1 = (Point)e1.origin; + var pi = (Point)e1.twin.origin; + + // Find the two intersections with boundary edge. + IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref pi); + IntersectSegments(v1, v2, ei.origin, ei.twin.origin, ref p1); + + // The infinite edge will now lie on the boundary. Update pointers: + e2.twin.next = e1.twin; + e1.twin.next = ei; + e1.twin.face = ei.face; + + e2.origin = e1.twin.origin; + + e1.twin.twin = null; + e1.twin = null; + + // Close the cell. + var gen = new DCEL.Vertex(v1.x, v1.y); + var he = new DCEL.HalfEdge(gen, e1.face); + + e1.next = he; + he.next = e1.face.edge; + + // Let the face edge point to the edge leaving at generator. + e1.face.edge = he; + + base.edges.Add(he); + + he.id = base.edges.Count; + + base.vertices[offset] = gen; + gen.id = offset++; + } + + /* + private int GetBoundaryMark(Vertex v) + { + Otri tri = default(Otri); + Otri next = default(Otri); + Osub seg = default(Osub); + + // Get triangle connected to generator. + v.tri.Copy(ref tri); + v.tri.Copy(ref next); + + // Find boundary triangle. + while (next.triangle.id != -1) + { + next.Copy(ref tri); + next.OnextSelf(); + } + + // Find edge dual to current half-edge. + tri.LnextSelf(); + tri.LnextSelf(); + + tri.SegPivot(ref seg); + + return seg.seg.boundary; + } + //*/ + + /// + /// Compute intersection of two segments. + /// + /// Segment 1 start point. + /// Segment 1 end point. + /// Segment 2 start point. + /// Segment 2 end point. + /// The intersection point. + /// + /// This is a special case of segment intersection. Since the calling algorithm assures + /// that a valid intersection exists, there's no need to check for any special cases. + /// + private static void IntersectSegments(Point p0, Point p1, Point q0, Point q1, ref Point i0) + { + double ux = p1.x - p0.x; + double uy = p1.y - p0.y; + double vx = q1.x - q0.x; + double vy = q1.y - q0.y; + double wx = p0.x - q0.x; + double wy = p0.y - q0.y; + + double d = (ux * vy - uy * vx); + double s = (vx * wy - vy * wx) / d; + + // Intersection point + i0.x = p0.X + s * ux; + i0.y = p0.Y + s * uy; + } + + protected override IEnumerable EnumerateEdges() + { + var edges = new List(this.edges.Count / 2); + + foreach (var edge in this.edges) + { + var twin = edge.twin; + + // Report edge only once. + if (twin == null) + { + edges.Add(new Edge(edge.origin.id, edge.next.origin.id)); + } + else if (edge.id < twin.id) + { + edges.Add(new Edge(edge.origin.id, twin.origin.id)); + } + } + + return edges; } } } diff --git a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs index 2d314b4..5712174 100644 --- a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs +++ b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs @@ -270,7 +270,7 @@ namespace TriangleNet.Voronoi } } - protected IEnumerable EnumerateEdges() + protected virtual IEnumerable EnumerateEdges() { var edges = new List(this.edges.Count / 2);