1use std::{
2 hash::{Hash, Hasher},
3 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
4};
5
6use fnv::FnvHasher;
7
8#[derive(Copy, Clone, Debug, Default)]
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10pub struct Position {
11 pub x: f32,
12 pub y: f32,
13}
14
15impl Add<Vector> for Position {
16 type Output = Self;
17
18 #[inline]
19 fn add(self, other: Vector) -> Self {
20 Self {
21 x: self.x + other.x,
22 y: self.y + other.y,
23 }
24 }
25}
26
27impl Sub<Vector> for Position {
28 type Output = Self;
29
30 #[inline]
31 fn sub(self, other: Vector) -> Self {
32 Self {
33 x: self.x - other.x,
34 y: self.y - other.y,
35 }
36 }
37}
38
39impl Sub for Position {
40 type Output = Vector;
41
42 #[inline]
43 fn sub(self, other: Self) -> Vector {
44 Vector {
45 x: self.x - other.x,
46 y: self.y - other.y,
47 }
48 }
49}
50
51impl Position {
52 pub(crate) fn equals(p1: Self, p2: Self, tol: f32) -> bool {
53 (p2 - p1).mag2() < tol * tol
54 }
55
56 pub(crate) fn segment_distance(pos: Self, ppos: Self, qpos: Self) -> f32 {
57 let pq: Vector = qpos - ppos;
58 let dpos: Vector = pos - ppos;
59 let d: f32 = pq.mag2();
60 let mut t: f32 = pq.dot(dpos);
61
62 if d > 0.0 {
63 t /= d;
64 }
65
66 t = t.clamp(min:0.0, max:1.0);
67
68 let dpos: Vector = (ppos - pos) + pq * t;
69
70 dpos.mag2()
71 }
72}
73
74#[derive(Copy, Clone, Debug, Default)]
75pub struct Vector {
76 pub x: f32,
77 pub y: f32,
78}
79
80impl Vector {
81 pub fn zero() -> Self {
82 Self { x: 0.0, y: 0.0 }
83 }
84
85 pub fn x(x: f32) -> Self {
86 Self { x, y: 0.0 }
87 }
88 pub fn y(y: f32) -> Self {
89 Self { x: 0.0, y }
90 }
91
92 pub fn with_basis(self, basis_x: Self, basis_y: Self) -> Self {
93 basis_x * self.x + basis_y * self.y
94 }
95
96 pub fn cross(self, other: Self) -> f32 {
97 self.orthogonal().dot(other)
98 }
99
100 #[inline]
101 pub fn dot(self, other: Self) -> f32 {
102 self.x * other.x + self.y * other.y
103 }
104
105 #[inline]
106 pub fn mag2(self) -> f32 {
107 self.dot(self)
108 }
109
110 #[inline]
111 pub fn orthogonal(self) -> Self {
112 Self { x: self.y, y: -self.x }
113 }
114
115 #[inline]
116 pub fn from_angle(angle: f32) -> Self {
117 let (y, x) = angle.sin_cos();
118 Self { x, y }
119 }
120
121 #[inline]
122 pub fn angle(&self) -> f32 {
123 self.y.atan2(self.x)
124 }
125
126 pub fn normalize(&mut self) -> f32 {
127 let d = self.x.hypot(self.y);
128
129 if d > 1e-6 {
130 let id = 1.0 / d;
131 self.x *= id;
132 self.y *= id;
133 }
134
135 d
136 }
137}
138
139impl Add for Vector {
140 type Output = Self;
141
142 #[inline]
143 fn add(self, other: Self) -> Self {
144 Self {
145 x: self.x + other.x,
146 y: self.y + other.y,
147 }
148 }
149}
150
151impl Sub for Vector {
152 type Output = Self;
153
154 #[inline]
155 fn sub(self, other: Self) -> Self {
156 Self {
157 x: self.x - other.x,
158 y: self.y - other.y,
159 }
160 }
161}
162
163impl Neg for Vector {
164 type Output = Self;
165
166 #[inline]
167 fn neg(self) -> Self {
168 Self { x: -self.x, y: -self.y }
169 }
170}
171
172impl Mul<f32> for Vector {
173 type Output = Self;
174
175 #[inline]
176 fn mul(self, other: f32) -> Self {
177 Self {
178 x: self.x * other,
179 y: self.y * other,
180 }
181 }
182}
183
184impl MulAssign<f32> for Vector {
185 #[inline]
186 fn mul_assign(&mut self, other: f32) {
187 self.x *= other;
188 self.y *= other;
189 }
190}
191
192pub fn quantize(a: f32, d: f32) -> f32 {
193 (a / d + 0.5).trunc() * d
194}
195
196/// 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent transformations such as translation, rotation, or scaling.
197#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
198#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
199pub struct Transform2D(pub [f32; 6]);
200
201impl Transform2D {
202 /// Creates an identity transformation with no translation, rotation, or scaling applied.
203 pub fn identity() -> Self {
204 Self([1.0, 0.0, 0.0, 1.0, 0.0, 0.0])
205 }
206
207 /// Creates a new transformation matrix.
208 ///
209 /// The parameters are interpreted as matrix elements as follows:
210 /// [a c x]
211 /// [b d y]
212 /// [0 0 1]
213 pub fn new(a: f32, b: f32, c: f32, d: f32, x: f32, y: f32) -> Self {
214 Self([a, b, c, d, x, y])
215 }
216
217 /// Creates a translation transformation matrix.
218 pub fn translation(tx: f32, ty: f32) -> Self {
219 Self([1.0, 0.0, 0.0, 1.0, tx, ty])
220 }
221
222 /// Creates a rotation transformation matrix.
223 pub fn rotation(a: f32) -> Self {
224 let (sin, cos) = a.sin_cos();
225
226 Self([cos, sin, -sin, cos, 0.0, 0.0])
227 }
228
229 /// Creates a scaling transformation matrix.
230 pub fn scaling(sx: f32, sy: f32) -> Self {
231 Self([sx, 0.0, 0.0, sy, 0.0, 0.0])
232 }
233
234 /// Translates the matrix.
235 pub fn translate(&mut self, tx: f32, ty: f32) {
236 let Self([.., x, y]) = self;
237
238 *x += tx;
239 *y += ty;
240 }
241
242 /// Rotates the matrix.
243 pub fn rotate(&mut self, a: f32) {
244 let (sin, cos) = a.sin_cos();
245
246 let Self([a, b, c, d, x, y]) = self;
247
248 [*a, *b] = [*a * cos - *b * sin, *a * sin + *b * cos];
249 [*c, *d] = [*c * cos - *d * sin, *c * sin + *d * cos];
250 [*x, *y] = [*x * cos - *y * sin, *x * sin + *y * cos];
251 }
252
253 /// Scales the matrix.
254 pub fn scale(&mut self, sx: f32, sy: f32) {
255 let Self([a, b, c, d, x, y]) = self;
256
257 *a *= sx;
258 *b *= sy;
259 *c *= sx;
260 *d *= sy;
261 *x *= sx;
262 *y *= sy;
263 }
264
265 /// Skews the matrix horizontally.
266 pub fn skew_x(&mut self, a: f32) {
267 let tan = a.tan();
268
269 let Self([a, b, c, d, x, y]) = self;
270
271 *a += *b * tan;
272 *c += *d * tan;
273 *x += *y * tan;
274 }
275
276 /// Skews the matrix vertically.
277 pub fn skew_y(&mut self, a: f32) {
278 let tan = a.tan();
279
280 let Self([a, b, c, d, x, y]) = self;
281
282 *b += *a * tan;
283 *d += *c * tan;
284 *y += *x * tan;
285 }
286
287 /// Premultiplies the current transformation matrix with another matrix.
288 #[inline]
289 pub fn premultiply(&mut self, other: &Self) {
290 *self = *other * *self;
291 }
292
293 /// Inverts the current transformation matrix.
294 #[inline]
295 pub fn invert(&mut self) {
296 *self = self.inverse()
297 }
298
299 /// Returns the inverse of the current transformation matrix.
300 pub fn inverse(&self) -> Self {
301 let &Self([a, b, c, d, x, y]) = self;
302 let [a, b, c, d, x, y] = [a as f64, b as f64, c as f64, d as f64, x as f64, y as f64];
303
304 let det = a * d - c * b;
305
306 if det > -1e-6 && det < 1e-6 {
307 return Self::identity();
308 }
309
310 let invdet = 1.0 / det;
311
312 Self([
313 (d * invdet) as f32,
314 (-b * invdet) as f32,
315 (-c * invdet) as f32,
316 (a * invdet) as f32,
317 ((c * y - d * x) * invdet) as f32,
318 ((b * x - a * y) * invdet) as f32,
319 ])
320 }
321
322 /// Transforms a point using the current transformation matrix.
323 pub fn transform_point(&self, sx: f32, sy: f32) -> (f32, f32) {
324 let &Self([a, b, c, d, x, y]) = self;
325
326 let dx = sx * a + sy * c + x;
327 let dy = sx * b + sy * d + y;
328 (dx, dy)
329 }
330
331 /// Calculates the average scale factor of the current transformation matrix.
332 pub fn average_scale(&self) -> f32 {
333 let &Self([a, b, c, d, ..]) = self;
334
335 let sx = a.hypot(c);
336 let sy = b.hypot(d);
337
338 (sx + sy) * 0.5
339 }
340
341 /// Converts the current transformation matrix to a 3×4 matrix format.
342 pub fn to_mat3x4(self) -> [f32; 12] {
343 let Self([a, b, c, d, x, y]) = self;
344 [a, b, 0.0, 0.0, c, d, 0.0, 0.0, x, y, 1.0, 0.0]
345 }
346
347 /// Generates a cache key for the current transformation matrix.
348 pub fn cache_key(&self) -> u64 {
349 let mut hasher = FnvHasher::default();
350
351 for i in 0..6 {
352 self.0[i].to_bits().hash(&mut hasher);
353 }
354
355 hasher.finish()
356 }
357}
358
359impl Default for Transform2D {
360 fn default() -> Self {
361 Self::identity()
362 }
363}
364
365impl Index<usize> for Transform2D {
366 type Output = f32;
367
368 fn index(&self, index: usize) -> &Self::Output {
369 &self.0[index]
370 }
371}
372
373impl IndexMut<usize> for Transform2D {
374 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
375 &mut self.0[index]
376 }
377}
378
379impl Add for Transform2D {
380 type Output = Self;
381
382 fn add(self, other: Self) -> Self::Output {
383 let Self([a0: f32, b0: f32, c0: f32, d0: f32, x0: f32, y0: f32]) = self;
384 let Self([a1: f32, b1: f32, c1: f32, d1: f32, x1: f32, y1: f32]) = other;
385
386 Self([a0 + a1, b0 + b1, c0 + c1, d0 + d1, x0 + x1, y0 + y1])
387 }
388}
389
390impl AddAssign for Transform2D {
391 #[inline]
392 fn add_assign(&mut self, other: Self) {
393 *self = *self + other;
394 }
395}
396
397impl Sub for Transform2D {
398 type Output = Self;
399
400 fn sub(self, other: Self) -> Self::Output {
401 let Self([a0: f32, b0: f32, c0: f32, d0: f32, x0: f32, y0: f32]) = self;
402 let Self([a1: f32, b1: f32, c1: f32, d1: f32, x1: f32, y1: f32]) = other;
403
404 Self([a0 - a1, b0 - b1, c0 - c1, d0 - d1, x0 - x1, y0 - y1])
405 }
406}
407
408impl SubAssign for Transform2D {
409 #[inline]
410 fn sub_assign(&mut self, other: Self) {
411 *self = *self - other;
412 }
413}
414
415impl Mul for Transform2D {
416 type Output = Self;
417
418 #[inline]
419 fn mul(mut self, other: Self) -> Self::Output {
420 self *= other;
421 self
422 }
423}
424
425impl MulAssign for Transform2D {
426 fn mul_assign(&mut self, other: Self) {
427 let Self([a0: &mut f32, b0: &mut f32, c0: &mut f32, d0: &mut f32, x0: &mut f32, y0: &mut f32]) = self;
428 let Self([a1: f32, b1: f32, c1: f32, d1: f32, x1: f32, y1: f32]) = other;
429
430 [*a0, *b0] = [*a0 * a1 + *b0 * c1, *a0 * b1 + *b0 * d1];
431 [*c0, *d0] = [*c0 * a1 + *d0 * c1, *c0 * b1 + *d0 * d1];
432 [*x0, *y0] = [*x0 * a1 + *y0 * c1 + x1, *x0 * b1 + *y0 * d1 + y1];
433 }
434}
435
436impl Div for Transform2D {
437 type Output = Self;
438
439 fn div(self, other: Self) -> Self::Output {
440 self * other.inverse()
441 }
442}
443
444impl DivAssign for Transform2D {
445 #[inline]
446 fn div_assign(&mut self, other: Self) {
447 *self = *self / other;
448 }
449}
450
451#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
452pub struct Rect {
453 pub x: f32,
454 pub y: f32,
455 pub w: f32,
456 pub h: f32,
457}
458
459impl Rect {
460 pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
461 Self { x, y, w, h }
462 }
463
464 pub fn intersect(&self, other: Self) -> Self {
465 let minx = self.x.max(other.x);
466 let miny = self.y.max(other.y);
467 let maxx = (self.x + self.w).min(other.x + other.w);
468 let maxy = (self.y + self.h).min(other.y + other.h);
469
470 Self::new(minx, miny, 0.0f32.max(maxx - minx), 0.0f32.max(maxy - miny))
471 }
472
473 pub fn contains_rect(&self, other: &Self) -> bool {
474 other.is_empty()
475 || (self.x <= other.x
476 && other.x + other.w <= self.x + self.w
477 && self.y <= other.y
478 && other.y + other.h <= self.y + self.h)
479 }
480
481 pub fn intersection(&self, other: &Self) -> Option<Self> {
482 let x = self.x.max(other.x);
483 let y = self.y.max(other.y);
484 let w = (self.x + self.w).min(other.x + other.w) - x;
485 let h = (self.y + self.h).min(other.y + other.h) - y;
486
487 let result = Self { x, y, w, h };
488 if result.is_empty() {
489 None
490 } else {
491 Some(result)
492 }
493 }
494
495 pub fn is_empty(&self) -> bool {
496 self.w <= 0. || self.h <= 0.
497 }
498}
499
500#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
501pub struct Bounds {
502 pub minx: f32,
503 pub miny: f32,
504 pub maxx: f32,
505 pub maxy: f32,
506}
507
508impl Default for Bounds {
509 fn default() -> Self {
510 Self {
511 minx: 1e6,
512 miny: 1e6,
513 maxx: -1e6,
514 maxy: -1e6,
515 }
516 }
517}
518
519impl Bounds {
520 pub(crate) fn contains(&self, x: f32, y: f32) -> bool {
521 (self.minx..=self.maxx).contains(&x) && (self.miny..=self.maxy).contains(&y)
522 }
523}
524