nx_voronoi.nx
buildroot/runtime/nx_voronoi.nx
about
nx_voronoi.nx -- 2D Voronoi diagram (procgen LAYER 3).
Sites are scattered in [0, w) x [0, h); each cell of the canvas is
assigned to its NEAREST site by squared Euclidean distance. Output
is a per-pixel label array (which site index owns each pixel).
USE CASES:
- City-block partition for procgen city generation (each block
becomes a Voronoi cell around its district seed)
- Zombie-escape agent territories (each spawn point owns the
region closest to it)
- Reaction-diffusion / cellular-automaton substrate (cell shape)
- Crystal-grain texture for procgen surfaces
- Lloyd relaxation seed for centroidal Voronoi tessellation
ALGORITHM:
Brute-force nearest-site per pixel. For each pixel (x, y), scan
all n_sites and pick the index with minimum (dx^2 + dy^2). Cost:
O(w * h * n_sites). Patent-clean (squared-distance is textbook).
SCALING NOTE:
Fortune's sweepline (1986) and Aurenhammer (1991) give O(n log n)
for the EDGES of the diagram, but per-pixel labelling for a
raster canvas is still O(w*h*n) without spatial acceleration.
For substrate use (canvas <= 256x256, sites <= 256), brute-force
is fast under qemu-riscv64 -- millions of i64 ops, no f64, no
sqrt. Upgrade path: jump-flooding-algorithm (JFA, Rong+Tan 2006)
for GPU-equivalent O(w*h*log(max(w,h))) when canvas grows.
QUALITATIVE BAND (dual-reading cardinal):
Per-site cell-area sealed enum classifies how uniform the
partition is, derived from variance of per-site pixel count.
COMPOSITION:
sites can be supplied by any source -- in practice
nx_poisson_disk_sample gives the most visually-pleasing
uniform-but-not-grid distribution. Demo wiring in
nx_voronoi_test.nx.
genealogy_id: voronoi_1908 + dirichlet_1850 + fortune_1986 +
dependencies 2 imports · 1 importers
imports: nx_syscalls.nxnx_tier.nx
imported by: nx_voronoi_test.nx
structs
| none |
consts
| 59 | const NX_VORONOI_BAND_UNIFORM: nx_int = 0 // very even, CV < 0.15 |
| 60 | const NX_VORONOI_BAND_BALANCED: nx_int = 1 // moderate spread, CV < 0.35 |
| 61 | const NX_VORONOI_BAND_LOPSIDED: nx_int = 2 // some sites dominate, CV < 0.65 |
| 62 | const NX_VORONOI_BAND_DEGENERATE: nx_int = 3 // wildly uneven, CV >= 0.65 |
| 63 | const NX_VORONOI_N_BANDS: nx_int = 4 |
| 65 | const NX_VORONOI_Q: nx_int = 1024 |
| 67 | const NX_VORONOI_CV_UNIFORM_Q10: nx_int = 154 |
| 68 | const NX_VORONOI_CV_BALANCED_Q10: nx_int = 358 |
| 69 | const NX_VORONOI_CV_LOPSIDED_Q10: nx_int = 666 |
functions
| 71 | func nx_voronoi_band_is_valid(band: nx_int) -> nx_int called by 1: main |
| 83 | func nx_voronoi_label(w: nx_int, h: nx_int, called by 1: main |
| 122 | func nx_voronoi_site_counts(w: nx_int, h: nx_int, called by 1: main |
| 154 | func _vor_isqrt(n: nx_int) -> nx_int called by 1: nx_voronoi_classify |
| 187 | func nx_voronoi_classify(counts: *i64, n_sites: nx_int) -> nx_int |
| 220 | func nx_voronoi_label_at(labels: *i64, w: nx_int, h: nx_int, called by 1: main |