pub const FAN_OUT: usize = 8;
pub const OVERFLOW_FLOOR: usize = 64;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rect {
pub min: [f64; 2],
pub max: [f64; 2],
}
impl Rect {
pub fn new(a: [f64; 2], b: [f64; 2]) -> Option<Self> {
if !a.iter().chain(b.iter()).all(|v| v.is_finite()) {
return None;
}
Some(Self {
min: [a[0].min(b[0]), a[1].min(b[1])],
max: [a[0].max(b[0]), a[1].max(b[1])],
})
}
pub fn point(p: [f64; 2]) -> Option<Self> {
Self::new(p, p)
}
pub fn of_points(points: &[[f64; 2]]) -> Option<Self> {
let first = *points.first()?;
let mut rect = Self::point(first)?;
for p in &points[1..] {
rect = rect.union(&Self::point(*p)?);
}
Some(rect)
}
pub fn grown(&self, margin: f64) -> Self {
let mut r = *self;
for axis in 0..2 {
r.min[axis] -= margin;
r.max[axis] += margin;
if r.min[axis] > r.max[axis] {
let mid = (self.min[axis] + self.max[axis]) / 2.0;
r.min[axis] = mid;
r.max[axis] = mid;
}
}
r
}
pub fn union(&self, other: &Self) -> Self {
Self {
min: [self.min[0].min(other.min[0]), self.min[1].min(other.min[1])],
max: [self.max[0].max(other.max[0]), self.max[1].max(other.max[1])],
}
}
pub fn intersects(&self, other: &Self) -> bool {
self.min[0] <= other.max[0]
&& other.min[0] <= self.max[0]
&& self.min[1] <= other.max[1]
&& other.min[1] <= self.max[1]
}
fn centre(&self, axis: usize) -> f64 {
(self.min[axis] + self.max[axis]) / 2.0
}
}
#[derive(Clone, Debug)]
struct Node {
rect: Rect,
kids: Vec<usize>,
leaf: bool,
}
#[derive(Clone, Debug)]
pub struct Index<T> {
entries: Vec<(Rect, T)>,
built: usize,
nodes: Vec<Node>,
root: Option<usize>,
rebuilds: usize,
}
impl<T> Default for Index<T> {
fn default() -> Self {
Self {
entries: Vec::new(),
built: 0,
nodes: Vec::new(),
root: None,
rebuilds: 0,
}
}
}
impl<T> Index<T> {
pub fn new() -> Self {
Self::default()
}
pub fn build(items: Vec<(Rect, T)>) -> Self {
let mut index = Self {
entries: items,
..Self::default()
};
index.rebuild();
index
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn overflow(&self) -> usize {
self.entries.len() - self.built
}
pub fn rebuilds(&self) -> usize {
self.rebuilds
}
pub fn needs_rebuild(&self) -> bool {
self.overflow() > OVERFLOW_FLOOR && self.overflow() * 4 > self.built
}
pub fn insert(&mut self, rect: Rect, item: T) {
self.entries.push((rect, item));
if self.needs_rebuild() {
self.rebuild();
}
}
pub fn rebuild(&mut self) {
self.rebuilds += 1;
self.built = self.entries.len();
self.nodes.clear();
self.root = None;
if self.entries.is_empty() {
return;
}
let rects: Vec<Rect> = self.entries.iter().map(|(r, _)| *r).collect();
let mut level: Vec<usize> = (0..rects.len()).collect();
let mut leaf = true;
let mut rects_of_level = rects;
loop {
let order = tile(&rects_of_level, FAN_OUT);
let mut next_nodes: Vec<usize> = Vec::new();
let mut next_rects: Vec<Rect> = Vec::new();
for group in order.chunks(FAN_OUT) {
let kids: Vec<usize> = group.iter().map(|&i| level[i]).collect();
let rect = group
.iter()
.map(|&i| rects_of_level[i])
.reduce(|a, b| a.union(&b))
.expect("non-empty chunk");
next_nodes.push(self.nodes.len());
next_rects.push(rect);
self.nodes.push(Node { rect, kids, leaf });
}
if next_nodes.len() == 1 {
self.root = Some(next_nodes[0]);
return;
}
level = next_nodes;
rects_of_level = next_rects;
leaf = false;
}
}
pub fn query(&self, window: &Rect) -> Vec<&T> {
let mut out = Vec::new();
self.visit(window, &mut |item| out.push(item));
out
}
pub fn visit<'a>(&'a self, window: &Rect, found: &mut dyn FnMut(&'a T)) {
if let Some(root) = self.root {
let mut stack = vec![root];
while let Some(at) = stack.pop() {
let node = &self.nodes[at];
if !node.rect.intersects(window) {
continue;
}
if node.leaf {
for &k in &node.kids {
let (rect, item) = &self.entries[k];
if rect.intersects(window) {
found(item);
}
}
} else {
stack.extend(node.kids.iter().copied());
}
}
}
for (rect, item) in &self.entries[self.built..] {
if rect.intersects(window) {
found(item);
}
}
}
}
fn tile(rects: &[Rect], fan: usize) -> Vec<usize> {
let n = rects.len();
let mut order: Vec<usize> = (0..n).collect();
order.sort_by(|&a, &b| rects[a].centre(0).total_cmp(&rects[b].centre(0)));
let nodes = n.div_ceil(fan);
let slices = (nodes as f64).sqrt().ceil() as usize;
let per_slice = slices.max(1) * fan;
for slice in order.chunks_mut(per_slice) {
slice.sort_by(|&a, &b| rects[a].centre(1).total_cmp(&rects[b].centre(1)));
}
order
}