code wiki / (root) / nx_poisson_disk_test.nx

nx_poisson_disk_test.nx source

↩ module page · 93 lines · 3921 B

1// nx_poisson_disk_test.nx -- smoke for Bridson 2007 Poisson disk. 2 3import "nx_syscalls.nx" 4import "nx_tier.nx" 5import "nx_poisson_disk.nx" 6 7func main() -> nx_int { 8 // === Test 1: same seed -> identical point sets (determinism) === 9 let max_pts: nx_int = 256 10 let xs_a: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 11 let ys_a: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 12 let n_a: nx_int = nx_poisson_disk_sample(42, 64, 64, 8, xs_a, ys_a, max_pts) 13 let xs_b: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 14 let ys_b: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 15 let n_b: nx_int = nx_poisson_disk_sample(42, 64, 64, 8, xs_b, ys_b, max_pts) 16 if n_a != n_b { return 1 } 17 var i: nx_int = 0 18 while i < n_a { 19 if xs_a[i] != xs_b[i] { return 2 } 20 if ys_a[i] != ys_b[i] { return 3 } 21 i = i + 1 22 } 23 24 // === Test 2: minimum-distance invariant -- no two points within r === 25 // Bridson's defining property: any pair of returned points must be 26 // at least r apart. 27 let r: nx_int = 8 28 var i2: nx_int = 0 29 while i2 < n_a { 30 var j2: nx_int = i2 + 1 31 while j2 < n_a { 32 let dx: nx_int = xs_a[i2] - xs_a[j2] 33 let dy: nx_int = ys_a[i2] - ys_a[j2] 34 let d_sq: nx_int = dx * dx + dy * dy 35 // Bridson allows points at exactly distance r; allow tiny tolerance. 36 if d_sq < (r * r - r) { return 10 } 37 j2 = j2 + 1 38 } 39 i2 = i2 + 1 40 } 41 42 // === Test 3: all points in bounds === 43 var i3: nx_int = 0 44 while i3 < n_a { 45 if xs_a[i3] < 0 { return 20 } 46 if xs_a[i3] >= 64 { return 21 } 47 if ys_a[i3] < 0 { return 22 } 48 if ys_a[i3] >= 64 { return 23 } 49 i3 = i3 + 1 50 } 51 52 // === Test 4: different seeds -> different sets (at least different counts OR positions) === 53 let xs_c: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 54 let ys_c: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 55 let n_c: nx_int = nx_poisson_disk_sample(99, 64, 64, 8, xs_c, ys_c, max_pts) 56 // Different seed: even if counts match (likely), positions should differ. 57 var any_diff: nx_int = 0 58 if n_a != n_c { any_diff = 1 } 59 if n_a == n_c { 60 var i4: nx_int = 0 61 while i4 < n_a { 62 if xs_a[i4] != xs_c[i4] { any_diff = 1 } 63 if ys_a[i4] != ys_c[i4] { any_diff = 1 } 64 i4 = i4 + 1 65 } 66 } 67 if any_diff != 1 { return 30 } 68 69 // === Test 5: edge case -- r = 0 or w = 0 returns 0 points === 70 let xs_e: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 71 let ys_e: *i64 = (sys_mmap(max_pts * NX_SIZEOF_NX_INT)) as *i64 72 if nx_poisson_disk_sample(1, 64, 64, 0, xs_e, ys_e, max_pts) != 0 { return 40 } 73 if nx_poisson_disk_sample(1, 0, 64, 8, xs_e, ys_e, max_pts) != 0 { return 41 } 74 if nx_poisson_disk_sample(1, 64, 64, 8, xs_e, ys_e, 0) != 0 { return 42 } 75 76 // === Test 6: qualitative density classification === 77 if nx_poisson_disk_band_is_valid(NX_PD_BAND_SPARSE) != 1 { return 50 } 78 if nx_poisson_disk_band_is_valid(NX_PD_BAND_SATURATED) != 1 { return 51 } 79 if nx_poisson_disk_band_is_valid(99) != 0 { return 52 } 80 // Actual n_a achieved should classify into one of the bands. 81 let band: nx_int = nx_poisson_disk_classify(n_a, 64, 64, 8) 82 if nx_poisson_disk_band_is_valid(band) != 1 { return 53 } 83 // Zero points always SPARSE. 84 if nx_poisson_disk_classify(0, 64, 64, 8) != NX_PD_BAND_SPARSE { return 54 } 85 86 // === Test 7: at least the seed point lands === 87 if n_a < 1 { return 60 } 88 // And typically Bridson fills ~50-70% of theoretical max for r=8 in 64x64; 89 // so n_a should not be just 1. Loose lower bound: at least 5. 90 if n_a < 5 { return 61 } 91 92 return 0 93}