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).
A 2D Voronoi diagram of a set of vertices.
An error type indicating that the two given vertices have the same position.
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
.
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
.
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).