pub const GRID_W: u32 = 256;
pub const GRID_H: u32 = 192;
pub const GRID_CELLS: u32 = GRID_W * GRID_H;
pub const NAME_SLOTS: u32 = 16384;
pub const CLAIM_BASE: u32 = 0;
pub const OCC_BASE: u32 = GRID_CELLS;
pub const NAME_CLAIM_BASE: u32 = 2 * GRID_CELLS;
pub const NAME_WON_BASE: u32 = 2 * GRID_CELLS + NAME_SLOTS;
pub const GRID_WORDS: u32 = 2 * GRID_CELLS + 2 * NAME_SLOTS;
pub const LABEL_ROUNDS: u32 = 32;
pub const MIN_REPEAT_PX: f32 = 380.0;
pub const REPEAT_CELL_PX: f32 = MIN_REPEAT_PX * 0.5;
pub const LABEL_PAD_PX: [f32; 2] = [10.0, 6.0];
pub const MAX_VISIBLE_LABELS: u32 = 48;
pub const HALO_TAPS: u32 = 4;
pub const INSTANCES_PER_GLYPH: u32 = HALO_TAPS + 1;
pub const HALO_OFFSETS: [[f32; 2]; HALO_TAPS as usize] =
[[1.0, 0.0], [-1.0, 0.0], [0.0, 1.0], [0.0, -1.0]];
#[must_use]
pub fn name_hash(text: &str) -> u32 {
let mut h: u32 = 0x811C_9DC5;
for b in text.as_bytes() {
h ^= u32::from(*b);
h = h.wrapping_mul(0x0100_0193);
}
if h == 0 { 1 } else { h }
}
#[must_use]
pub fn priority(rank: u8, order: u32) -> u32 {
(u32::from(rank) << 24) | (0x00FF_FFFF - order.min(0x00FF_FFFE))
}
pub const BLOCKER_RANK: u8 = 0xFF;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ScreenLabel {
pub center: [f32; 2],
pub half: [f32; 2],
pub priority: u32,
pub name_hash: u32,
pub lod: u32,
pub blocker: bool,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LabelGridParams {
pub viewport: [f32; 2],
pub inv_cell: [f32; 2],
pub inv_repeat: f32,
pub lod: u32,
}
impl LabelGridParams {
#[must_use]
pub fn new(viewport: [f32; 2], lod: u32) -> Self {
let w = if viewport[0] > 0.0 { viewport[0] } else { 1.0 };
let h = if viewport[1] > 0.0 { viewport[1] } else { 1.0 };
Self {
viewport: [w, h],
inv_cell: [GRID_W as f32 / w, GRID_H as f32 / h],
inv_repeat: 1.0 / REPEAT_CELL_PX,
lod,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct Footprint {
cx0: u32,
cy0: u32,
cx1: u32,
cy1: u32,
ncx: i32,
ncy: i32,
}
fn footprint(l: &ScreenLabel, p: &LabelGridParams) -> Option<Footprint> {
if l.lod > p.lod {
return None;
}
let (cx, cy, hx, hy) = (l.center[0], l.center[1], l.half[0].abs(), l.half[1].abs());
if !(cx.is_finite() && cy.is_finite() && hx.is_finite() && hy.is_finite()) {
return None;
}
let (x0, y0, x1, y1) = (cx - hx, cy - hy, cx + hx, cy + hy);
if x1 < 0.0 || y1 < 0.0 || x0 > p.viewport[0] || y0 > p.viewport[1] {
return None;
}
let span = |lo: f32, hi: f32, inv: f32, n: u32| -> (u32, u32) {
let top = (n - 1) as f32;
let a = (lo * inv).floor().clamp(0.0, top) as u32;
let b = (hi * inv).floor().clamp(0.0, top) as u32;
(a.min(b), a.max(b))
};
let (cx0, cx1) = span(x0, x1, p.inv_cell[0], GRID_W);
let (cy0, cy1) = span(y0, y1, p.inv_cell[1], GRID_H);
Some(Footprint {
cx0,
cy0,
cx1,
cy1,
ncx: (cx * p.inv_repeat).floor() as i32,
ncy: (cy * p.inv_repeat).floor() as i32,
})
}
#[must_use]
pub fn repeat_slot(name_hash: u32, ncx: i32, ncy: i32) -> u32 {
let mut h = name_hash
^ (ncx as u32).wrapping_mul(0x9E37_79B9)
^ (ncy as u32).wrapping_mul(0x85EB_CA6B);
h ^= h >> 15;
h = h.wrapping_mul(0x2C1B_3C6D);
h ^= h >> 12;
h % NAME_SLOTS
}
pub const LS_PENDING: u32 = 0;
pub const LS_WON: u32 = 1;
pub const LS_BLOCKED: u32 = 2;
pub const LS_RETIRED: u32 = 3;
fn blocked(grid: &[u32], f: &Footprint) -> bool {
for cy in f.cy0..=f.cy1 {
for cx in f.cx0..=f.cx1 {
if grid[(OCC_BASE + cy * GRID_W + cx) as usize] != 0 {
return true;
}
}
}
false
}
fn owns_claim(grid: &[u32], f: &Footprint, priority: u32) -> bool {
for cy in f.cy0..=f.cy1 {
for cx in f.cx0..=f.cx1 {
if grid[(CLAIM_BASE + cy * GRID_W + cx) as usize] != priority {
return false;
}
}
}
true
}
pub fn resolve_into(labels: &[ScreenLabel], p: &LabelGridParams, grid: &mut Vec<u32>) -> Vec<u32> {
grid.clear();
grid.resize(GRID_WORDS as usize, 0);
let fps: Vec<Option<Footprint>> = labels.iter().map(|l| footprint(l, p)).collect();
let mut ls: Vec<u32> =
fps.iter().map(|f| if f.is_some() { LS_PENDING } else { LS_BLOCKED }).collect();
let mut winners: Vec<u32> = Vec::new();
for _round in 0..LABEL_ROUNDS {
for w in &mut grid[CLAIM_BASE as usize..(CLAIM_BASE + GRID_CELLS) as usize] {
*w = 0;
}
for w in &mut grid[NAME_CLAIM_BASE as usize..NAME_WON_BASE as usize] {
*w = 0;
}
let mut pending = 0usize;
for (i, l) in labels.iter().enumerate() {
if ls[i] != LS_PENDING {
continue;
}
let f = fps[i].expect("a pending label has a footprint");
if blocked(grid, &f) {
ls[i] = LS_BLOCKED;
continue;
}
pending += 1;
for cy in f.cy0..=f.cy1 {
for cx in f.cx0..=f.cx1 {
let idx = (CLAIM_BASE + cy * GRID_W + cx) as usize;
grid[idx] = grid[idx].max(l.priority);
}
}
}
if pending == 0 {
break; }
for (i, l) in labels.iter().enumerate() {
if ls[i] != LS_PENDING {
continue;
}
let f = fps[i].expect("a pending label has a footprint");
if !owns_claim(grid, &f, l.priority) {
continue;
}
let s = (NAME_CLAIM_BASE + repeat_slot(l.name_hash, f.ncx, f.ncy)) as usize;
grid[s] = grid[s].max(l.priority);
}
let mut round: Vec<u32> = Vec::new();
for (i, l) in labels.iter().enumerate() {
if ls[i] != LS_PENDING {
continue;
}
let f = fps[i].expect("a pending label has a footprint");
if !owns_claim(grid, &f, l.priority) {
continue;
}
let mut repeat_clear = true;
for dy in -1i32..=1 {
for dx in -1i32..=1 {
let slot = repeat_slot(l.name_hash, f.ncx + dx, f.ncy + dy);
if grid[(NAME_CLAIM_BASE + slot) as usize] > l.priority
|| grid[(NAME_WON_BASE + slot) as usize] > l.priority
{
repeat_clear = false;
}
}
}
if repeat_clear {
round.push(i as u32);
} else {
ls[i] = LS_RETIRED;
}
}
for &i in &round {
let l = &labels[i as usize];
let f = fps[i as usize].expect("a round winner has a footprint");
for cy in f.cy0..=f.cy1 {
for cx in f.cx0..=f.cx1 {
let idx = (OCC_BASE + cy * GRID_W + cx) as usize;
grid[idx] = grid[idx].max(l.priority);
}
}
let ns = (NAME_WON_BASE + repeat_slot(l.name_hash, f.ncx, f.ncy)) as usize;
grid[ns] = grid[ns].max(l.priority);
ls[i as usize] = LS_WON;
if !l.blocker {
winners.push(i);
}
}
}
winners.sort_by(|a, b| labels[*b as usize].priority.cmp(&labels[*a as usize].priority));
winners.truncate(MAX_VISIBLE_LABELS as usize);
winners
}
#[must_use]
pub fn resolve(labels: &[ScreenLabel], p: &LabelGridParams) -> Vec<u32> {
let mut grid = Vec::new();
resolve_into(labels, p, &mut grid)
}
pub const FLAG_SCREEN_SPACE: u32 = 1;
pub const FLAG_BLOCKER: u32 = 2;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "wgpu", derive(bytemuck::Pod, bytemuck::Zeroable))]
pub struct LabelCandidate {
pub pos: [f32; 2],
pub half_px: [f32; 2],
pub priority: u32,
pub name_hash: u32,
pub glyph_start: u32,
pub glyph_count: u32,
pub lod: u32,
pub flags: u32,
pub _pad: [u32; 2],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "wgpu", derive(bytemuck::Pod, bytemuck::Zeroable))]
pub struct GlyphSrc {
pub off_min: [f32; 2],
pub off_max: [f32; 2],
pub uv_min: [f32; 2],
pub uv_max: [f32; 2],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "wgpu", derive(bytemuck::Pod, bytemuck::Zeroable))]
pub struct LabelGlyphInstance {
pub rect_min: [f32; 2],
pub rect_max: [f32; 2],
pub uv_min: [f32; 2],
pub uv_max: [f32; 2],
pub color: [f32; 4],
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LabelFrame {
pub zoom: [f32; 2],
pub ref_pos: [f32; 2],
pub screen_center: [f32; 2],
pub viewport: [f32; 2],
pub lod: u32,
pub ink: [f32; 4],
pub halo: [f32; 4],
}
impl LabelFrame {
#[must_use]
pub fn screen(viewport: [f32; 2], lod: u32, ink: egui::Color32, halo: egui::Color32) -> Self {
Self {
zoom: [1.0, 1.0],
ref_pos: [0.0, 0.0],
screen_center: [0.0, 0.0],
viewport,
lod,
ink: color_rgba(ink),
halo: color_rgba(halo),
}
}
#[must_use]
pub fn project(&self, c: &LabelCandidate) -> [f32; 2] {
if c.flags & FLAG_SCREEN_SPACE != 0 {
return c.pos;
}
[
(c.pos[0] - self.ref_pos[0]) * self.zoom[0] + self.screen_center[0],
(c.pos[1] - self.ref_pos[1]) * self.zoom[1] + self.screen_center[1],
]
}
#[must_use]
pub fn grid_params(&self) -> LabelGridParams {
LabelGridParams::new(self.viewport, self.lod)
}
}
#[must_use]
pub fn screen_labels(cands: &[LabelCandidate], frame: &LabelFrame) -> Vec<ScreenLabel> {
cands
.iter()
.map(|c| ScreenLabel {
center: frame.project(c),
half: c.half_px,
priority: c.priority,
name_hash: c.name_hash,
lod: c.lod,
blocker: c.flags & FLAG_BLOCKER != 0,
})
.collect()
}
#[must_use]
pub fn color_rgba(c: egui::Color32) -> [f32; 4] {
let [r, g, b, a] = c.to_array();
[f32::from(r) / 255.0, f32::from(g) / 255.0, f32::from(b) / 255.0, f32::from(a) / 255.0]
}
#[must_use]
pub fn label_half_extent(text_size: [f32; 2]) -> [f32; 2] {
[(text_size[0] + LABEL_PAD_PX[0]) * 0.5, (text_size[1] + LABEL_PAD_PX[1]) * 0.5]
}
#[cfg(test)]
mod tests {
use super::*;
fn params() -> LabelGridParams {
LabelGridParams::new([1280.0, 768.0], 2)
}
fn lbl(x: f32, y: f32, rank: u8, order: u32, name: &str) -> ScreenLabel {
ScreenLabel {
center: [x, y],
half: [40.0, 9.0],
priority: priority(rank, order),
name_hash: name_hash(name),
lod: 0,
blocker: false,
}
}
#[test]
fn priority_is_unique_and_rank_dominates_order() {
let mut seen = std::collections::HashSet::new();
for rank in [0u8, 1, 7, 200, BLOCKER_RANK] {
for order in 0..64u32 {
assert!(seen.insert(priority(rank, order)), "priority({rank},{order}) collided");
}
}
assert!(priority(5, 0x00FF_FFFE) > priority(4, 0));
assert!(priority(5, 0) > priority(5, 1));
assert!(priority(BLOCKER_RANK, 1000) > priority(BLOCKER_RANK - 1, 0));
}
#[test]
fn stacked_labels_leave_exactly_the_best_one() {
let p = params();
let ls = [
lbl(400.0, 300.0, 3, 10, "a"),
lbl(402.0, 301.0, 9, 11, "b"), lbl(398.0, 299.0, 5, 12, "c"),
lbl(401.0, 302.0, 1, 13, "d"),
];
let kept = resolve(&ls, &p);
assert_eq!(kept, vec![1], "one survivor, the top-ranked one — got {kept:?}");
}
#[test]
fn well_separated_labels_all_survive() {
let p = params();
let ls: Vec<ScreenLabel> = (0..6)
.map(|i| lbl(100.0 + i as f32 * 190.0, 80.0 + (i % 2) as f32 * 500.0, 5, i, &format!("n{i}")))
.collect();
let kept = resolve(&ls, &p);
assert_eq!(kept.len(), ls.len(), "nothing overlaps, so nothing may be culled — got {kept:?}");
}
#[test]
fn a_label_blocked_only_by_a_loser_still_draws() {
let p = params();
let a = lbl(200.0, 300.0, 9, 0, "A");
let b = lbl(250.0, 300.0, 5, 1, "B");
let c = lbl(325.0, 300.0, 1, 2, "C");
let kept = resolve(&[a, b, c], &p);
assert!(kept.contains(&0), "the top-ranked label draws");
assert!(!kept.contains(&1), "the label overlapping it does not");
assert!(
kept.contains(&2),
"the label that overlaps only the LOSER must still draw — got {kept:?}; \
[0] alone is the single-pass cascade this rule exists to avoid"
);
assert!(c.center[0] - c.half[0] < b.center[0] + b.half[0], "the fixture's C overlaps B");
assert!(c.center[0] - c.half[0] > a.center[0] + a.half[0], "…and does NOT overlap A");
}
#[test]
fn a_crowded_pane_still_letters_most_of_what_fits() {
let p = params();
let mut seed = 0x2545_F491_4F6C_DD1Du64;
let mut next = || {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
(seed >> 11) as f32 / (1u64 << 53) as f32
};
const STREETS: u32 = 40;
const WAYS: u32 = 6;
let names: Vec<String> = (0..STREETS).map(|i| format!("Strasse {i}")).collect();
let mut ls: Vec<ScreenLabel> = Vec::new();
for st in 0..STREETS {
let (x0, y0) = (next() * 1000.0, next() * 730.0);
let rank = (next() * 9.0) as u8;
for w in 0..WAYS {
ls.push(ScreenLabel {
center: [x0 + w as f32 * 60.0, y0 + w as f32 * 6.0],
half: label_half_extent([70.0, 13.0]),
priority: priority(rank, st * WAYS + w),
name_hash: name_hash(&names[st as usize]),
lod: 0,
blocker: false,
});
}
}
let kept = resolve(&ls, &p);
let distinct: std::collections::BTreeSet<u32> =
kept.iter().map(|&i| ls[i as usize].name_hash).collect();
assert!(
kept.len() >= 44,
"a crowded pane must letter a useful number of roads — got {} of {}. \
26 is the signature of zombie labels holding pixels they never draw on; \
~39 of too few resolution rounds",
kept.len(),
ls.len()
);
assert!(
distinct.len() >= 32,
"the repeat filter must not cost distinct names — {} distinct of {} lettered \
(40 exist). A low distinct count with a full label budget means one street's \
name is being printed where a different street's could have been",
distinct.len(),
kept.len()
);
assert!(kept.len() < ls.len() / 2, "and it must genuinely cull: {} of {}", kept.len(), ls.len());
for (ai, a) in kept.iter().enumerate() {
for b in &kept[ai + 1..] {
let (x, y) = (&ls[*a as usize], &ls[*b as usize]);
let overlap = (x.center[0] - y.center[0]).abs() < x.half[0] + y.half[0]
&& (x.center[1] - y.center[1]).abs() < x.half[1] + y.half[1];
assert!(!overlap, "labels {a} and {b} were both kept but their padded boxes overlap");
}
}
eprintln!(
"[label_grid] crowded pane: {} of {} lettered, {} distinct of 40, all pairwise clear",
kept.len(),
ls.len(),
distinct.len()
);
}
#[test]
fn same_name_repeats_are_thinned_but_distinct_names_are_not() {
let p = params();
let xs = [80.0f32, 260.0, 440.0, 620.0]; let same: Vec<ScreenLabel> =
xs.iter().enumerate().map(|(i, &x)| lbl(x, 300.0, 5, i as u32, "Feldkircher Strasse")).collect();
let distinct: Vec<ScreenLabel> =
xs.iter().enumerate().map(|(i, &x)| lbl(x, 300.0, 5, i as u32, &format!("Street {i}"))).collect();
let same_kept = resolve(&same, &p);
let distinct_kept = resolve(&distinct, &p);
assert_eq!(distinct_kept.len(), 4, "four different names at these spots all fit: {distinct_kept:?}");
assert!(
same_kept.len() < distinct_kept.len(),
"one street repeated must be thinned ({} kept) below four distinct names ({} kept)",
same_kept.len(),
distinct_kept.len()
);
assert!(!same_kept.is_empty(), "…but the street is still lettered at least once");
}
#[test]
fn a_blocker_reserves_pixels_and_is_never_drawn() {
let p = params();
let blocker = ScreenLabel {
center: [500.0, 400.0],
half: [22.0, 22.0],
priority: priority(BLOCKER_RANK, 0),
name_hash: name_hash("#pin"),
lod: 0,
blocker: true,
};
let on_top = lbl(505.0, 402.0, 9, 5, "Bahnhofstrasse");
let elsewhere = lbl(1000.0, 120.0, 9, 6, "Bahnhofstrasse2");
let kept = resolve(&[blocker, on_top, elsewhere], &p);
assert!(!kept.contains(&0), "a blocker must never be drawn");
assert!(!kept.contains(&1), "a label over a pin must be suppressed");
assert!(kept.contains(&2), "…and the same label away from the pin must survive");
}
#[test]
fn lod_and_offscreen_labels_are_not_candidates() {
let mut p = params();
p.lod = 1;
let mut city = lbl(400.0, 300.0, 5, 0, "city street");
city.lod = 2;
assert!(resolve(&[city], &p).is_empty(), "a city-tier label is not a candidate at region LOD");
let edge = lbl(20.0, 300.0, 5, 1, "edge");
let far_left = lbl(-9000.0, 300.0, 9, 2, "far"); let kept = resolve(&[edge, far_left], &p);
assert_eq!(kept, vec![0], "the off-screen label must claim nothing; the edge label survives — got {kept:?}");
}
#[test]
fn wire_layouts_match_the_shader_strides() {
assert_eq!(std::mem::size_of::<LabelCandidate>(), 48, "Candidate stride");
assert_eq!(std::mem::size_of::<GlyphSrc>(), 32, "GlyphSrc stride");
assert_eq!(std::mem::size_of::<LabelGlyphInstance>(), 48, "GlyphOut / vertex stride");
assert_eq!(std::mem::offset_of!(LabelGlyphInstance, color), 32);
assert_eq!(std::mem::offset_of!(LabelCandidate, priority), 16);
assert_eq!(std::mem::offset_of!(LabelCandidate, flags), 36);
assert_eq!(FLAG_SCREEN_SPACE | FLAG_BLOCKER, 3, "the two flag bits are distinct");
}
#[test]
fn projection_is_subtract_before_scale_per_axis() {
let frame = LabelFrame {
zoom: [8.0e7, 4.0e7], ref_pos: [0.031_25, 0.062_5],
screen_center: [640.0, 384.0],
viewport: [1280.0, 768.0],
lod: 2,
ink: [1.0; 4],
halo: [0.0, 0.0, 0.0, 1.0],
};
let (dx, dy) = (1.0e-5_f32, -2.0e-5_f32);
let merc =
LabelCandidate { pos: [frame.ref_pos[0] + dx, frame.ref_pos[1] + dy], ..Default::default() };
let got = frame.project(&merc);
let want = [640.0 + dx * 8.0e7, 384.0 + dy * 4.0e7];
assert!((got[0] - want[0]).abs() < 1.0, "x = (pos−ref)·zoom_x + centre: want {want:?} got {got:?}");
assert!((got[1] - want[1]).abs() < 1.0, "y uses zoom_Y, not zoom_x: want {want:?} got {got:?}");
assert!(got[0] != merc.pos[0] && got[1] != merc.pos[1], "the projection is not the identity");
assert!((got[0] - 640.0).abs() > 100.0, "the scale is applied: {} px from centre", got[0] - 640.0);
assert!(
(got[1] - (384.0 + dy * 8.0e7)).abs() > 100.0,
"y must NOT have used zoom_x ({} vs the swapped {})",
got[1],
384.0 + dy * 8.0e7
);
let mut shifted = frame;
shifted.ref_pos[0] += 1.0e-5;
assert!(
(shifted.project(&merc)[0] - got[0]).abs() > 100.0,
"moving `ref` must move the projected label"
);
let screen =
LabelCandidate { pos: [123.0, 456.0], flags: FLAG_SCREEN_SPACE, ..Default::default() };
assert_eq!(frame.project(&screen), [123.0, 456.0], "a screen-space candidate is not projected");
}
#[test]
fn half_extent_adds_the_pad_once() {
assert_eq!(label_half_extent([80.0, 14.0]), [45.0, 10.0]);
assert!(label_half_extent([0.0, 0.0])[0] > 0.0, "the pad alone is still a box");
}
#[test]
fn screen_labels_carry_the_rule_inputs_including_combined_flags() {
let frame = LabelFrame {
zoom: [1000.0, 1000.0],
ref_pos: [0.0, 0.0],
screen_center: [100.0, 100.0],
viewport: [1280.0, 768.0],
lod: 1,
ink: [1.0; 4],
halo: [0.0; 4],
};
let pin = LabelCandidate {
pos: [300.0, 200.0],
half_px: [12.0, 12.0],
priority: priority(BLOCKER_RANK, 0),
name_hash: name_hash("#pin"),
lod: 0,
flags: FLAG_SCREEN_SPACE | FLAG_BLOCKER,
..Default::default()
};
let out = screen_labels(&[pin], &frame);
assert_eq!(out[0].center, [300.0, 200.0]);
assert!(out[0].blocker, "a candidate carrying BOTH flags is still a blocker");
assert_eq!(out[0].priority, priority(BLOCKER_RANK, 0));
assert_eq!(out[0].name_hash, name_hash("#pin"));
}
#[test]
fn grid_regions_do_not_overlap() {
assert_eq!(GRID_CELLS, GRID_W * GRID_H);
assert_eq!(CLAIM_BASE, 0);
assert_eq!(OCC_BASE, CLAIM_BASE + GRID_CELLS);
assert_eq!(NAME_CLAIM_BASE, OCC_BASE + GRID_CELLS);
assert_eq!(NAME_WON_BASE, NAME_CLAIM_BASE + NAME_SLOTS);
assert_eq!(GRID_WORDS, NAME_WON_BASE + NAME_SLOTS);
assert!(repeat_slot(name_hash("x"), 0, 0) < NAME_SLOTS);
assert!(repeat_slot(name_hash("x"), -7, 12) < NAME_SLOTS);
assert_eq!(INSTANCES_PER_GLYPH, 5);
assert!(2.0 * REPEAT_CELL_PX <= MIN_REPEAT_PX, "3x3 over {REPEAT_CELL_PX} px cells must stay inside {MIN_REPEAT_PX} px");
assert!(LABEL_ROUNDS >= 2, "one round cannot resolve an A-blocks-B-blocks-C chain");
}
}