ianmackenzie / elm-geometry / VoronoiDiagram2d

For any given set of distinct (non-equal) points in 2D, there is a finite region around each point such that anywhere in the region is closer to that point than to any other point. These are the called the Voronoi regions of each point, and the collection of the Voronoi regions for a set of points is called the Voronoi diagram of those points.

Voronoi diagram

Although some Voronoi regions will be infinite in size, if they are all clipped to a particular bounding box then they will all be finite, convex polygons. This module therefore provides functionality for:

The returned polygons can then be used in various interesting ways:

The current implementation is somewhat inefficient, but there are plans to speed it up in the future (without requiring any changes to the API).


type VoronoiDiagram2d vertex units coordinates

A 2D Voronoi diagram of a set of vertices.


type Error vertex
    = CoincidentVertices vertex vertex

An error type indicating that the two given vertices have the same position.

Construction

Constructing a Voronoi diagram from points/vertices is currently an O(n^2) operation but should be O(n log n) in the future.

empty : VoronoiDiagram2d vertex units coordinates

An empty Voronoi diagram with no vertices or faces.

fromPoints : Array (Point2d units coordinates) -> Result (Error (Point2d units coordinates)) (VoronoiDiagram2d (Point2d units coordinates) units coordinates)

Construct a Voronoi diagram from an array of points. The points must all be distinct; if any two points are equal, you will get an Err CoincidentVertices.

fromVerticesBy : (vertex -> Point2d units coordinates) -> Array vertex -> Result (Error vertex) (VoronoiDiagram2d vertex units coordinates)

Construct a Voronoi diagram from an array of vertices of arbitrary type, by supplying a function that returns the position of each vertex as a Point2d. For example, if you had

types alias Vertex =
    { position = Point2d Meters WorldCoordinates
    , color = String
    }

and

vertices : Array Vertex
vertices =
    ...

then you would use

VoronoiDiagram2d.fromVerticesBy .position vertices

The vertices must all be distinct; if any two have the same position, you will get an Err CoincidentVertices.

Modification

Inserting a point into a Voronoi diagram is currently an O(n) operation but should be O(log n) in the future.

insertPoint : Point2d units coordinates -> VoronoiDiagram2d (Point2d units coordinates) units coordinates -> Result (Error (Point2d units coordinates)) (VoronoiDiagram2d (Point2d units coordinates) units coordinates)

Add a new point into an existing Voronoi diagram. It must not be equal to any existing point; if it is, you will get an Err CoincidentVertices.

insertVertexBy : (vertex -> Point2d units coordinates) -> vertex -> VoronoiDiagram2d vertex units coordinates -> Result (Error vertex) (VoronoiDiagram2d vertex units coordinates)

Add a new vertex into an existing Voronoi diagram, by supplying a function to get the position of the vertex. The vertex must not have the same position as any existing vertex; if it is, you will get an Err CoincidentVertices.

Properties

vertices : VoronoiDiagram2d vertex units coordinates -> Array vertex

Get the vertices of a Voronoi diagram. If the diagram was constructed by calling fromPoints or fromVerticesBy, then the returned vertex array will simply be the array that was passed in. If any vertices were added using insertPoint or insertVertexBy, then they will be appended to the end of the array. This is a simple accessor, so complexity is O(1).

polygons : BoundingBox2d units coordinates -> VoronoiDiagram2d vertex units coordinates -> List ( vertex, Polygon2d units coordinates )

Convert a Voronoi diagram to a list of polygons, by clipping each (possibly infinite/unbounded) Voronoi region to the given bounding box. Each item in the returned list will be an input vertex with its corresponding (clipped) Voronoi region.

If the bounding box contains all vertices, then there will be an entry in the list for every vertex. However, if some vertices fall outside the given bounding box, then it is possible that their Voronoi region is also entirely outside the bounding box, in which case they will have no entry in the returned list.

Complexity should be O(n) in the vast majority of cases but may be O(n log n) in pathological cases (such as 1000 points on a circle surrounding a single center point, in which case the Voronoi region for the center point will be a polygon with 1000 edges).

Conversion

A Voronoi diagram of a set or vertices is the dual of the Delaunay triangulation of those vertices. As a result, it is possible to convert back and forth between the two.

fromDelaunayTriangulation : DelaunayTriangulation2d vertex units coordinates -> VoronoiDiagram2d vertex units coordinates

Construct a Voronoi diagram from a Delaunay triangulation. Complexity should be O(n) in the vast majority of cases but may be O(n log n) in pathological cases.

toDelaunayTriangulation : VoronoiDiagram2d vertex units coordinates -> DelaunayTriangulation2d vertex units coordinates

Convert a Voronoi diagram to a Delaunay triangulation. This is a simple accessor, so complexity is O(1).