1#![doc = "Basic geometry types for visualization"]
2
3#[derive(Debug, Clone, Copy, PartialEq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Point {
7 pub x: f64,
9 pub y: f64,
11}
12
13impl Point {
14 pub fn new(x: f64, y: f64) -> Self {
16 Self { x, y }
17 }
18
19 pub fn origin() -> Self {
21 Self::new(0.0, 0.0)
22 }
23
24 pub fn distance_to(&self, other: &Point) -> f64 {
26 let dx = self.x - other.x;
27 let dy = self.y - other.y;
28 (dx * dx + dy * dy).sqrt()
29 }
30
31 pub fn translate(&self, dx: f64, dy: f64) -> Point {
33 Point::new(self.x + dx, self.y + dy)
34 }
35
36 pub fn scale(&self, factor: f64) -> Point {
38 Point::new(self.x * factor, self.y * factor)
39 }
40}
41
42impl Default for Point {
43 fn default() -> Self {
44 Self::origin()
45 }
46}
47
48impl std::ops::Add for Point {
49 type Output = Point;
50
51 fn add(self, other: Point) -> Point {
52 Point::new(self.x + other.x, self.y + other.y)
53 }
54}
55
56impl std::ops::Sub for Point {
57 type Output = Point;
58
59 fn sub(self, other: Point) -> Point {
60 Point::new(self.x - other.x, self.y - other.y)
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67pub struct Size {
68 pub width: f64,
70 pub height: f64,
72}
73
74impl Size {
75 pub fn new(width: f64, height: f64) -> Self {
77 Self { width, height }
78 }
79
80 pub fn square(size: f64) -> Self {
82 Self::new(size, size)
83 }
84
85 pub fn area(&self) -> f64 {
87 self.width * self.height
88 }
89
90 pub fn aspect_ratio(&self) -> f64 {
92 if self.height != 0.0 { self.width / self.height } else { f64::INFINITY }
93 }
94
95 pub fn scale(&self, factor: f64) -> Size {
97 Size::new(self.width * factor, self.height * factor)
98 }
99
100 pub fn scale_xy(&self, x_factor: f64, y_factor: f64) -> Size {
102 Size::new(self.width * x_factor, self.height * y_factor)
103 }
104}
105
106impl Default for Size {
107 fn default() -> Self {
108 Self::new(100.0, 50.0)
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
115pub struct Rect {
116 pub origin: Point,
118 pub size: Size,
120}
121
122impl Rect {
123 pub fn new(origin: Point, size: Size) -> Self {
125 Self { origin, size }
126 }
127
128 pub fn from_xywh(x: f64, y: f64, width: f64, height: f64) -> Self {
130 Self::new(Point::new(x, y), Size::new(width, height))
131 }
132
133 pub fn from_points(p1: Point, p2: Point) -> Self {
135 let min_x = p1.x.min(p2.x);
136 let min_y = p1.y.min(p2.y);
137 let max_x = p1.x.max(p2.x);
138 let max_y = p1.y.max(p2.y);
139
140 Self::from_xywh(min_x, min_y, max_x - min_x, max_y - min_y)
141 }
142
143 pub fn x(&self) -> f64 {
145 self.origin.x
146 }
147
148 pub fn y(&self) -> f64 {
150 self.origin.y
151 }
152
153 pub fn width(&self) -> f64 {
155 self.size.width
156 }
157
158 pub fn height(&self) -> f64 {
160 self.size.height
161 }
162
163 pub fn min_x(&self) -> f64 {
165 self.origin.x
166 }
167
168 pub fn min_y(&self) -> f64 {
170 self.origin.y
171 }
172
173 pub fn max_x(&self) -> f64 {
175 self.origin.x + self.size.width
176 }
177
178 pub fn max_y(&self) -> f64 {
180 self.origin.y + self.size.height
181 }
182
183 pub fn center(&self) -> Point {
185 Point::new(self.origin.x + self.size.width / 2.0, self.origin.y + self.size.height / 2.0)
186 }
187
188 pub fn top_left(&self) -> Point {
190 self.origin
191 }
192
193 pub fn top_right(&self) -> Point {
195 Point::new(self.max_x(), self.min_y())
196 }
197
198 pub fn bottom_left(&self) -> Point {
200 Point::new(self.min_x(), self.max_y())
201 }
202
203 pub fn bottom_right(&self) -> Point {
205 Point::new(self.max_x(), self.max_y())
206 }
207
208 pub fn contains_point(&self, point: Point) -> bool {
210 point.x >= self.min_x() && point.x <= self.max_x() && point.y >= self.min_y() && point.y <= self.max_y()
211 }
212
213 pub fn intersects(&self, other: &Rect) -> bool {
215 !(self.max_x() < other.min_x() || other.max_x() < self.min_x() || self.max_y() < other.min_y() || other.max_y() < self.min_y())
216 }
217
218 pub fn union(&self, other: &Rect) -> Rect {
220 let min_x = self.min_x().min(other.min_x());
221 let min_y = self.min_y().min(other.min_y());
222 let max_x = self.max_x().max(other.max_x());
223 let max_y = self.max_y().max(other.max_y());
224
225 Rect::from_xywh(min_x, min_y, max_x - min_x, max_y - min_y)
226 }
227
228 pub fn translate(&self, dx: f64, dy: f64) -> Rect {
230 Rect::new(self.origin.translate(dx, dy), self.size)
231 }
232
233 pub fn scale(&self, factor: f64) -> Rect {
235 Rect::new(self.origin.scale(factor), self.size.scale(factor))
236 }
237
238 pub fn expand(&self, margin: f64) -> Rect {
240 Rect::from_xywh(self.x() - margin, self.y() - margin, self.width() + 2.0 * margin, self.height() + 2.0 * margin)
241 }
242}
243
244impl Default for Rect {
245 fn default() -> Self {
246 Self::new(Point::default(), Size::default())
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq)]
252#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
253pub struct Transform {
254 pub a: f64,
256 pub b: f64,
258 pub c: f64,
260 pub d: f64,
262 pub e: f64,
264 pub f: f64,
266}
267
268impl Transform {
269 pub fn identity() -> Self {
271 Self { a: 1.0, b: 0.0, c: 0.0, d: 1.0, e: 0.0, f: 0.0 }
272 }
273
274 pub fn translate(x: f64, y: f64) -> Self {
276 Self { a: 1.0, b: 0.0, c: 0.0, d: 1.0, e: x, f: y }
277 }
278
279 pub fn scale(x: f64, y: f64) -> Self {
281 Self { a: x, b: 0.0, c: 0.0, d: y, e: 0.0, f: 0.0 }
282 }
283
284 pub fn rotate(angle: f64) -> Self {
286 let cos_a = angle.cos();
287 let sin_a = angle.sin();
288
289 Self { a: cos_a, b: sin_a, c: -sin_a, d: cos_a, e: 0.0, f: 0.0 }
290 }
291
292 pub fn transform_point(&self, point: Point) -> Point {
294 Point::new(self.a * point.x + self.c * point.y + self.e, self.b * point.x + self.d * point.y + self.f)
295 }
296
297 pub fn compose(&self, other: &Transform) -> Transform {
299 Transform {
300 a: self.a * other.a + self.b * other.c,
301 b: self.a * other.b + self.b * other.d,
302 c: self.c * other.a + self.d * other.c,
303 d: self.c * other.b + self.d * other.d,
304 e: self.e * other.a + self.f * other.c + other.e,
305 f: self.e * other.b + self.f * other.d + other.f,
306 }
307 }
308}
309
310impl Default for Transform {
311 fn default() -> Self {
312 Self::identity()
313 }
314}