Skip to main content

goud_engine/core/math/
rect.rs

1//! 2D rectangle type with FFI-safe memory layout.
2
3use super::vec2::Vec2;
4
5/// A 2D rectangle with FFI-safe memory layout.
6///
7/// Defined by position (x, y) and size (width, height).
8/// The position represents the top-left corner in screen space.
9#[repr(C)]
10#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize)]
11pub struct Rect {
12    /// The x-coordinate of the top-left corner of the rectangle.
13    pub x: f32,
14    /// The y-coordinate of the top-left corner of the rectangle.
15    pub y: f32,
16    /// The width of the rectangle.
17    pub width: f32,
18    /// The height of the rectangle.
19    pub height: f32,
20}
21
22impl Rect {
23    /// Creates a new rectangle from position and size.
24    #[inline]
25    pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
26        Self {
27            x,
28            y,
29            width,
30            height,
31        }
32    }
33
34    /// Creates a rectangle from min and max points.
35    #[inline]
36    pub fn from_min_max(min: Vec2, max: Vec2) -> Self {
37        Self {
38            x: min.x,
39            y: min.y,
40            width: max.x - min.x,
41            height: max.y - min.y,
42        }
43    }
44
45    /// Creates a unit rectangle (0, 0, 1, 1).
46    #[inline]
47    pub const fn unit() -> Self {
48        Self {
49            x: 0.0,
50            y: 0.0,
51            width: 1.0,
52            height: 1.0,
53        }
54    }
55
56    /// Returns the minimum point (top-left corner).
57    #[inline]
58    pub const fn min(&self) -> Vec2 {
59        Vec2 {
60            x: self.x,
61            y: self.y,
62        }
63    }
64
65    /// Returns the maximum point (bottom-right corner).
66    #[inline]
67    pub fn max(&self) -> Vec2 {
68        Vec2 {
69            x: self.x + self.width,
70            y: self.y + self.height,
71        }
72    }
73
74    /// Returns the center point of the rectangle.
75    #[inline]
76    pub fn center(&self) -> Vec2 {
77        Vec2 {
78            x: self.x + self.width * 0.5,
79            y: self.y + self.height * 0.5,
80        }
81    }
82
83    /// Returns the size as a Vec2.
84    #[inline]
85    pub const fn size(&self) -> Vec2 {
86        Vec2 {
87            x: self.width,
88            y: self.height,
89        }
90    }
91
92    /// Returns the area of the rectangle.
93    #[inline]
94    pub fn area(&self) -> f32 {
95        self.width * self.height
96    }
97
98    /// Checks if the rectangle contains a point.
99    #[inline]
100    pub fn contains(&self, point: Vec2) -> bool {
101        point.x >= self.x
102            && point.x < self.x + self.width
103            && point.y >= self.y
104            && point.y < self.y + self.height
105    }
106
107    /// Checks if this rectangle intersects with another.
108    #[inline]
109    pub fn intersects(&self, other: &Rect) -> bool {
110        self.x < other.x + other.width
111            && self.x + self.width > other.x
112            && self.y < other.y + other.height
113            && self.y + self.height > other.y
114    }
115
116    /// Returns the intersection of two rectangles, or None if they don't intersect.
117    pub fn intersection(&self, other: &Rect) -> Option<Rect> {
118        let x = self.x.max(other.x);
119        let y = self.y.max(other.y);
120        let max_x = (self.x + self.width).min(other.x + other.width);
121        let max_y = (self.y + self.height).min(other.y + other.height);
122
123        if x < max_x && y < max_y {
124            Some(Rect {
125                x,
126                y,
127                width: max_x - x,
128                height: max_y - y,
129            })
130        } else {
131            None
132        }
133    }
134}