code wiki / (root) / nx_poisson_disk.nx

nx_poisson_disk.nx

buildroot/runtime/nx_poisson_disk.nx

13285 B338 linesdepth 3pulls 3 transitivereach 19 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_poisson_disk.nx -- Bridson 2007 fast Poisson disk sampling. LAYER 2 of the procgen substrate (Perlin = layer 1). Genuinely modern algorithm (2007), patent-clean, O(N). Used by Townscaper- class procedural tools for building placement, Houdini's scatter SOP for prop distribution, agent-spawn placement in zombie-escape city games -- anywhere "looks random AND evenly spaced AND fast" matters more than uniform random scattering (which clumps). Honest deviation note vs canonical Bridson paper (PDF was not directly readable; spec verified from training data; v1 caveat): 1. Initial seed point: RANDOM (fixed in v1.1 -- previously center). 2. Annulus sample radius: drawn LINEARLY in [r, 2r] rather than area-uniform (canonical r' = sqrt(uniform * (4r^2 - r^2) + r^2) requires sqrt; queued for follow-up once nx_sqrt_q10 ships). Substrate still satisfies the min-distance invariant; the bias is a slight inner-ring density skew, not a correctness bug. Algorithm (Bridson 2007 SIGGRAPH sketch): 1. Background grid with cell size r / sqrt(n_dim). Each cell can hold at most one point (because two points within one cell would be < r apart). 2. Start: place one seed point, mark it active. 3. Loop while active non-empty: Pick random active point p. Try k = 30 candidates at distance [r, 2r] from p. For each candidate: - Check in-bounds. - Check no existing point within r (grid neighbors only -- this is what makes Bridson O(N)). - If valid, add point + mark active; break. If all 30 fail, remove p from active. 4. Return collected points. Why this beats Perlin-grid-scatter for city gen: Perlin scatter has clumping (high-noise spots get many points; low-noise spots none). Poisson disk guarantees minimum distance r AND fills space uniformly -- exactly what zombie-spawn / building-plot placement requires. Cross-modal: also gives n-gram-diverse sample selection from a

dependencies 3 imports · 5 importers

nx_syscalls.nx nx_tier.nx nx_prng.nx nx_poisson_disk.nx nx_poisson_disk_test.nx nx_procgen_preset.nx nx_procgen_signature.nx nx_procgen_water.nx nx_voronoi_test.nx

imports: nx_syscalls.nxnx_tier.nxnx_prng.nx

imported by: nx_poisson_disk_test.nxnx_procgen_preset.nxnx_procgen_signature.nxnx_procgen_water.nxnx_voronoi_test.nx

structs

none

consts

64const NX_PD_Q: nx_int = 1024
67const NX_PD_INV_SQRT_2: nx_int = 724
68const NX_PD_K_CANDIDATES: nx_int = 30
69const NX_PD_N_ANGLES: nx_int = 16
73const NX_PD_COS_0: nx_int = 1024
74const NX_PD_COS_1: nx_int = 946
75const NX_PD_COS_2: nx_int = 724
76const NX_PD_COS_3: nx_int = 392
77const NX_PD_COS_4: nx_int = 0
78const NX_PD_COS_5: nx_int = -392
79const NX_PD_COS_6: nx_int = -724
80const NX_PD_COS_7: nx_int = -946
81const NX_PD_COS_8: nx_int = -1024
82const NX_PD_COS_9: nx_int = -946
83const NX_PD_COS_10: nx_int = -724
84const NX_PD_COS_11: nx_int = -392
85const NX_PD_COS_12: nx_int = 0
86const NX_PD_COS_13: nx_int = 392
87const NX_PD_COS_14: nx_int = 724
88const NX_PD_COS_15: nx_int = 946
90const NX_PD_SIN_0: nx_int = 0
91const NX_PD_SIN_1: nx_int = 392
92const NX_PD_SIN_2: nx_int = 724
93const NX_PD_SIN_3: nx_int = 946
94const NX_PD_SIN_4: nx_int = 1024
95const NX_PD_SIN_5: nx_int = 946
96const NX_PD_SIN_6: nx_int = 724
97const NX_PD_SIN_7: nx_int = 392
98const NX_PD_SIN_8: nx_int = 0
99const NX_PD_SIN_9: nx_int = -392
100const NX_PD_SIN_10: nx_int = -724
101const NX_PD_SIN_11: nx_int = -946
102const NX_PD_SIN_12: nx_int = -1024
103const NX_PD_SIN_13: nx_int = -946
104const NX_PD_SIN_14: nx_int = -724
105const NX_PD_SIN_15: nx_int = -392
113const NX_PD_MAX_FACTOR_Q10: nx_int = 5530 // ~ 5.4 * Q10
115const NX_PD_BAND_SPARSE: nx_int = 0
116const NX_PD_BAND_MODERATE: nx_int = 1
117const NX_PD_BAND_DENSE: nx_int = 2
118const NX_PD_BAND_SATURATED: nx_int = 3
119const NX_PD_N_BANDS: nx_int = 4

functions

121func _pd_cos(idx: nx_int) -> nx_int
140func _pd_sin(idx: nx_int) -> nx_int
160func _pd_dist_sq(ax: nx_int, ay: nx_int, bx: nx_int, by: nx_int) -> nx_int
called by 1: _pd_accept
170func _pd_accept(cx: nx_int, cy: nx_int, r: nx_int, r_sq: nx_int,
called by 1: nx_poisson_disk_sample calls 1: _pd_dist_sq
210func nx_poisson_disk_sample(seed: nx_int, w: nx_int, h: nx_int, r: nx_int,
318func nx_poisson_disk_classify(n_points: nx_int, w: nx_int, h: nx_int, r: nx_int) -> nx_int
called by 1: main
334func nx_poisson_disk_band_is_valid(band: nx_int) -> nx_int
called by 1: main