mod resolver;
pub use resolver::{CollisionResolver, SmartCollisionResolver};
pub trait CollisionDetector: Send + Sync {
fn check_collision(&self, bbox: &BoundingBox, existing: &[BoundingBox]) -> bool;
fn find_free_position(
&self,
bbox: &BoundingBox,
existing: &[BoundingBox],
bounds: &BoundingBox,
) -> Option<(f32, f32)>;
}
#[derive(Debug, Clone, Copy)]
pub struct BoundingBox {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl BoundingBox {
pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
Self {
x,
y,
width,
height,
}
}
pub fn intersects(&self, other: &BoundingBox) -> bool {
self.x < other.x + other.width
&& self.x + self.width > other.x
&& self.y < other.y + other.height
&& self.y + self.height > other.y
}
pub fn overlap_area(&self, other: &BoundingBox) -> f32 {
let x_overlap = (self.x + self.width).min(other.x + other.width) - self.x.max(other.x);
let y_overlap = (self.y + self.height).min(other.y + other.height) - self.y.max(other.y);
if x_overlap > 0.0 && y_overlap > 0.0 {
x_overlap * y_overlap
} else {
0.0
}
}
pub fn expand(&self, margin: f32) -> Self {
Self {
x: self.x - margin,
y: self.y - margin,
width: self.width + margin * 2.0,
height: self.height + margin * 2.0,
}
}
pub fn center(&self) -> (f32, f32) {
(self.x + self.width / 2.0, self.y + self.height / 2.0)
}
}
#[derive(Debug, Clone)]
pub struct PositionedEvent {
pub bbox: BoundingBox,
pub layer: i32,
pub margin_v: i32,
pub margin_l: i32,
pub margin_r: i32,
pub alignment: u8,
pub priority: i32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bounding_box_intersection() {
let box1 = BoundingBox::new(0.0, 0.0, 100.0, 50.0);
let box2 = BoundingBox::new(50.0, 25.0, 100.0, 50.0);
let box3 = BoundingBox::new(200.0, 200.0, 50.0, 50.0);
assert!(box1.intersects(&box2));
assert!(box2.intersects(&box1));
assert!(!box1.intersects(&box3));
assert!(!box3.intersects(&box1));
}
}