using Jobberwocky.GeometryAlgorithms.Source.Core; using Jobberwocky.GeometryAlgorithms.Source.Parameters; using Jobberwocky.TriangleNet.Geometry; using Jobberwocky.TriangleNet.Meshing; using Jobberwocky.TriangleNet.Voronoi; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Jobberwocky.GeometryAlgorithms.Source.Algorithms.Voronoi2D { public class Voronoi2DWrapper { public Voronoi2DWrapper() { } public Geometry Voronoi2D(Voronoi2DParameters parameters) { return Voronoi2DBase(parameters); } /// /// The base algorithm for the creation of a 2D voronoi diagram. /// /// /// Geometry private Geometry Voronoi2DBase(Voronoi2DParameters parameters) { var geometry = new Geometry(); if (parameters == null) { parameters = new Voronoi2DParameters(); } var points = parameters.Points; if (points != null && points.Length > 2) { var inputVertices = VectorToVertex(points, parameters.CoordinateSystem); var polygon = new Polygon(); for (var i = 0; i < inputVertices.Length; i++) { polygon.Add(inputVertices[i]); } ConstraintOptions cOptions = new ConstraintOptions() {ConformingDelaunay = true}; var triangulationMesh = (TriangleNet.Mesh) polygon.Triangulate(cOptions); VoronoiBase voronoi; // Create the voronoi from the triangulated mesh if (parameters.Bounded) { voronoi = new BoundedVoronoi(triangulationMesh); } else { voronoi = new StandardVoronoi(triangulationMesh); } // Extract all the data from the voronoi object var voronoiVertices = voronoi.Vertices.ToArray(); var voronoiEdges = voronoi.Edges.ToArray(); var voronoiHalfEdges = voronoi.HalfEdges.ToArray(); var voronoiFaces = voronoi.Faces.ToArray(); // First we retrieve all the voronoi vertices, e.g. the start and end point of each voronoi line var vertices = new Core.Vertex[voronoiVertices.Length]; for (int i = 0; i < voronoiVertices.Length; i++) { var vertex = voronoiVertices[i]; vertices[vertex.ID] = new Core.Vertex(Utils.FromCoordinateSystemDefaultTo( new Vector3((float) vertex.X, (float) vertex.Y, (float) vertex.Z), parameters.CoordinateSystem), vertex.ID); } // Set the indices to get all the voronoi lines var indices = new int[voronoiEdges.Length * 2]; for (int i = 0; i < voronoiEdges.Length; i++) { var edge = voronoiEdges[i]; indices[(i * 2) + 0] = edge.P0; indices[(i * 2) + 1] = edge.P1; } // For each voronoi face (voronoi cell) we want to know which (unique) vertices it contains var faceVertices = new Dictionary[voronoiFaces.Length]; for (var i = 0; i < voronoiFaces.Length; i++) { faceVertices[i] = new Dictionary(); } for (var i = 0; i < voronoiHalfEdges.Length; i++) { var edge = voronoiHalfEdges[i]; if (edge.Face.ID == -1) { continue; } var dictionary = faceVertices[edge.Face.ID]; if (!dictionary.ContainsKey(edge.Origin.ID)) { dictionary.Add(edge.Origin.ID, vertices[edge.Origin.ID]); } if (!dictionary.ContainsKey(edge.Twin.Origin.ID)) { dictionary.Add(edge.Twin.Origin.ID, vertices[edge.Twin.Origin.ID]); } } var cells = new Geometry[voronoiFaces.Length]; for (var i = 0; i < faceVertices.Length; i++) { cells[i] = new Geometry() {Vertices = faceVertices[i].Values.ToArray()}; } geometry.Vertices = vertices; geometry.Indices = indices; geometry.Cells = cells; geometry.Topology = MeshTopology.Lines; } return geometry; } /// /// Transforms Vector data to Vertex points. /// /// /// private TriangleNet.Geometry.Vertex[] VectorToVertex(Vector3[] vectors, CoordinateSystem coordinateSystem) { TriangleNet.Geometry.Vertex[] vertices = new TriangleNet.Geometry.Vertex[vectors.Length]; for (var i = 0; i < vectors.Length; i++) { var vector = Utils.ToCoordinateSystemDefault(vectors[i], coordinateSystem); var vertex = new TriangleNet.Geometry.Vertex(vector.x, vector.y); vertex.Z = vector.z; vertices[i] = vertex; } return vertices; } } }