1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! Geometry module.

mod angle;
mod real;

pub(crate) use angle::angle_consts;
pub(crate) use angle::Trigonometry;
pub use angle::{Angle, AngleUnit};
pub use embedded_graphics_core::geometry::{
    AnchorPoint, Dimensions, OriginDimensions, Point, Size,
};
pub(crate) use real::Real;

pub(crate) trait PointExt {
    /// Returns a point that is rotated by 90° relative to the origin.
    fn rotate_90(self) -> Self;

    /// Calculates the dot product of two points.
    fn dot_product(self, other: Point) -> i32;

    /// Calculates the determinant of a 2x2 matrix formed by this and another point.
    ///
    /// ```text
    ///          | self.x  self.y  |
    /// result = |                 |
    ///          | other.x other.y |
    /// ```
    fn determinant(self, other: Point) -> i32;

    /// Returns the squared length.
    ///
    /// The returned value is the square of the length of a vector from `(0, 0)`
    /// to `(self.x, self.y)`.
    fn length_squared(self) -> i32;
}

impl PointExt for Point {
    fn rotate_90(self) -> Self {
        Self::new(self.y, -self.x)
    }

    fn dot_product(self, other: Point) -> i32 {
        self.x * other.x + self.y * other.y
    }

    fn determinant(self, other: Point) -> i32 {
        self.x * other.y - self.y * other.x
    }

    fn length_squared(self) -> i32 {
        self.x.pow(2) + self.y.pow(2)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn check_length_squared() {
        let p = Point::new(3, 4);

        assert_eq!(p.length_squared(), 25);
    }

    #[test]
    fn rotate_90() {
        assert_eq!(Point::new(1, 0).rotate_90(), Point::new(0, -1));
        assert_eq!(Point::new(0, -2).rotate_90(), Point::new(-2, 0));
        assert_eq!(Point::new(-3, 0).rotate_90(), Point::new(0, 3));
        assert_eq!(Point::new(0, 4).rotate_90(), Point::new(4, 0));
    }
}