1use std::ops::{Add, Mul, Neg, Sub};
23use std::option::Option;
24
25#[derive(PartialOrd, PartialEq, Copy, Clone, Debug)]
26pub struct Point {
33 #[allow(missing_docs)]
34 pub x: f64,
35 #[allow(missing_docs)]
36 pub y: f64,
37}
38
39#[derive(PartialOrd, PartialEq, Copy, Clone, Debug)]
40pub struct Vector {
42 #[allow(missing_docs)]
43 pub x: f64,
44 #[allow(missing_docs)]
45 pub y: f64,
46}
47
48#[derive(Copy, Clone, Debug)]
49pub struct Matrix {
51 pub a1: f64,
53 pub b1: f64,
55 pub a2: f64,
57 pub b2: f64,
59}
60
61#[derive(PartialOrd, PartialEq, Copy, Clone, Debug)]
62pub(crate) struct Rect {
63 pub top_left: Point,
64 pub bottom_right: Point,
65}
66
67impl Neg for Vector {
68 type Output = Vector;
69 fn neg(self) -> Vector {
70 Vector {
71 x: -self.x,
72 y: -self.y,
73 }
74 }
75}
76
77impl Sub<Matrix> for Matrix {
78 type Output = Matrix;
79 fn sub(self, rhs: Matrix) -> Matrix {
80 Matrix {
81 a1: self.a1 - rhs.a1,
82 a2: self.a2 - rhs.a2,
83 b1: self.b1 - rhs.b1,
84 b2: self.b2 - rhs.b2,
85 }
86 }
87}
88
89impl Add<Matrix> for Matrix {
90 type Output = Matrix;
91 fn add(self, rhs: Matrix) -> Matrix {
92 Matrix {
93 a1: self.a1 + rhs.a1,
94 a2: self.a2 + rhs.a2,
95 b1: self.b1 + rhs.b1,
96 b2: self.b2 + rhs.b2,
97 }
98 }
99}
100
101impl Mul<Matrix> for Matrix {
102 type Output = Matrix;
103 fn mul(self, rhs: Matrix) -> Matrix {
104 Matrix {
105 a1: (self.a1 * rhs.a1) + (self.b1 * rhs.a2),
106 a2: (self.a2 * rhs.a1) + (self.b2 * rhs.a2),
107 b1: (self.a1 * rhs.b1) + (self.b1 * rhs.b2),
108 b2: (self.a2 * rhs.b1) + (self.b2 * rhs.b2),
109 }
110 }
111}
112
113impl Mul<f64> for Matrix {
114 type Output = Matrix;
115 fn mul(self, rhs: f64) -> Matrix {
116 Matrix {
117 a1: self.a1 * rhs,
118 a2: self.a2 * rhs,
119 b1: self.b1 * rhs,
120 b2: self.b2 * rhs,
121 }
122 }
123}
124
125impl Mul<Point> for Matrix {
126 type Output = Point;
127 fn mul(self, rhs: Point) -> Point {
128 Point {
129 x: (self.a1 * rhs.x) + (self.b1 * rhs.y),
130 y: (self.a2 * rhs.x) + (self.b2 * rhs.y),
131 }
132 }
133}
134
135impl Mul<Vector> for Matrix {
136 type Output = Vector;
137 fn mul(self, rhs: Vector) -> Vector {
138 Vector {
139 x: (self.a1 * rhs.x) + (self.b1 * rhs.y),
140 y: (self.a2 * rhs.x) + (self.b2 * rhs.y),
141 }
142 }
143}
144
145impl Matrix {
146 pub fn inverse(self) -> Option<Matrix> {
149 let det = (self.a1 * self.b2) - (self.b1 * self.a2);
150 if det == 0.0 {
151 None
152 } else {
153 Some(
154 Matrix {
155 a1: self.b2,
156 b1: -self.b1,
157 a2: -self.a2,
158 b2: self.a1,
159 } * (1.0 / det),
160 )
161 }
162 }
163}
164
165impl Add<Vector> for Vector {
166 type Output = Vector;
167 fn add(self, rhs: Vector) -> Vector {
168 Vector {
169 x: self.x + rhs.x,
170 y: self.y + rhs.y,
171 }
172 }
173}
174
175impl Sub<Vector> for Vector {
176 type Output = Vector;
177 fn sub(self, rhs: Vector) -> Vector {
178 Vector {
179 x: self.x - rhs.x,
180 y: self.y - rhs.y,
181 }
182 }
183}
184
185impl Mul<f64> for Vector {
186 type Output = Vector;
187 fn mul(self, rhs: f64) -> Vector {
188 Vector {
189 x: self.x * rhs,
190 y: self.y * rhs,
191 }
192 }
193}
194
195impl Sub<Vector> for Point {
196 type Output = Point;
197 fn sub(self, rhs: Vector) -> Point {
198 Point {
199 x: self.x - rhs.x,
200 y: self.y - rhs.y,
201 }
202 }
203}
204
205impl Add<Vector> for Point {
206 type Output = Point;
207 fn add(self, rhs: Vector) -> Point {
208 Point {
209 x: self.x + rhs.x,
210 y: self.y + rhs.y,
211 }
212 }
213}
214
215impl Sub<Point> for Vector {
216 type Output = Point;
217 fn sub(self, rhs: Point) -> Point {
218 Point {
219 x: self.x - rhs.x,
220 y: self.y - rhs.y,
221 }
222 }
223}
224
225impl Add<Point> for Vector {
226 type Output = Point;
227 fn add(self, rhs: Point) -> Point {
228 Point {
229 x: self.x + rhs.x,
230 y: self.y + rhs.y,
231 }
232 }
233}
234
235impl Sub<Point> for Point {
236 type Output = Vector;
237 fn sub(self, rhs: Point) -> Vector {
238 Vector {
239 x: self.x - rhs.x,
240 y: self.y - rhs.y,
241 }
242 }
243}
244
245#[allow(unused)]
248impl Rect {
249 pub(crate) fn centered_with_radius(p1: &Point, radius: f64) -> Rect {
250 let v = Vector {
251 x: radius,
252 y: radius,
253 };
254 Rect::from_points(&(*p1 - v), &(*p1 + v))
255 }
256
257 pub(crate) fn from_points(p1: &Point, p2: &Point) -> Rect {
258 let mut r = Rect::null_at(&p1);
259 r.expand_to_include(&p2);
260 r
261 }
262
263 pub(crate) fn from_point_and_size(point: &Point, size: &Vector) -> Rect {
264 assert!(size.x > 0.0);
265 assert!(size.y > 0.0);
266 Rect {
267 top_left: *point,
268 bottom_right: *point + *size,
269 }
270 }
271
272 pub(crate) fn null() -> Rect {
273 let nan = ::std::f64::NAN;
274 Rect {
275 top_left: Point { x: nan, y: nan },
276 bottom_right: Point { x: nan, y: nan },
277 }
278 }
279
280 pub(crate) fn null_at(point: &Point) -> Rect {
281 Rect {
282 top_left: *point,
283 bottom_right: *point,
284 }
285 }
286
287 pub(crate) fn expand(&self, left: f64, top: f64, right: f64, bottom: f64) -> Rect {
288 let top_left_vec = Vector { x: left, y: top };
289 let bottom_right_vec = Vector {
290 x: right,
291 y: bottom,
292 };
293 Rect {
294 top_left: self.top_left - top_left_vec,
295 bottom_right: self.bottom_right + bottom_right_vec,
296 }
297 }
298
299 pub(crate) fn width(&self) -> f64 {
300 self.bottom_right.x - self.top_left.x
301 }
302
303 pub(crate) fn height(&self) -> f64 {
304 self.bottom_right.y - self.top_left.y
305 }
306
307 pub(crate) fn left(&self) -> f64 {
308 self.top_left.x
309 }
310
311 pub(crate) fn right(&self) -> f64 {
312 self.bottom_right.x
313 }
314
315 pub(crate) fn top(&self) -> f64 {
316 self.top_left.y
317 }
318
319 pub(crate) fn bottom(&self) -> f64 {
320 self.bottom_right.y
321 }
322
323 pub(crate) fn top_left(&self) -> Point {
324 self.top_left
325 }
326
327 pub(crate) fn bottom_right(&self) -> Point {
328 self.bottom_right
329 }
330
331 pub(crate) fn bottom_left(&self) -> Point {
332 Point {
333 x: self.top_left().x,
334 y: self.bottom_right().y,
335 }
336 }
337
338 pub(crate) fn top_right(&self) -> Point {
339 Point {
340 x: self.bottom_right().x,
341 y: self.top_left().y,
342 }
343 }
344
345 pub(crate) fn north(&self) -> Point {
346 Point {
347 x: self.left() + self.width() / 2.0,
348 y: self.top(),
349 }
350 }
351
352 pub(crate) fn south(&self) -> Point {
353 Point {
354 x: self.left() + self.width() / 2.0,
355 y: self.bottom(),
356 }
357 }
358
359 pub(crate) fn west(&self) -> Point {
360 Point {
361 x: self.left(),
362 y: self.top() + self.height() / 2.0,
363 }
364 }
365
366 pub(crate) fn east(&self) -> Point {
367 Point {
368 x: self.right(),
369 y: self.top() + self.height() / 2.0,
370 }
371 }
372
373 pub(crate) fn expanded_by(&self, point: &Point) -> Rect {
374 let mut r = self.clone();
375 r.expand_to_include(point);
376 r
377 }
378
379 pub(crate) fn is_null(&self) -> bool {
380 self.top_left.x.is_nan()
381 || self.top_left.y.is_nan()
382 || self.bottom_right.x.is_nan()
383 || self.bottom_right.y.is_nan()
384 }
385
386 pub(crate) fn expand_to_include(&mut self, point: &Point) {
387 fn min(a: f64, b: f64) -> f64 {
388 if a.is_nan() {
389 return b;
390 }
391 if b.is_nan() {
392 return a;
393 }
394 if a < b {
395 return a;
396 }
397 return b;
398 }
399
400 fn max(a: f64, b: f64) -> f64 {
401 if a.is_nan() {
402 return b;
403 }
404 if b.is_nan() {
405 return a;
406 }
407 if a > b {
408 return a;
409 }
410 return b;
411 }
412
413 self.top_left.x = min(self.top_left.x, point.x);
414 self.top_left.y = min(self.top_left.y, point.y);
415
416 self.bottom_right.x = max(self.bottom_right.x, point.x);
417 self.bottom_right.y = max(self.bottom_right.y, point.y);
418 }
419
420 pub(crate) fn union_with(&self, other: &Rect) -> Rect {
421 let mut r = self.clone();
422 r.expand_to_include(&other.top_left);
423 r.expand_to_include(&other.bottom_right);
424 r
425 }
426
427 pub(crate) fn contains(&self, p: &Point) -> bool {
428 p.x >= self.top_left.x
429 && p.x < self.bottom_right.x
430 && p.y >= self.top_left.y
431 && p.y < self.bottom_right.y
432 }
433
434 pub(crate) fn does_intersect(&self, other: &Rect) -> bool {
435 let r1 = self;
436 let r2 = other;
437
438 !(r2.left() > r1.right()
441 || r2.right() < r1.left()
442 || r2.top() > r1.bottom()
443 || r2.bottom() < r1.top())
444 }
445
446 pub(crate) fn intersect_with(&self, other: &Rect) -> Rect {
447 if !self.does_intersect(other) {
448 return Rect::null();
449 }
450 let left = self.left().max(other.left());
451 let right = self.right().min(other.right());
452
453 let top = self.top().max(other.top());
454 let bottom = self.bottom().min(other.bottom());
455
456 Rect::from_points(
457 &Point { x: left, y: top },
458 &Point {
459 x: right,
460 y: bottom,
461 },
462 )
463 }
464
465 pub(crate) fn midpoint(&self) -> Point {
466 let half = Vector {
467 x: self.width() / 2.0,
468 y: self.height() / 2.0,
469 };
470 self.top_left() + half
471 }
472
473 pub(crate) fn split_vert(&self) -> (Rect, Rect) {
474 let half_size = Vector {
475 x: self.width() / 2.0,
476 y: self.height(),
477 };
478 let half_offset = Vector {
479 x: self.width() / 2.0,
480 y: 0.0,
481 };
482 (
483 Rect::from_point_and_size(&self.top_left, &half_size),
484 Rect::from_point_and_size(&(self.top_left + half_offset), &half_size),
485 )
486 }
487
488 pub(crate) fn split_hori(&self) -> (Rect, Rect) {
489 let half_size = Vector {
490 x: self.width(),
491 y: self.height() / 2.0,
492 };
493 let half_offset = Vector {
494 x: 0.0,
495 y: self.height() / 2.0,
496 };
497 (
498 Rect::from_point_and_size(&self.top_left, &half_size),
499 Rect::from_point_and_size(&(self.top_left + half_offset), &half_size),
500 )
501 }
502
503 pub(crate) fn split_quad(&self) -> [Rect; 4] {
504 let half = Vector {
505 x: self.width() / 2.0,
506 y: self.height() / 2.0,
507 };
508 [
509 Rect::from_point_and_size(&self.top_left, &half),
512 Rect::from_point_and_size(
515 &Point {
516 x: self.top_left.x + half.x,
517 ..self.top_left
518 },
519 &half,
520 ),
521 Rect::from_point_and_size(
524 &Point {
525 y: self.top_left.y + half.y,
526 ..self.top_left
527 },
528 &half,
529 ),
530 Rect::from_point_and_size(&(self.top_left + half), &half),
533 ]
534 }
535
536 pub(crate) fn close_to(&self, other: &Rect, epsilon: f64) -> bool {
537 self.top_left.close_to(&other.top_left, epsilon)
538 && self.bottom_right.close_to(&other.bottom_right, epsilon)
539 }
540}
541
542impl Vector {
543 pub fn new(x: f64, y: f64) -> Self {
545 Self { x, y }
546 }
547
548 pub fn magnitude(&self) -> f64 {
550 (self.x * self.x + self.y * self.y).sqrt()
551 }
552
553 pub fn normalized(&self) -> Vector {
555 let m = self.magnitude();
556 Vector {
557 x: self.x / m,
558 y: self.y / m,
559 }
560 }
561
562 pub fn normal(&self) -> Vector {
564 Vector {
565 x: -self.y,
566 y: self.x,
567 }
568 }
569
570 pub fn mul_e(&self, other: &Vector) -> Vector {
572 Vector {
573 x: self.x * other.x,
574 y: self.y * other.y,
575 }
576 }
577
578 pub fn scale_e(&self, sx: f64, sy: f64) -> Vector {
580 Vector {
581 x: self.x * sx,
582 y: self.y * sy,
583 }
584 }
585
586 pub fn rotate(&self, theta: f64) -> Vector {
588 Matrix {
589 a1: f64::cos(theta),
590 b1: -f64::sin(theta),
591 a2: f64::sin(theta),
592 b2: f64::cos(theta),
593 } * *self
594 }
595
596 pub fn cross(&self, other: &Vector) -> f64 {
598 self.x * other.y - self.y * other.x
599 }
600
601 pub fn dot(&self, other: &Vector) -> f64 {
603 self.x * other.x + self.y * other.y
604 }
605
606 pub fn reflect(&self, normal: &Vector) -> Vector {
617 let t: f64 = 2.0 * (normal.x * self.x + normal.y * self.y)
618 / (normal.x * normal.x + normal.y * normal.y);
619 let x = self.x - t * normal.x;
620 let y = self.y - t * normal.y;
621 Vector { x, y }
622 }
623
624 pub fn p(self) -> Point {
628 Point {
629 x: self.x,
630 y: self.y,
631 }
632 }
633}
634
635impl From<(f64, f64)> for Vector {
636 fn from(value: (f64, f64)) -> Self {
637 Self {
638 x: value.0,
639 y: value.1,
640 }
641 }
642}
643
644impl Point {
645 pub fn new(x: f64, y: f64) -> Self {
647 Self { x, y }
648 }
649
650 pub fn close_to(&self, other: &Point, epsilon: f64) -> bool {
653 self.distance_2(other) < epsilon * epsilon
654 }
655
656 pub fn distance(&self, other: &Point) -> f64 {
658 self.distance_2(other).sqrt()
659 }
660
661 pub fn distance_2(&self, other: &Point) -> f64 {
664 let dx = self.x - other.x;
665 let dy = self.y - other.y;
666 dx * dx + dy * dy
667 }
668
669 pub fn v(self) -> Vector {
671 Vector {
672 x: self.x,
673 y: self.y,
674 }
675 }
676}
677
678impl From<(f64, f64)> for Point {
679 fn from(value: (f64, f64)) -> Self {
680 Self {
681 x: value.0,
682 y: value.1,
683 }
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use super::{Matrix, Vector};
690 #[test]
691 fn matrix_inverse() {
692 let m = Matrix {
693 a1: 1.0,
694 b1: 2.0,
695 a2: 3.0,
696 b2: 4.0,
697 };
698 let n = m.inverse().expect("This should have an inverse");
699 assert_eq!(n.a1, -2.0);
700 assert_eq!(n.b1, 1.0);
701 assert_eq!(n.a2, 1.5);
702 assert_eq!(n.b2, -0.5);
703 }
704
705 #[test]
706 fn matrix_inverse_identity() {
707 let m = Matrix {
708 a1: 1.0,
709 b1: 0.0,
710 a2: 0.0,
711 b2: 1.0,
712 };
713 let n = m.inverse().expect("This should have an inverse");
714 assert_eq!(n.a1, 1.0);
715 assert_eq!(n.b1, 0.0);
716 assert_eq!(n.a2, 0.0);
717 assert_eq!(n.b2, 1.0);
718 }
719
720 #[test]
721 fn matrix_inverse_singular() {
722 let m = Matrix {
723 a1: 0.0,
724 b1: 0.0,
725 a2: 0.0,
726 b2: 0.0,
727 };
728 let n = m.inverse();
729 if n.is_none() {
730 return;
731 } else {
732 panic!("This should be singular");
733 }
734 }
735
736 #[test]
737 fn vector_dot() {
738 let a = Vector { x: 1.0, y: 0.0 };
739 let b = Vector {
740 x: f64::cos(1.0),
741 y: f64::cos(1.0),
742 };
743 let t = f64::acos(a.dot(&b));
744 assert!(t < 1.0001);
745 assert!(t > 0.9999);
746 }
747
748 #[test]
749 fn vector_dot_2() {
750 let a = Vector { x: 0.0, y: 1.0 };
751 let b = Vector {
752 x: f64::sin(1.0),
753 y: f64::cos(1.0),
754 };
755 let t = f64::acos(a.dot(&b));
756 assert!(t < 1.0001);
757 assert!(t > 0.9999);
758 }
759
760 #[test]
761 fn vector_rotate() {
762 let v = Vector { x: 6.0, y: 4.0 };
763 let r = v.rotate(-std::f64::consts::PI / 2.0);
764
765 assert_eq!(r.x.round(), 4.0);
766 assert_eq!(r.y.round(), -6.0);
767 }
768
769 #[test]
770 fn vector_rotate_2() {
771 let v = Vector { x: 6.0, y: 4.0 };
772 let r = v.rotate(std::f64::consts::PI);
773
774 assert_eq!(r.x.round(), -6.0);
775 assert_eq!(r.y.round(), -4.0);
776 }
777}