Planar 2D (pyvoro2.planar)
pyvoro2 now ships a dedicated planar 2D namespace:
import pyvoro2.planar as pv2
This is intentionally separate from the 3D top-level API. The goal is to keep both surfaces explicit and mathematically honest:
pyvoro2is the 3D package,pyvoro2.planaris the 2D package.
The current 2D release scope is deliberately limited to the domains that the vendored legacy backend supports well:
pv2.Boxpv2.RectangularCell
There is no planar PeriodicCell yet. Rectangular periodic domains can be
periodic in either or both planar axes.
Basic compute
import numpy as np
import pyvoro2.planar as pv2
pts = np.array([
[0.2, 0.2],
[0.8, 0.2],
[0.5, 0.8],
], dtype=float)
cells = pv2.compute(
pts,
domain=pv2.Box(((0.0, 1.0), (0.0, 1.0))),
return_vertices=True,
return_edges=True,
)
Raw planar cells are dimension-specific by design:
areainstead ofvolume,edgesinstead offaces,adjacent_shiftis a length-2 periodic image shift when requested.
Rectangular periodic cells and edge shifts
For periodic rectangular domains, request return_edge_shifts=True when you
need the explicit periodic image of the neighboring site:
cell = pv2.RectangularCell(
((0.0, 1.0), (0.0, 1.0)),
periodic=(True, True),
)
cells = pv2.compute(
pts,
domain=cell,
return_vertices=True,
return_edges=True,
return_edge_shifts=True,
)
The planar wrapper reconstructs these edge shifts in Python and also repairs a legacy backend quirk where some fully periodic adjacencies can otherwise appear with negative neighbor ids.
locate(...) and ghost_cells(...)
The planar namespace mirrors the 3D operation names:
owners = pv2.locate(pts, [[0.1, 0.2], [0.9, 0.2]], domain=cell)
ghost = pv2.ghost_cells(
pts,
[[0.5, 0.5]],
domain=cell,
return_vertices=True,
return_edges=True,
)
So the same three high-level questions exist in both dimensions:
- compute every cell,
- locate the owner of a query point,
- compute the hypothetical cell of a query point without inserting it.
Diagnostics and wrapper-level convenience
Planar compute(...) supports the same kind of post-compute convenience that
3D users already expect, but specialized for 2D semantics:
cells, diag = pv2.compute(
pts,
domain=cell,
return_diagnostics=True,
)
For periodic domains, the wrapper automatically computes the temporary geometry needed for reciprocity checks and then strips it back out of the raw returned cells unless you explicitly requested it.
The same holds for normalization convenience:
result = pv2.compute(
pts,
domain=cell,
return_diagnostics=True,
normalize='topology',
)
This returns a pv2.PlanarComputeResult bundling:
- raw
cells, - optional tessellation diagnostics,
- optional normalized vertices,
- optional normalized topology.
This keeps the public API structured once the user wants more than a bare list of raw cells.
Planar normalization
The dedicated planar normalization helpers are:
pv2.normalize_vertices(...)pv2.normalize_edges(...)pv2.normalize_topology(...)pv2.validate_normalized_topology(...)
In planar topology work, the globally deduplicated boundary objects are edges, not faces.
Planar plotting
For quick inspection, use the optional matplotlib helper:
from pyvoro2.planar import plot_tessellation
fig, ax = plot_tessellation(cells, annotate_ids=True)
Install it with:
pip install "pyvoro2[viz2d]"
or install both 2D and 3D visualization helpers with:
pip install "pyvoro2[viz]"
Planar power fitting
The generic pairwise-separator powerfit API now supports planar domains too.
The solver vocabulary is shared between 2D and 3D; what changes is the meaning
of the realized boundary measure:
- face area in 3D,
- edge length in 2D.
The current planar domain restriction still applies here: rectangular periodic
cells are supported, but there is no planar oblique-periodic PeriodicCell
yet.