1#![doc = "Basic geometry types for visualization"]
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
7pub struct Point {
8 pub x: f64,
10 pub y: f64,
12}
13
14impl Point {
15 pub fn new(x: f64, y: f64) -> Self {
17 Self { x, y }
18 }
19
20 pub fn origin() -> Self {
22 Self::new(0.0, 0.0)
23 }
24
25 pub fn distance_to(&self, other: &Point) -> f64 {
27 let dx = self.x - other.x;
28 let dy = self.y - other.y;
29 (dx * dx + dy * dy).sqrt()
30 }
31
32 pub fn translate(&self, dx: f64, dy: f64) -> Point {
34 Point::new(self.x + dx, self.y + dy)
35 }
36
37 pub fn scale(&self, factor: f64) -> Point {
39 Point::new(self.x * factor, self.y * factor)
40 }
41}
42
43impl Default for Point {
44 fn default() -> Self {
45 Self::origin()
46 }
47}
48
49impl std::ops::Add for Point {
50 type Output = Point;
51
52 fn add(self, other: Point) -> Point {
53 Point::new(self.x + other.x, self.y + other.y)
54 }
55}
56
57impl std::ops::Sub for Point {
58 type Output = Point;
59
60 fn sub(self, other: Point) -> Point {
61 Point::new(self.x - other.x, self.y - other.y)
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Serialize, 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, Serialize, Deserialize)]
114pub struct Rect {
115 pub origin: Point,
117 pub size: Size,
119}
120
121impl Rect {
122 pub fn new(origin: Point, size: Size) -> Self {
124 Self { origin, size }
125 }
126
127 pub fn from_xywh(x: f64, y: f64, width: f64, height: f64) -> Self {
129 Self::new(Point::new(x, y), Size::new(width, height))
130 }
131
132 pub fn from_points(p1: Point, p2: Point) -> Self {
134 let min_x = p1.x.min(p2.x);
135 let min_y = p1.y.min(p2.y);
136 let max_x = p1.x.max(p2.x);
137 let max_y = p1.y.max(p2.y);
138
139 Self::from_xywh(min_x, min_y, max_x - min_x, max_y - min_y)
140 }
141
142 pub fn x(&self) -> f64 {
144 self.origin.x
145 }
146
147 pub fn y(&self) -> f64 {
149 self.origin.y
150 }
151
152 pub fn width(&self) -> f64 {
154 self.size.width
155 }
156
157 pub fn height(&self) -> f64 {
159 self.size.height
160 }
161
162 pub fn min_x(&self) -> f64 {
164 self.origin.x
165 }
166
167 pub fn min_y(&self) -> f64 {
169 self.origin.y
170 }
171
172 pub fn max_x(&self) -> f64 {
174 self.origin.x + self.size.width
175 }
176
177 pub fn max_y(&self) -> f64 {
179 self.origin.y + self.size.height
180 }
181
182 pub fn center(&self) -> Point {
184 Point::new(self.origin.x + self.size.width / 2.0, self.origin.y + self.size.height / 2.0)
185 }
186
187 pub fn top_left(&self) -> Point {
189 self.origin
190 }
191
192 pub fn top_right(&self) -> Point {
194 Point::new(self.max_x(), self.min_y())
195 }
196
197 pub fn bottom_left(&self) -> Point {
199 Point::new(self.min_x(), self.max_y())
200 }
201
202 pub fn bottom_right(&self) -> Point {
204 Point::new(self.max_x(), self.max_y())
205 }
206
207 pub fn contains_point(&self, point: Point) -> bool {
209 point.x >= self.min_x() && point.x <= self.max_x() && point.y >= self.min_y() && point.y <= self.max_y()
210 }
211
212 pub fn intersects(&self, other: &Rect) -> bool {
214 !(self.max_x() < other.min_x() || other.max_x() < self.min_x() || self.max_y() < other.min_y() || other.max_y() < self.min_y())
215 }
216
217 pub fn union(&self, other: &Rect) -> Rect {
219 let min_x = self.min_x().min(other.min_x());
220 let min_y = self.min_y().min(other.min_y());
221 let max_x = self.max_x().max(other.max_x());
222 let max_y = self.max_y().max(other.max_y());
223
224 Rect::from_xywh(min_x, min_y, max_x - min_x, max_y - min_y)
225 }
226
227 pub fn translate(&self, dx: f64, dy: f64) -> Rect {
229 Rect::new(self.origin.translate(dx, dy), self.size)
230 }
231
232 pub fn scale(&self, factor: f64) -> Rect {
234 Rect::new(self.origin.scale(factor), self.size.scale(factor))
235 }
236
237 pub fn expand(&self, margin: f64) -> Rect {
239 Rect::from_xywh(self.x() - margin, self.y() - margin, self.width() + 2.0 * margin, self.height() + 2.0 * margin)
240 }
241}
242
243impl Default for Rect {
244 fn default() -> Self {
245 Self::new(Point::default(), Size::default())
246 }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
251pub struct Transform {
252 pub a: f64,
254 pub b: f64,
256 pub c: f64,
258 pub d: f64,
260 pub e: f64,
262 pub f: f64,
264}
265
266impl Transform {
267 pub fn identity() -> Self {
269 Self { a: 1.0, b: 0.0, c: 0.0, d: 1.0, e: 0.0, f: 0.0 }
270 }
271
272 pub fn translate(x: f64, y: f64) -> Self {
274 Self { a: 1.0, b: 0.0, c: 0.0, d: 1.0, e: x, f: y }
275 }
276
277 pub fn scale(x: f64, y: f64) -> Self {
279 Self { a: x, b: 0.0, c: 0.0, d: y, e: 0.0, f: 0.0 }
280 }
281
282 pub fn rotate(angle: f64) -> Self {
284 let cos_a = angle.cos();
285 let sin_a = angle.sin();
286
287 Self { a: cos_a, b: sin_a, c: -sin_a, d: cos_a, e: 0.0, f: 0.0 }
288 }
289
290 pub fn transform_point(&self, point: Point) -> Point {
292 Point::new(self.a * point.x + self.c * point.y + self.e, self.b * point.x + self.d * point.y + self.f)
293 }
294
295 pub fn compose(&self, other: &Transform) -> Transform {
297 Transform {
298 a: self.a * other.a + self.b * other.c,
299 b: self.a * other.b + self.b * other.d,
300 c: self.c * other.a + self.d * other.c,
301 d: self.c * other.b + self.d * other.d,
302 e: self.e * other.a + self.f * other.c + other.e,
303 f: self.e * other.b + self.f * other.d + other.f,
304 }
305 }
306}
307
308impl Default for Transform {
309 fn default() -> Self {
310 Self::identity()
311 }
312}