use alloc::vec::Vec;
const MIN_ELEMENTS: usize = 16;
const MAX_LEVEL: usize = 100;
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct Bounds {
pub min: [f64; 2],
pub max: [f64; 2],
}
impl Bounds {
pub(crate) fn around(first: [f64; 2], second: [f64; 2]) -> Self {
Self {
min: [first[0].min(second[0]), first[1].min(second[1])],
max: [first[0].max(second[0]), first[1].max(second[1])],
}
}
pub(crate) fn expand(&mut self, other: &Self) {
for axis in 0..2 {
self.min[axis] = self.min[axis].min(other.min[axis]);
self.max[axis] = self.max[axis].max(other.max[axis]);
}
}
fn overlaps(&self, other: &Self) -> bool {
(0..2).all(|axis| self.max[axis] >= other.min[axis] && other.max[axis] >= self.min[axis])
}
#[expect(
clippy::manual_midpoint,
reason = "C++ divides the interval as `(mi + ma) / 2`, and where the two disagree the split lands on a different coordinate and the walk visits a different order"
)]
fn halves(&self, axis: usize) -> (Self, Self) {
let middle = (self.min[axis] + self.max[axis]) / 2.0;
let mut lower = *self;
let mut upper = *self;
lower.max[axis] = middle;
upper.min[axis] = middle;
(lower, upper)
}
}
fn enclosing(bounds: &[Bounds], of: &[usize]) -> Bounds {
let mut total = bounds[of[0]];
for &index in &of[1..] {
total.expand(&bounds[index]);
}
total
}
fn split(
bounds: &[Bounds],
of: &[usize],
lower_box: &Bounds,
upper_box: &Bounds,
) -> [Vec<usize>; 3] {
let mut lower = Vec::new();
let mut upper = Vec::new();
let mut exceeding = Vec::new();
for &index in of {
let in_lower = lower_box.overlaps(&bounds[index]);
let in_upper = upper_box.overlaps(&bounds[index]);
match (in_lower, in_upper) {
(true, true) => exceeding.push(index),
(true, false) => lower.push(index),
(false, true) => upper.push(index),
(false, false) => {}
}
}
[lower, upper, exceeding]
}
fn deep_enough(of: &[usize], level: usize) -> bool {
of.len() >= MIN_ELEMENTS && level < MAX_LEVEL
}
struct Walk<'a> {
first: &'a [Bounds],
second: &'a [Bounds],
visited: Vec<(usize, usize)>,
}
impl Walk<'_> {
fn pair_up(&mut self, ones: &[usize], twos: &[usize]) {
for &one in ones {
for &two in twos {
self.visited.push((one, two));
}
}
}
fn narrow(&mut self, box_: &Bounds, ones: &[usize], twos: &[usize], level: usize, axis: usize) {
if deep_enough(ones, level) && deep_enough(twos, level) {
self.descend(box_, ones, twos, level + 1, 1 - axis);
} else {
self.pair_up(ones, twos);
}
}
fn against_both_halves(
&mut self,
straddlers: &[usize],
halves: (&[usize], &[usize]),
straddlers_lead: bool,
level: usize,
axis: usize,
) {
let (lower, upper) = halves;
let bounds = if straddlers_lead {
self.first
} else {
self.second
};
if deep_enough(lower, level) && deep_enough(upper, level) && deep_enough(straddlers, level)
{
let box_ = enclosing(bounds, straddlers);
let (level, axis) = (level + 1, 1 - axis);
if straddlers_lead {
self.descend(&box_, straddlers, lower, level, axis);
self.descend(&box_, straddlers, upper, level, axis);
} else {
self.descend(&box_, lower, straddlers, level, axis);
self.descend(&box_, upper, straddlers, level, axis);
}
} else if straddlers_lead {
self.pair_up(straddlers, lower);
self.pair_up(straddlers, upper);
} else {
self.pair_up(lower, straddlers);
self.pair_up(upper, straddlers);
}
}
fn descend(
&mut self,
box_: &Bounds,
ones: &[usize],
twos: &[usize],
level: usize,
axis: usize,
) {
let (lower_box, upper_box) = box_.halves(axis);
let [lower1, upper1, exceeding1] = split(self.first, ones, &lower_box, &upper_box);
let [lower2, upper2, exceeding2] = split(self.second, twos, &lower_box, &upper_box);
if !exceeding1.is_empty() {
let mut box_ = enclosing(self.first, &exceeding1);
if !exceeding2.is_empty() {
box_.expand(&enclosing(self.second, &exceeding2));
}
self.narrow(&box_, &exceeding1, &exceeding2, level, axis);
self.against_both_halves(&exceeding1, (&lower2, &upper2), true, level, axis);
}
if !exceeding2.is_empty() {
self.against_both_halves(&exceeding2, (&lower1, &upper1), false, level, axis);
}
self.narrow(&lower_box, &lower1, &lower2, level, axis);
self.narrow(&upper_box, &upper1, &upper2, level, axis);
}
}
fn visit_order(first: &[Bounds], second: &[Bounds]) -> Vec<(usize, usize)> {
if first.is_empty() || second.is_empty() {
return Vec::new();
}
let ones: Vec<usize> = (0..first.len()).collect();
let twos: Vec<usize> = (0..second.len()).collect();
let mut walk = Walk {
first,
second,
visited: Vec::new(),
};
if first.len() > MIN_ELEMENTS && second.len() > MIN_ELEMENTS {
let mut total = enclosing(first, &ones);
total.expand(&enclosing(second, &twos));
walk.descend(&total, &ones, &twos, 0, 0);
} else {
walk.pair_up(&ones, &twos);
}
walk.visited
}
pub(crate) struct VisitRank(Vec<((usize, usize), usize)>);
impl VisitRank {
pub(crate) fn of(first: &[Bounds], second: &[Bounds]) -> Self {
let mut ranked: Vec<((usize, usize), usize)> = visit_order(first, second)
.into_iter()
.enumerate()
.map(|(rank, pair)| (pair, rank))
.collect();
ranked.sort_unstable();
ranked.dedup_by_key(|(pair, _)| *pair);
Self(ranked)
}
pub(crate) fn rank(&self, first: usize, second: usize) -> usize {
self.0
.binary_search_by_key(&(first, second), |&(pair, _)| pair)
.map_or(usize::MAX, |at| self.0[at].1)
}
}