use glam::{UVec2, Vec2};
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct Pose2 {
pub position: Vec2,
pub yaw: f32,
}
impl Pose2 {
pub fn new(position: Vec2, yaw: f32) -> Self {
Self { position, yaw }
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Bounds {
pub min: Vec2,
pub max: Vec2,
}
impl Bounds {
pub fn empty() -> Self {
Self {
min: Vec2::new(f32::INFINITY, f32::INFINITY),
max: Vec2::new(f32::NEG_INFINITY, f32::NEG_INFINITY),
}
}
pub fn is_empty(&self) -> bool {
self.min.x >= self.max.x || self.min.y >= self.max.y
}
pub fn expand_to_include(&mut self, p: Vec2) {
self.min.x = self.min.x.min(p.x);
self.min.y = self.min.y.min(p.y);
self.max.x = self.max.x.max(p.x);
self.max.y = self.max.y.max(p.y);
}
pub fn expand_by(&mut self, margin: f32) {
self.min.x -= margin;
self.min.y -= margin;
self.max.x += margin;
self.max.y += margin;
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CellRegion {
pub min: UVec2,
pub max: UVec2,
}
impl CellRegion {
pub fn new(min: UVec2, max: UVec2) -> Self {
Self { min, max }
}
#[inline]
pub fn contains(&self, pos: UVec2) -> bool {
pos.x >= self.min.x && pos.x < self.max.x && pos.y >= self.min.y && pos.y < self.max.y
}
}
#[derive(Debug, Clone, Default)]
pub struct Footprint {
pub points: Vec<Vec2>,
}
impl Footprint {
pub fn rectangle(length: f32, width: f32) -> Self {
let half_length = length / 2.0;
let half_width = width / 2.0;
Self {
points: vec![
Vec2::new(half_length, half_width),
Vec2::new(half_length, -half_width),
Vec2::new(-half_length, -half_width),
Vec2::new(-half_length, half_width),
],
}
}
pub fn transform(&self, pose: Pose2) -> Vec<Vec2> {
let cos_yaw = pose.yaw.cos();
let sin_yaw = pose.yaw.sin();
self.points
.iter()
.map(|p| {
let rotated =
Vec2::new(p.x * cos_yaw - p.y * sin_yaw, p.x * sin_yaw + p.y * cos_yaw);
pose.position + rotated
})
.collect()
}
pub fn is_valid(&self) -> bool {
self.points.len() >= 3
}
}