use std::collections::HashMap;
pub mod morton {
fn part1by1(mut v: u64) -> u64 {
v &= 0x0000_0000_ffff_ffff;
v = (v | (v << 16)) & 0x0000_ffff_0000_ffff;
v = (v | (v << 8)) & 0x00ff_00ff_00ff_00ff;
v = (v | (v << 4)) & 0x0f0f_0f0f_0f0f_0f0f;
v = (v | (v << 2)) & 0x3333_3333_3333_3333;
v = (v | (v << 1)) & 0x5555_5555_5555_5555;
v
}
fn compact1by1(mut v: u64) -> u64 {
v &= 0x5555_5555_5555_5555;
v = (v | (v >> 1)) & 0x3333_3333_3333_3333;
v = (v | (v >> 2)) & 0x0f0f_0f0f_0f0f_0f0f;
v = (v | (v >> 4)) & 0x00ff_00ff_00ff_00ff;
v = (v | (v >> 8)) & 0x0000_ffff_0000_ffff;
v = (v | (v >> 16)) & 0x0000_0000_ffff_ffff;
v
}
pub fn encode_2d(x: u32, y: u32) -> u64 {
part1by1(x as u64) | (part1by1(y as u64) << 1)
}
pub fn decode_2d(code: u64) -> (u32, u32) {
(compact1by1(code) as u32, compact1by1(code >> 1) as u32)
}
fn part1by2(mut v: u64) -> u64 {
v &= 0x1f_ffff;
v = (v | (v << 32)) & 0x001f_0000_0000_ffff;
v = (v | (v << 16)) & 0x001f_0000_ff00_00ff;
v = (v | (v << 8)) & 0x100f_00f0_0f00_f00f;
v = (v | (v << 4)) & 0x10c3_0c30_c30c_30c3;
v = (v | (v << 2)) & 0x1249_2492_4924_9249;
v
}
fn compact1by2(mut v: u64) -> u64 {
v &= 0x1249_2492_4924_9249;
v = (v | (v >> 2)) & 0x10c3_0c30_c30c_30c3;
v = (v | (v >> 4)) & 0x100f_00f0_0f00_f00f;
v = (v | (v >> 8)) & 0x001f_0000_ff00_00ff;
v = (v | (v >> 16)) & 0x001f_0000_0000_ffff;
v = (v | (v >> 32)) & 0x1f_ffff;
v
}
pub fn encode_3d(x: u32, y: u32, z: u32) -> u64 {
part1by2(x as u64) | (part1by2(y as u64) << 1) | (part1by2(z as u64) << 2)
}
pub fn decode_3d(code: u64) -> (u32, u32, u32) {
(compact1by2(code) as u32, compact1by2(code >> 1) as u32, compact1by2(code >> 2) as u32)
}
}
#[derive(Debug, Clone, Copy)]
pub struct GridQuantizer {
origin_x: f32,
origin_y: f32,
cell_size: f32,
}
impl GridQuantizer {
pub fn new(origin: (f32, f32), cell_size: f32) -> Self {
if cell_size <= 0.0 || cell_size.is_nan() {
panic!("GridQuantizer cell_size must be positive");
}
Self {
origin_x: origin.0,
origin_y: origin.1,
cell_size,
}
}
pub fn cell(&self, x: f32, y: f32) -> (u32, u32) {
let cx = ((x - self.origin_x) / self.cell_size).floor().max(0.0);
let cy = ((y - self.origin_y) / self.cell_size).floor().max(0.0);
(cx as u32, cy as u32)
}
pub fn key(&self, x: f32, y: f32) -> u64 {
let (cx, cy) = self.cell(x, y);
morton::encode_2d(cx, cy)
}
pub fn cells_for_radius(&self, radius: f32) -> u32 {
(radius / self.cell_size).ceil().max(0.0) as u32
}
pub fn cell_size(&self) -> f32 {
self.cell_size
}
}
#[derive(Debug, Clone)]
pub struct SpatialGrid<Id: Copy> {
quantizer: GridQuantizer,
cells: HashMap<u64, Vec<Id>>,
}
impl<Id: Copy> SpatialGrid<Id> {
pub fn new(quantizer: GridQuantizer) -> Self {
Self {
quantizer,
cells: HashMap::new(),
}
}
pub fn clear(&mut self) {
for bucket in self.cells.values_mut() {
bucket.clear();
}
}
pub fn insert(&mut self, id: Id, x: f32, y: f32) {
let key = self.quantizer.key(x, y);
self.cells.entry(key).or_default().push(id);
}
pub fn query_radius(&self, x: f32, y: f32, radius: f32, out: &mut Vec<Id>) {
let (cx, cy) = self.quantizer.cell(x, y);
let r = self.quantizer.cells_for_radius(radius);
let (x0, x1) = (cx.saturating_sub(r), cx.saturating_add(r));
let (y0, y1) = (cy.saturating_sub(r), cy.saturating_add(r));
for gy in y0..=y1 {
for gx in x0..=x1 {
if let Some(bucket) = self.cells.get(&morton::encode_2d(gx, gy)) {
out.extend_from_slice(bucket);
}
}
}
}
pub fn quantizer(&self) -> &GridQuantizer {
&self.quantizer
}
}
#[derive(Debug, Clone, Copy)]
pub struct TierBoundary {
enter: f32,
leave: f32,
}
impl TierBoundary {
pub const fn new(enter: f32, leave: f32) -> Self {
debug_assert!(enter <= leave, "hysteresis needs enter <= leave");
Self {
enter,
leave: if leave < enter { enter } else { leave },
}
}
pub fn admits(&self, was_inside: bool, distance: f32) -> bool {
distance <= if was_inside { self.leave } else { self.enter }
}
}
#[derive(Debug, Clone, Default)]
pub struct VisibilitySet {
words: Vec<u64>,
}
impl VisibilitySet {
pub fn new() -> Self {
Self { words: Vec::new() }
}
pub fn with_capacity(max_index: u32) -> Self {
Self {
words: vec![0; (max_index as usize / 64) + 1],
}
}
pub fn clear(&mut self) {
for w in &mut self.words {
*w = 0;
}
}
pub fn insert(&mut self, index: u32) {
let (w, bit) = (index as usize / 64, index as usize % 64);
if w >= self.words.len() {
self.words.resize(w + 1, 0);
}
self.words[w] |= 1u64 << bit;
}
pub fn remove(&mut self, index: u32) {
let (w, bit) = (index as usize / 64, index as usize % 64);
if let Some(word) = self.words.get_mut(w) {
*word &= !(1u64 << bit);
}
}
pub fn contains(&self, index: u32) -> bool {
let (w, bit) = (index as usize / 64, index as usize % 64);
self.words.get(w).is_some_and(|word| word & (1u64 << bit) != 0)
}
pub fn diff(&self, previous: &VisibilitySet, entered: &mut Vec<u32>, left: &mut Vec<u32>) {
let n = self.words.len().max(previous.words.len());
for w in 0..n {
let cur = self.words.get(w).copied().unwrap_or(0);
let prev = previous.words.get(w).copied().unwrap_or(0);
emit_bits(cur & !prev, w, entered);
emit_bits(prev & !cur, w, left);
}
}
pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
self.words.iter().enumerate().flat_map(|(w, &word)| BitIter { word, base: (w * 64) as u32 })
}
pub fn digest(&self) -> u64 {
SetDigest::from_keys(self.iter().map(u64::from)).digest()
}
pub fn count(&self) -> usize {
self.words.iter().map(|w| w.count_ones() as usize).sum()
}
#[cfg(test)]
fn from_iter_for_test<I: IntoIterator<Item = u32>>(ids: I) -> Self {
let mut v = Self::new();
for i in ids {
v.insert(i);
}
v
}
}
pub use plaza_client_utils::digest::SetDigest;
fn emit_bits(mut word: u64, w: usize, out: &mut Vec<u32>) {
let base = (w * 64) as u32;
while word != 0 {
out.push(base + word.trailing_zeros());
word &= word - 1; }
}
struct BitIter {
word: u64,
base: u32,
}
impl Iterator for BitIter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.word == 0 {
return None;
}
let idx = self.base + self.word.trailing_zeros();
self.word &= self.word - 1;
Some(idx)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn morton_2d_round_trips_across_the_range() {
for &(x, y) in &[(0u32, 0u32), (1, 0), (0, 1), (12345, 67890), (u32::MAX, u32::MAX), (0xdead_beef, 0x0bad_f00d)] {
let code = morton::encode_2d(x, y);
assert_eq!(morton::decode_2d(code), (x, y), "2d round trip for ({x}, {y})");
}
}
#[test]
fn morton_3d_round_trips_within_21_bits() {
let max21 = (1u32 << 21) - 1;
for &(x, y, z) in &[(0u32, 0u32, 0u32), (1, 2, 3), (max21, max21, max21), (100_000, 5, 2_000_000)] {
let code = morton::encode_3d(x, y, z);
assert_eq!(morton::decode_3d(code), (x, y, z), "3d round trip for ({x}, {y}, {z})");
}
}
#[test]
fn morton_preserves_locality_within_a_cell_row() {
let a = morton::encode_2d(10, 10);
let b = morton::encode_2d(11, 10);
let far = morton::encode_2d(10, 1000);
assert!((a as i64 - b as i64).abs() < (a as i64 - far as i64).abs(), "neighbours are closer in code than a distant cell");
}
#[test]
fn the_quantizer_maps_points_to_cells_and_clamps_below_the_origin() {
let q = GridQuantizer::new((0.0, 0.0), 10.0);
assert_eq!(q.cell(5.0, 5.0), (0, 0));
assert_eq!(q.cell(15.0, 25.0), (1, 2));
assert_eq!(q.cell(-4.0, -100.0), (0, 0), "below the origin clamps to cell 0");
assert_eq!(q.cells_for_radius(25.0), 3, "25 world units spans 3 cells of 10");
}
#[test]
#[should_panic]
fn a_non_positive_cell_size_panics() {
let _ = GridQuantizer::new((0.0, 0.0), 0.0);
}
#[test]
fn the_grid_returns_ids_near_a_point_and_omits_distant_ones() {
let q = GridQuantizer::new((0.0, 0.0), 10.0);
let mut grid = SpatialGrid::new(q);
grid.insert(1u32, 5.0, 5.0); grid.insert(2, 12.0, 5.0); grid.insert(3, 500.0, 500.0);
let mut out = Vec::new();
grid.query_radius(5.0, 5.0, 10.0, &mut out); assert!(out.contains(&1) && out.contains(&2), "near ids returned: {out:?}");
assert!(!out.contains(&3), "distant id omitted");
}
#[test]
fn clearing_the_grid_keeps_capacity_and_empties_buckets() {
let q = GridQuantizer::new((0.0, 0.0), 10.0);
let mut grid = SpatialGrid::new(q);
grid.insert(1u32, 5.0, 5.0);
grid.clear();
let mut out = Vec::new();
grid.query_radius(5.0, 5.0, 10.0, &mut out);
assert!(out.is_empty(), "cleared grid returns nothing");
}
#[test]
fn a_visibility_set_inserts_and_contains() {
let mut v = VisibilitySet::new();
v.insert(3);
v.insert(70); assert!(v.contains(3) && v.contains(70));
assert!(!v.contains(4));
assert_eq!(v.count(), 2);
let seen: Vec<u32> = v.iter().collect();
assert_eq!(seen, vec![3, 70], "iterates ascending across words");
}
#[test]
fn a_digest_ignores_order_but_not_contents() {
let a = SetDigest::from_keys([7u64, 1, 99, 4]);
let b = SetDigest::from_keys([99u64, 4, 7, 1]);
assert_eq!(a.digest(), b.digest(), "the same set in a different order agrees");
let c = SetDigest::from_keys([7u64, 1, 99, 5]);
assert_ne!(a.digest(), c.digest(), "a different member disagrees");
let d = SetDigest::from_keys([7u64, 1, 99]);
assert_ne!(a.digest(), d.digest(), "a missing member disagrees");
}
#[test]
fn maintaining_a_digest_incrementally_matches_rebuilding_it() {
let mut live = SetDigest::new();
for k in [3u64, 9, 21, 40] {
live.insert(k);
}
live.remove(9);
live.insert(77);
let rebuilt = SetDigest::from_keys([3u64, 21, 40, 77]);
assert_eq!(live.digest(), rebuilt.digest(), "O(1) updates agree with a full rebuild");
assert_eq!(live.len(), 4);
}
#[test]
fn a_delta_that_never_landed_is_detectable() {
let mut server = SetDigest::from_keys([1u64, 2, 3, 4]);
let client = SetDigest::from_keys([1u64, 2, 3, 4]);
assert_eq!(server.digest(), client.digest());
server.remove(3); assert_ne!(server.digest(), client.digest(), "the mirror is stale and it shows");
}
#[test]
fn a_visibility_set_digest_tracks_its_membership() {
let mut v = VisibilitySet::new();
for i in [2u32, 8, 300] {
v.insert(i);
}
let before = v.digest();
v.remove(8);
assert_ne!(before, v.digest());
let same = VisibilitySet::from_iter_for_test([2u32, 300]);
assert_eq!(v.digest(), same.digest(), "membership alone decides the digest");
}
#[test]
fn removing_clears_a_bit_so_a_reused_slot_reads_as_a_fresh_arrival() {
let mut v = VisibilitySet::new();
v.insert(5);
v.remove(5);
assert!(!v.contains(5));
let mut next = VisibilitySet::new();
next.insert(5);
let (mut entered, mut left) = (Vec::new(), Vec::new());
next.diff(&v, &mut entered, &mut left);
assert_eq!(entered, vec![5]);
assert!(left.is_empty());
}
#[test]
fn the_visibility_diff_reports_spawns_and_despawns() {
let mut prev = VisibilitySet::new();
for i in [1, 2, 3] {
prev.insert(i);
}
let mut cur = VisibilitySet::new();
for i in [2, 3, 4, 100] {
cur.insert(i);
}
let (mut entered, mut left) = (Vec::new(), Vec::new());
cur.diff(&prev, &mut entered, &mut left);
assert_eq!(entered, vec![4, 100], "newly visible: spawn these");
assert_eq!(left, vec![1], "no longer visible: despawn these");
}
#[test]
fn a_full_relevance_pass_matches_a_brute_force_check() {
let q = GridQuantizer::new((0.0, 0.0), 32.0);
let mut grid = SpatialGrid::new(q);
let radius = 50.0;
let entities: Vec<(u32, f32, f32)> = (0..200u32)
.map(|i| {
let x = ((i * 73 % 1000) as f32) + 0.5;
let y = ((i * 149 % 1000) as f32) + 0.5;
(i, x, y)
})
.collect();
for &(id, x, y) in &entities {
grid.insert(id, x, y);
}
let (vx, vy) = (500.0f32, 500.0f32); let brute: std::collections::BTreeSet<u32> = entities
.iter()
.filter(|(_, x, y)| ((x - vx).powi(2) + (y - vy).powi(2)).sqrt() <= radius)
.map(|(id, _, _)| *id)
.collect();
let mut candidates = Vec::new();
grid.query_radius(vx, vy, radius, &mut candidates);
let grid_result: std::collections::BTreeSet<u32> = candidates
.into_iter()
.filter(|id| {
let (_, x, y) = entities[*id as usize];
((x - vx).powi(2) + (y - vy).powi(2)).sqrt() <= radius
})
.collect();
assert_eq!(grid_result, brute, "grid + exact test equals brute force");
}
#[test]
fn a_peer_loitering_on_the_boundary_does_not_flap() {
let tier = TierBoundary::new(100.0, 120.0);
assert!(tier.admits(true, 110.0));
assert!(tier.admits(true, 119.0));
assert!(!tier.admits(false, 110.0));
assert!(!tier.admits(false, 101.0));
assert!(tier.admits(false, 99.0));
assert!(!tier.admits(true, 121.0));
}
}