Skip to main content

paperforge_core/
geometry.rs

1/// A 2D point.
2#[derive(Debug, Clone, Copy, PartialEq)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4pub struct Point {
5    pub x: f64,
6    pub y: f64,
7}
8
9impl Point {
10    pub fn new(x: f64, y: f64) -> Self {
11        Self { x, y }
12    }
13
14    pub fn distance(&self, other: &Self) -> f64 {
15        ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
16    }
17}
18
19/// A 2D size.
20#[derive(Debug, Clone, Copy, PartialEq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Size {
23    pub width: f64,
24    pub height: f64,
25}
26
27impl Size {
28    pub fn new(width: f64, height: f64) -> Self {
29        Self { width, height }
30    }
31}
32
33/// A rectangle.
34#[derive(Debug, Clone, Copy, PartialEq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct Rect {
37    pub x: f64,
38    pub y: f64,
39    pub width: f64,
40    pub height: f64,
41}
42
43impl Rect {
44    pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
45        Self {
46            x,
47            y,
48            width,
49            height,
50        }
51    }
52
53    pub fn from_points(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
54        Self {
55            x: x1.min(x2),
56            y: y1.min(y2),
57            width: (x2 - x1).abs(),
58            height: (y2 - y1).abs(),
59        }
60    }
61
62    pub fn contains(&self, px: f64, py: f64) -> bool {
63        px >= self.x && px <= self.x + self.width && py >= self.y && py <= self.y + self.height
64    }
65
66    pub fn intersects(&self, other: &Self) -> bool {
67        self.x < other.x + other.width
68            && self.x + self.width > other.x
69            && self.y < other.y + other.height
70            && self.y + self.height > other.y
71    }
72
73    pub fn union(&self, other: &Self) -> Self {
74        let x = self.x.min(other.x);
75        let y = self.y.min(other.y);
76        let max_x = (self.x + self.width).max(other.x + other.width);
77        let max_y = (self.y + self.height).max(other.y + other.height);
78        Self {
79            x,
80            y,
81            width: max_x - x,
82            height: max_y - y,
83        }
84    }
85
86    pub fn intersection(&self, other: &Self) -> Option<Self> {
87        let x = self.x.max(other.x);
88        let y = self.y.max(other.y);
89        let max_x = (self.x + self.width).min(other.x + other.width);
90        let max_y = (self.y + self.height).min(other.y + other.height);
91        if max_x > x && max_y > y {
92            Some(Self {
93                x,
94                y,
95                width: max_x - x,
96                height: max_y - y,
97            })
98        } else {
99            None
100        }
101    }
102}
103
104/// A transformation matrix.
105#[derive(Debug, Clone, Copy, PartialEq)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub struct Matrix {
108    pub a: f64,
109    pub b: f64,
110    pub c: f64,
111    pub d: f64,
112    pub e: f64,
113    pub f: f64,
114}
115
116impl Matrix {
117    pub fn identity() -> Self {
118        Self {
119            a: 1.0,
120            b: 0.0,
121            c: 0.0,
122            d: 1.0,
123            e: 0.0,
124            f: 0.0,
125        }
126    }
127
128    pub fn translate(tx: f64, ty: f64) -> Self {
129        Self {
130            a: 1.0,
131            b: 0.0,
132            c: 0.0,
133            d: 1.0,
134            e: tx,
135            f: ty,
136        }
137    }
138
139    pub fn scale(sx: f64, sy: f64) -> Self {
140        Self {
141            a: sx,
142            b: 0.0,
143            c: 0.0,
144            d: sy,
145            e: 0.0,
146            f: 0.0,
147        }
148    }
149
150    pub fn rotate(angle: f64) -> Self {
151        let cos = angle.to_radians().cos();
152        let sin = angle.to_radians().sin();
153        Self {
154            a: cos,
155            b: sin,
156            c: -sin,
157            d: cos,
158            e: 0.0,
159            f: 0.0,
160        }
161    }
162
163    pub fn combine(&self, other: &Self) -> Self {
164        Self {
165            a: self.a * other.a + self.b * other.c,
166            b: self.a * other.b + self.b * other.d,
167            c: self.c * other.a + self.d * other.c,
168            d: self.c * other.b + self.d * other.d,
169            e: self.e * other.a + self.f * other.c + other.e,
170            f: self.e * other.b + self.f * other.d + other.f,
171        }
172    }
173
174    pub fn transform_point(&self, x: f64, y: f64) -> (f64, f64) {
175        (
176            self.a * x + self.c * y + self.e,
177            self.b * x + self.d * y + self.f,
178        )
179    }
180}
181
182/// Alias for Matrix.
183pub type Transform = Matrix;