use loam::Id;
use pointy::{BBox, Bounded, Float, Pt};
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
pub const M_NODE: usize = 6;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Entry<F>
where
F: Float,
{
id: Id,
bbox: BBox<F>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Node<F>
where
F: Float,
{
children: [Entry<F>; M_NODE],
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Root<F>
where
F: Float,
{
node: Node<F>,
n_elem: usize,
}
impl<F> Default for Entry<F>
where
F: Float,
{
fn default() -> Self {
let id = Id::new(0);
let pt = Pt::new(F::zero(), F::zero());
let bbox = BBox::new([pt, pt]);
Self { id, bbox }
}
}
impl<F> Entry<F>
where
F: Float,
{
pub fn new(id: Id, bbox: BBox<F>) -> Self {
Self { id, bbox }
}
pub fn id(&self) -> Id {
self.id
}
pub fn bbox(&self) -> BBox<F> {
self.bbox
}
pub fn compare_x(&self, rhs: &Self) -> Ordering {
self.bbox
.x_mid()
.partial_cmp(&rhs.bbox.x_mid())
.unwrap_or(Ordering::Equal)
}
pub fn compare_y(&self, rhs: &Self) -> Ordering {
self.bbox
.y_mid()
.partial_cmp(&rhs.bbox.y_mid())
.unwrap_or(Ordering::Equal)
}
}
impl<F> Bounded<F> for &Entry<F>
where
F: Float,
{
fn bounded_by(self, bbox: BBox<F>) -> bool {
self.id.is_valid() && self.bbox.bounded_by(bbox)
}
}
impl<F> Node<F>
where
F: Float,
{
pub fn height(n_elem: usize) -> usize {
let mut capacity = M_NODE;
for height in 1.. {
if capacity >= n_elem {
return height;
}
match capacity.checked_mul(M_NODE) {
Some(c) => capacity = c,
None => break,
}
}
panic!("Incalculable height!")
}
pub fn root_groups(n_elem: usize) -> usize {
let height = Node::<F>::height(n_elem);
let n_subtree = M_NODE.pow(height as u32 - 1);
let n_groups = (n_elem as f32 / n_subtree as f32).ceil();
n_groups.sqrt().ceil() as usize
}
pub fn partition_sz(height: usize) -> usize {
M_NODE.pow(height as u32 - 1)
}
pub fn new() -> Self {
let children = [Entry::default(); M_NODE];
Node { children }
}
pub fn push(&mut self, id: Id, bbox: BBox<F>) {
for i in 0..M_NODE {
if !self.children[i].id.is_valid() {
self.children[i] = Entry::new(id, bbox);
return;
}
}
panic!("Too many children: {id:?}");
}
pub fn bbox(&self) -> BBox<F> {
let mut bbox = BBox::default();
for child in &self.children {
if child.id.is_valid() {
bbox.extend(child.bbox);
}
}
bbox
}
pub fn into_entries(self) -> [Entry<F>; M_NODE] {
self.children
}
}
impl<F> Root<F>
where
F: Float,
{
pub fn new(node: Node<F>, n_elem: usize) -> Self {
Self { node, n_elem }
}
pub fn n_elem(&self) -> usize {
self.n_elem
}
pub fn into_node(self) -> Node<F> {
self.node
}
}