use bevy::math::{Rect, Vec2};
use pyo3::{exceptions::PyValueError, prelude::*};
use crate::vec2::PyVec2;
#[pyclass(name = "Rect", frozen)]
#[derive(Debug, Clone)]
pub struct PyRect {
#[pyo3(get)]
min: PyVec2,
#[pyo3(get)]
max: PyVec2,
}
#[pymethods]
impl PyRect {
#[new]
pub fn new(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
let rect = Rect::new(x0, y0, x1, y1);
Self {
min: rect.min.into(),
max: rect.max.into(),
}
}
#[staticmethod]
pub fn from_corners(p0: PyVec2, p1: PyVec2) -> Self {
let rect = Rect::from_corners(p0.into(), p1.into());
Self {
min: rect.min.into(),
max: rect.max.into(),
}
}
#[staticmethod]
pub fn from_center_size(origin: PyVec2, size: PyVec2) -> Self {
let rect = Rect::from_center_size(origin.into(), size.into());
Self {
min: rect.min.into(),
max: rect.max.into(),
}
}
#[staticmethod]
pub fn from_center_half_size(origin: PyVec2, half_size: PyVec2) -> Self {
let rect = Rect::from_center_half_size(origin.into(), half_size.into());
Self {
min: rect.min.into(),
max: rect.max.into(),
}
}
pub fn center(&self) -> PyVec2 {
self.to_bevy().center().into()
}
pub fn size(&self) -> PyVec2 {
self.to_bevy().size().into()
}
pub fn half_size(&self) -> PyVec2 {
self.to_bevy().half_size().into()
}
pub fn width(&self) -> f32 {
self.to_bevy().width()
}
pub fn height(&self) -> f32 {
self.to_bevy().height()
}
pub fn contains(&self, point: PyVec2) -> bool {
self.to_bevy().contains(point.into())
}
pub fn is_empty(&self) -> bool {
self.to_bevy().is_empty()
}
pub fn intersect(&self, other: &PyRect) -> PyResult<PyRect> {
let result = self.to_bevy().intersect(other.to_bevy());
if result.is_empty() {
Err(PyValueError::new_err("Rectangles do not intersect"))
} else {
Ok(Self {
min: result.min.into(),
max: result.max.into(),
})
}
}
pub fn union(&self, other: &PyRect) -> PyRect {
let result = self.to_bevy().union(other.to_bevy());
Self {
min: result.min.into(),
max: result.max.into(),
}
}
pub fn union_point(&self, point: PyVec2) -> PyRect {
let result = self.to_bevy().union_point(point.into());
Self {
min: result.min.into(),
max: result.max.into(),
}
}
pub fn inflate(&self, expansion: f32) -> PyRect {
let result = self.to_bevy().inflate(expansion);
Self {
min: result.min.into(),
max: result.max.into(),
}
}
pub fn __repr__(&self) -> String {
let min_vec: Vec2 = (&self.min).into();
let max_vec: Vec2 = (&self.max).into();
format!(
"Rect(min=Vec2({}, {}), max=Vec2({}, {}))",
min_vec.x, min_vec.y, max_vec.x, max_vec.y
)
}
}
impl PartialEq for PyRect {
fn eq(&self, other: &Self) -> bool {
self.to_bevy() == other.to_bevy()
}
}
impl PyRect {
fn to_bevy(&self) -> Rect {
Rect {
min: (&self.min).into(),
max: (&self.max).into(),
}
}
}
impl From<Rect> for PyRect {
fn from(rect: Rect) -> Self {
Self {
min: rect.min.into(),
max: rect.max.into(),
}
}
}
impl From<PyRect> for Rect {
fn from(rect: PyRect) -> Self {
Rect {
min: rect.min.into(),
max: rect.max.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rect_creation() {
let rect = PyRect::new(0.0, 0.0, 10.0, 20.0);
assert_eq!(rect.width(), 10.0);
assert_eq!(rect.height(), 20.0);
}
#[test]
fn test_rect_from_corners() {
let p0 = PyVec2::new(0.0, 0.0);
let p1 = PyVec2::new(10.0, 20.0);
let rect = PyRect::from_corners(p0, p1);
assert_eq!(rect.width(), 10.0);
assert_eq!(rect.height(), 20.0);
}
#[test]
fn test_rect_from_center_size() {
let center = PyVec2::new(5.0, 10.0);
let size = PyVec2::new(10.0, 20.0);
let rect = PyRect::from_center_size(center.clone(), size.clone());
assert_eq!(rect.center(), center);
assert_eq!(rect.size(), size);
}
#[test]
fn test_rect_contains() {
let rect = PyRect::new(0.0, 0.0, 10.0, 20.0);
assert!(rect.contains(PyVec2::new(5.0, 10.0)));
assert!(!rect.contains(PyVec2::new(15.0, 10.0)));
}
#[test]
fn test_rect_intersect() {
let rect1 = PyRect::new(0.0, 0.0, 10.0, 10.0);
let rect2 = PyRect::new(5.0, 5.0, 15.0, 15.0);
let intersection = rect1.intersect(&rect2).unwrap();
assert_eq!(intersection.width(), 5.0);
assert_eq!(intersection.height(), 5.0);
}
#[test]
fn test_rect_union() {
let rect1 = PyRect::new(0.0, 0.0, 10.0, 10.0);
let rect2 = PyRect::new(5.0, 5.0, 15.0, 15.0);
let union = rect1.union(&rect2);
let min_vec: Vec2 = (&union.min).into();
let max_vec: Vec2 = (&union.max).into();
assert_eq!(min_vec.x, 0.0);
assert_eq!(min_vec.y, 0.0);
assert_eq!(max_vec.x, 15.0);
assert_eq!(max_vec.y, 15.0);
}
}