use serde::{Deserialize, Serialize};
pub use hecs::Entity;
pub use rapier2d::na::Vector2;
pub use rapier2d::na::Vector3;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Rectangle {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl Rectangle {
pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
Self {
x,
y,
width,
height,
}
}
pub fn contains_point(&self, x: f32, y: f32) -> bool {
x >= self.x && y >= self.y && x <= self.x + self.width && y <= self.y + self.height
}
pub fn from_point_and_size(
point: impl Into<crate::Vector2<f32>>,
size: impl Into<crate::Vector2<f32>>,
) -> Self {
let point = point.into();
let size = size.into();
Self {
x: point.x,
y: point.y,
width: size.x,
height: size.y,
}
}
pub fn zeroed() -> Self {
Rectangle::new(0.0, 0.0, 0.0, 0.0)
}
pub fn is_zero_sized(self) -> bool {
self.width == 0.0 && self.height == 0.0
}
#[inline]
pub fn left(&self) -> f32 {
self.x
}
#[inline]
pub fn right(&self) -> f32 {
self.x + self.width
}
#[inline]
pub fn bottom(&self) -> f32 {
self.y
}
#[inline]
pub fn top(&self) -> f32 {
self.y + self.height
}
#[inline]
pub fn bottom_left(&self) -> Vector2<f32> {
Vector2::new(self.left(), self.bottom())
}
#[inline]
pub fn size(&self) -> crate::Vector2<f32> {
Vector2::new(self.width, self.height)
}
#[inline]
pub fn center(&self) -> crate::Vector2<f32> {
self.bottom_left() + self.size() / 2.0
}
pub fn intersects_with(&self, other: &Rectangle) -> 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
}
}
#[cfg(test)]
pub mod tests {
use crate::Rectangle;
#[test]
fn rect_contains_point() {
let rect = Rectangle::new(10.0, 10.0, 5.0, 5.0);
assert!(rect.contains_point(10.0, 10.0));
assert!(rect.contains_point(15.0, 15.0));
assert!(rect.contains_point(12.0, 12.0));
assert!(!rect.contains_point(16.0, 12.0));
assert!(!rect.contains_point(0.0, 12.0));
}
#[test]
fn exact_overlap_intersects() {
let rect_a = Rectangle::new(0.0, 0.0, 10.0, 10.0);
let rect_b = rect_a.clone();
assert!(rect_a.intersects_with(&rect_b));
assert!(rect_b.intersects_with(&rect_a));
}
#[test]
fn rect_intersects_halfway() {
let rect_a = Rectangle::new(0.0, 0.0, 10.0, 10.0);
let mut rect_b = rect_a.clone();
rect_b.x = 5.0;
rect_b.y = 5.0;
assert!(rect_a.intersects_with(&rect_b));
assert!(rect_b.intersects_with(&rect_a));
}
#[test]
fn rect_intersects_halfway_negative() {
let rect_a = Rectangle::new(0.0, 0.0, 10.0, 10.0);
let mut rect_b = rect_a.clone();
rect_b.x = -5.0;
rect_b.y = -5.0;
assert!(rect_a.intersects_with(&rect_b));
assert!(rect_b.intersects_with(&rect_a));
}
}