Skip to main content

lotus_shared/
math.rs

1//! Mathematik-Hilfen und Re-Exports von `glam`-Vektortypen.
2//!
3//! Math helpers and re-exports of `glam` vector types.
4
5use serde::{Deserialize, Serialize};
6
7pub use glam::*;
8
9/// Achsenausgerichtetes Rechteck auf einem ganzzahligen Pixelraster.
10///
11/// Axis-aligned rectangle on an integer pixel grid.
12#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct Rectangle {
14    start: UVec2,
15    end: UVec2,
16}
17
18impl Rectangle {
19    /// Erstellt ein Rechteck aus inklusive Start- und Endecke.
20    ///
21    /// Creates a rectangle from inclusive start and end corners.
22    pub fn new(start: UVec2, end: UVec2) -> Self {
23        assert!(start.x <= end.x);
24        assert!(start.y <= end.y);
25
26        Self { start, end }
27    }
28
29    /// Erstellt ein Rechteck aus Startecke und Größe.
30    ///
31    /// Creates a rectangle from a start corner and a size.
32    pub fn from_size(start: UVec2, size: UVec2) -> Self {
33        Self::new(start, start + size)
34    }
35
36    /// Gibt die inklusive Startecke zurück.
37    ///
38    /// Returns the inclusive start corner.
39    #[inline(always)]
40    pub fn start(&self) -> UVec2 {
41        self.start
42    }
43
44    /// Gibt die inklusive Endecke zurück.
45    ///
46    /// Returns the inclusive end corner.
47    #[inline(always)]
48    pub fn end(&self) -> UVec2 {
49        self.end
50    }
51
52    /// Gibt die Breite in Pixeln zurück.
53    ///
54    /// Returns the width in pixels.
55    #[inline(always)]
56    pub fn width(&self) -> u32 {
57        self.end.x - self.start.x
58    }
59
60    /// Gibt die Höhe in Pixeln zurück.
61    ///
62    /// Returns the height in pixels.
63    #[inline(always)]
64    pub fn height(&self) -> u32 {
65        self.end.y - self.start.y
66    }
67
68    /// Gibt die Größe als [`UVec2`] zurück.
69    ///
70    /// Returns the size as a [`UVec2`].
71    #[inline(always)]
72    pub fn size(&self) -> UVec2 {
73        UVec2 {
74            x: self.width(),
75            y: self.height(),
76        }
77    }
78
79    /// Gibt zurück, ob das Rechteck den Punkt enthält.
80    ///
81    /// Returns whether the rectangle contains the given point.
82    #[inline]
83    pub fn contains(&self, point: UVec2) -> bool {
84        self.start.x <= point.x
85            && point.x <= self.end.x
86            && self.start.y <= point.y
87            && point.y <= self.end.y
88    }
89
90    /// Gibt zurück, ob sich dieses Rechteck mit einem anderen schneidet.
91    ///
92    /// Returns whether this rectangle intersects another.
93    #[inline]
94    pub fn intersects(&self, other: &Rectangle) -> bool {
95        self.start.x <= other.end.x
96            && self.end.x >= other.start.x
97            && self.start.y <= other.end.y
98            && self.end.y >= other.start.y
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_rectangle_creation() {
108        let start = UVec2 { x: 0, y: 0 };
109        let end = UVec2 { x: 5, y: 5 };
110        let rect = Rectangle::new(start, end);
111        assert_eq!(rect.start(), start);
112        assert_eq!(rect.end(), end);
113    }
114
115    #[test]
116    fn test_rectangle_width_and_height() {
117        let start = UVec2 { x: 1, y: 1 };
118        let end = UVec2 { x: 4, y: 6 };
119        let rect = Rectangle::new(start, end);
120        assert_eq!(rect.width(), 3);
121        assert_eq!(rect.height(), 5);
122    }
123
124    #[test]
125    fn test_rectangle_contains() {
126        let start = UVec2 { x: 0, y: 0 };
127        let end = UVec2 { x: 10, y: 10 };
128        let rect = Rectangle::new(start, end);
129        assert!(rect.contains(UVec2 { x: 5, y: 5 }));
130        assert!(!rect.contains(UVec2 { x: 11, y: 5 }));
131    }
132
133    #[test]
134    fn test_rectangle_intersects() {
135        let rect1 = Rectangle::new(UVec2 { x: 0, y: 0 }, UVec2 { x: 5, y: 5 });
136        let rect2 = Rectangle::new(UVec2 { x: 3, y: 3 }, UVec2 { x: 7, y: 7 });
137        let rect3 = Rectangle::new(UVec2 { x: 6, y: 6 }, UVec2 { x: 8, y: 8 });
138
139        assert!(rect1.intersects(&rect2));
140        assert!(!rect1.intersects(&rect3));
141    }
142}