ianmackenzie / elm-geometry-prerelease / 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.

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

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

An empty Voronoi diagram with no vertices or faces.

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

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) -> Array vertex -> Result (Error vertex) (VoronoiDiagram2d vertex)

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
    , 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 -> VoronoiDiagram2d Point2d -> Result (Error Point2d) (VoronoiDiagram2d Point2d)

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) -> vertex -> VoronoiDiagram2d vertex -> Result (Error vertex) (VoronoiDiagram2d vertex)

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 -> 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 -> VoronoiDiagram2d vertex -> List ( vertex, Polygon2d )

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).