geomotif.motifs.voronoi
¶
Voronoi diagrams, the Delaunay triangulation, and Lloyd's relaxation.
Scatter some points and ask, of every place on the page, "which of you is nearest?". The answer divides the plane into one convex cell per point -- the Voronoi diagram -- and joining the points whose cells touch gives the Delaunay triangulation, the same figure read the other way round.
Everything in this module is built from one construction: a site's cell is the region rectangle, clipped by the perpendicular bisector between that site and each of its Delaunay neighbours. No other bisector reaches it, which is what makes this cheap: the neighbours are a handful rather than the whole set, and one triangulation answers every question asked below.
The triangulation itself comes from scipy's Qhull binding, which makes this the one module in the catalog behind an optional dependency::
pip install 'geomotif[scipy]'
That dependency is real rather than a convenience. Points sharing a circle -- a plain square grid, which this library will happily hand you -- are exactly where a hand-rolled incremental triangulator has to break a tie arbitrarily and can then contradict itself; getting that right is Qhull's day job.
scipy is imported when a design is built, not when this module is imported,
so these motifs can still be listed, described and reported as unavailable on
a machine without it. They carry requires="scipy" in the registry for
exactly that reason.
Classes:
| Name | Description |
|---|---|
Delaunay |
The triangulation that joins points whose Voronoi cells touch. |
Voronoi |
The map of which point is nearest, drawn as its borders. |
VoronoiCells |
The same map, drawn one closed region at a time. |
LloydRelaxation |
Points nudged toward the middle of their own cells, over and over. |
Delaunay
dataclass
¶
Bases: SegmentMotif
The triangulation that joins points whose Voronoi cells touch.
Of all the ways to cut a point set into triangles, this is the one that avoids thin ones: no point ever falls inside another triangle's circumcircle, which maximizes the smallest angle in the whole mesh. That is why it is what meshers, terrain models and low-poly renderers use, and why a scatter drawn this way reads as a surface rather than a tangle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
sequence of (float, float)
|
The sites to triangulate. At least three, not all on one line. |
required |
Voronoi
dataclass
¶
Voronoi(points: Sequence[Point], region: Bounds | None = None, *, merge: bool = False, show_nodes: bool = False)
Bases: SegmentMotif
The map of which point is nearest, drawn as its borders.
Each border is drawn once, however many cells meet along it, so the
result is a plotter's diagram rather than a stack of outlines --
merge=True then chains those borders into long strokes.
:class:VoronoiCells is the same figure when each region matters more
than the lines between them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
sequence of (float, float)
|
The sites. At least three, not all on one line. |
required |
region
|
Bounds
|
Where to cut off the cells of the outermost sites, whose borders otherwise run to infinity. Defaults to the points' own extent, grown by a tenth. |
None
|
Methods:
| Name | Description |
|---|---|
cells |
Return one convex cell per site, clipped to the region. |
corners |
Return the shared corner table and each cell as indices into it. |
VoronoiCells
dataclass
¶
VoronoiCells(points: Sequence[Point], region: Bounds | None = None, inset: float = 0.0)
Bases: PolygonMotif
The same map, drawn one closed region at a time.
Each cell is its own closed path, so a border shared by two of them is
drawn twice -- the price of having each region be a thing in itself,
which is what you want to fill, color, or cut. inset pulls every
cell back from its neighbours and gives the cracked-mud look the diagram
is usually drawn for.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
sequence of (float, float)
|
The sites. At least three, not all on one line. |
required |
region
|
Bounds
|
Where to cut off the outermost cells. Defaults to the points' own extent, grown by a tenth. |
None
|
inset
|
float
|
Fraction of the way each cell is pulled toward its own middle.
|
0.0
|
LloydRelaxation
dataclass
¶
LloydRelaxation(points: Sequence[Point], iterations: int = 3, region: Bounds | None = None)
Bases: Motif
Points nudged toward the middle of their own cells, over and over.
Lloyd's algorithm, and the cheapest way to turn a clumped scatter into an even one that still looks unplanned. Each pass replaces every point with the center of area of its Voronoi cell; a point in a crowd is off-center in its own cell and drifts away from the crowd, a point in a gap is already central and stays. The fixed point of that -- reached in a handful of passes -- is a centroidal diagram, which is what stippling, dot art and object scattering all want.
Produces loose points, not strokes: the result is the input to the other motifs here rather than a drawing of its own.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
sequence of (float, float)
|
The sites to even out. At least three, not all on one line. |
required |
iterations
|
int
|
Passes to run. Most of the work happens in the first three. |
3
|
region
|
Bounds
|
The area the points are kept inside. Defaults to their own extent, grown by a tenth, and is fixed at the start so the set cannot creep. |
None
|
Methods:
| Name | Description |
|---|---|
relaxed |
Return the points after the relaxation, ready to feed another motif. |
relaxed
¶
Return the points after the relaxation, ready to feed another motif.