123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- // -----------------------------------------------------------------------
- // <copyright file="VoronoiBase.cs">
- // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
- // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
- // </copyright>
- // -----------------------------------------------------------------------
- namespace UnityEngine.U2D.Animation.TriangleNet
- .Voronoi
- {
- using System.Collections.Generic;
- using Animation.TriangleNet.Topology;
- using Animation.TriangleNet.Geometry;
- using Animation.TriangleNet.Topology.DCEL;
- using Vertex = Animation.TriangleNet.Topology.DCEL.Vertex;
- /// <summary>
- /// The Voronoi diagram is the dual of a pointset triangulation.
- /// </summary>
- internal abstract class VoronoiBase : DcelMesh
- {
- protected IPredicates predicates;
- protected IVoronoiFactory factory;
- // List of infinite half-edges, i.e. half-edges that start at circumcenters of triangles
- // which lie on the domain boundary.
- protected List<HalfEdge> rays;
- /// <summary>
- /// Initializes a new instance of the <see cref="VoronoiBase" /> class.
- /// </summary>
- /// <param name="mesh">Triangle mesh.</param>
- /// <param name="factory">Voronoi object factory.</param>
- /// <param name="predicates">Geometric predicates implementation.</param>
- /// <param name="generate">If set to true, the constuctor will call the Generate
- /// method, which builds the Voronoi diagram.</param>
- protected VoronoiBase(Mesh mesh, IVoronoiFactory factory, IPredicates predicates,
- bool generate)
- : base(false)
- {
- this.factory = factory;
- this.predicates = predicates;
- if (generate)
- {
- Generate(mesh);
- }
- }
- /// <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>
- /// 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);
- Animation.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);
- }
- }
- }
- }
- /// <summary>
- /// Connect all edges of the Voronoi diagram.
- /// </summary>
- /// <param name="map">Maps all vertices to a list of leaving edges.</param>
- protected virtual void ConnectEdges(List<HalfEdge>[] map)
- {
- int length = map.Length;
- // For each half-edge, find its successor in the connected face.
- foreach (var edge in this.edges)
- {
- var face = edge.face.generator.id;
- // The id of the dest vertex of current edge.
- int id = edge.twin.origin.id;
- // The edge origin can also be an infinite vertex. Sort them out
- // by checking the id.
- if (id < length)
- {
- // Look for the edge that is connected to the current face. Each
- // Voronoi vertex has degree 3, so this loop is actually O(1).
- foreach (var next in map[id])
- {
- if (next.face.generator.id == face)
- {
- edge.next = next;
- break;
- }
- }
- }
- }
- }
- protected override IEnumerable<IEdge> EnumerateEdges()
- {
- var edges = new List<IEdge>(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;
- }
- }
- }
|