use crate::{
math::Rect,
num_traits::Zero,
pool::{Handle, Pool},
};
use nalgebra::Scalar;
use num_traits::NumAssign;
struct RectPackNode<T>
where
T: NumAssign + Scalar + PartialOrd + Copy,
{
filled: bool,
split: bool,
bounds: Rect<T>,
left: Handle<RectPackNode<T>>,
right: Handle<RectPackNode<T>>,
}
impl<T> RectPackNode<T>
where
T: NumAssign + Scalar + PartialOrd + Copy,
{
fn new(bounds: Rect<T>) -> Self {
Self {
bounds,
filled: false,
split: false,
left: Handle::NONE,
right: Handle::NONE,
}
}
}
pub struct RectPacker<T>
where
T: NumAssign + Scalar + PartialOrd + Copy,
{
nodes: Pool<RectPackNode<T>>,
root: Handle<RectPackNode<T>>,
width: T,
height: T,
unvisited: Vec<Handle<RectPackNode<T>>>,
}
impl<T> RectPacker<T>
where
T: NumAssign + Scalar + PartialOrd + Copy,
{
pub fn new(w: T, h: T) -> Self {
let mut nodes = Pool::new();
let root = nodes.spawn(RectPackNode::new(Rect::new(
Zero::zero(),
Zero::zero(),
w,
h,
)));
Self {
nodes,
root,
width: w,
height: h,
unvisited: Default::default(),
}
}
pub fn clear(&mut self) {
self.nodes.clear();
self.unvisited.clear();
self.root = self.nodes.spawn(RectPackNode::new(Rect::new(
Zero::zero(),
Zero::zero(),
self.width,
self.height,
)));
}
pub fn find_free(&mut self, w: T, h: T) -> Option<Rect<T>> {
if self.unvisited.is_empty() {
self.unvisited.push(self.root);
}
while let Some(node_handle) = self.unvisited.pop() {
let node = self.nodes.borrow_mut(node_handle);
if node.split {
self.unvisited.push(node.right);
self.unvisited.push(node.left);
} else if !node.filled && node.bounds.w() >= w && node.bounds.h() >= h {
if node.bounds.w() == w && node.bounds.h() == h {
node.filled = true;
return Some(node.bounds);
}
node.split = true;
let (left_bounds, right_bounds) = if node.bounds.w() - w > node.bounds.h() - h {
(
Rect::new(node.bounds.x(), node.bounds.y(), w, node.bounds.h()),
Rect::new(
node.bounds.x() + w,
node.bounds.y(),
node.bounds.w() - w,
node.bounds.h(),
),
)
} else {
(
Rect::new(node.bounds.x(), node.bounds.y(), node.bounds.w(), h),
Rect::new(
node.bounds.x(),
node.bounds.y() + h,
node.bounds.w(),
node.bounds.h() - h,
),
)
};
let left = self.nodes.spawn(RectPackNode::new(left_bounds));
let right = self.nodes.spawn(RectPackNode::new(right_bounds));
let node = self.nodes.borrow_mut(node_handle);
node.left = left;
node.right = right;
self.unvisited.push(left);
}
}
None
}
}