geometry/
point.rs

1//! 2-D points.
2
3use serde::{Deserialize, Serialize};
4use std::ops::Mul;
5
6use crate::dims::Dims;
7use crate::dir::Dir;
8use crate::prelude::Transform;
9use crate::snap::snap_to_grid;
10use crate::transform::{
11    TransformMut, TransformRef, Transformation, Translate, TranslateMut, TranslateRef,
12};
13
14/// A point in two-dimensional space.
15#[derive(
16    Debug, Copy, Clone, Default, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord,
17)]
18pub struct Point {
19    /// The x-coordinate of the point.
20    pub x: i64,
21    /// The y-coordinate of the point.
22    pub y: i64,
23}
24
25impl Point {
26    /// Creates a new [`Point`] from (x,y) coordinates.
27    pub const fn new(x: i64, y: i64) -> Self {
28        Self { x, y }
29    }
30
31    /// Creates a new point from the given direction and coordinates.
32    ///
33    /// If `dir` is [`Dir::Horiz`], `a` becomes the x-coordinate and `b` becomes the y-coordinate.
34    /// If `dir` is [`Dir::Vert`], `a` becomes the y-coordinate and `b` becomes the x-coordinate.
35    pub const fn from_dir_coords(dir: Dir, a: i64, b: i64) -> Self {
36        match dir {
37            Dir::Horiz => Self::new(a, b),
38            Dir::Vert => Self::new(b, a),
39        }
40    }
41
42    /// Returns the origin, `(0, 0)`.
43    ///
44    /// # Example
45    ///
46    /// ```
47    /// # use geometry::prelude::*;
48    /// let origin = Point::zero();
49    /// assert_eq!(origin, Point::new(0, 0));
50    /// ```
51    #[inline]
52    pub const fn zero() -> Self {
53        Self { x: 0, y: 0 }
54    }
55
56    /// Gets the coordinate associated with direction `dir`.
57    pub const fn coord(&self, dir: Dir) -> i64 {
58        match dir {
59            Dir::Horiz => self.x,
60            Dir::Vert => self.y,
61        }
62    }
63
64    /// Snaps the x and y coordinates of this point to the nearest multiple of `grid`.
65    #[inline]
66    pub fn snap_to_grid(&self, grid: i64) -> Self {
67        self.snap_x_to_grid(grid).snap_y_to_grid(grid)
68    }
69
70    /// Snaps only the x-coordinate of this point to the nearest multiple of `grid`.
71    #[inline]
72    pub fn snap_x_to_grid(&self, grid: i64) -> Self {
73        let x = snap_to_grid(self.x, grid);
74        Self { x, y: self.y }
75    }
76
77    /// Snaps only the y-coordinate of this point to the nearest multiple of `grid`.
78    #[inline]
79    pub fn snap_y_to_grid(&self, grid: i64) -> Self {
80        let y = snap_to_grid(self.y, grid);
81        Self { x: self.x, y }
82    }
83}
84
85impl TranslateRef for Point {
86    fn translate_ref(&self, p: Point) -> Self {
87        self.translate(p)
88    }
89}
90
91impl TranslateMut for Point {
92    fn translate_mut(&mut self, p: Point) {
93        self.x += p.x;
94        self.y += p.y;
95    }
96}
97
98impl TransformRef for Point {
99    fn transform_ref(&self, trans: Transformation) -> Self {
100        self.transform(trans)
101    }
102}
103
104impl TransformMut for Point {
105    fn transform_mut(&mut self, trans: Transformation) {
106        *self = trans.mat * *self + trans.b;
107    }
108}
109
110impl std::ops::Add<Point> for Point {
111    type Output = Self;
112    fn add(self, rhs: Point) -> Self::Output {
113        Self::new(self.x + rhs.x, self.y + rhs.y)
114    }
115}
116
117impl std::ops::Add<Dims> for Point {
118    type Output = Self;
119    fn add(self, rhs: Dims) -> Self::Output {
120        Self::new(self.x + rhs.width(), self.y + rhs.height())
121    }
122}
123
124impl std::ops::AddAssign<Point> for Point {
125    fn add_assign(&mut self, rhs: Point) {
126        self.x += rhs.x;
127        self.y += rhs.y;
128    }
129}
130
131impl std::ops::AddAssign<Dims> for Point {
132    fn add_assign(&mut self, rhs: Dims) {
133        self.x += rhs.width();
134        self.y += rhs.height();
135    }
136}
137
138impl std::ops::Sub<Point> for Point {
139    type Output = Self;
140    fn sub(self, rhs: Point) -> Self::Output {
141        Self::new(self.x - rhs.x, self.y - rhs.y)
142    }
143}
144
145impl std::ops::SubAssign<Point> for Point {
146    fn sub_assign(&mut self, rhs: Point) {
147        self.x -= rhs.x;
148        self.y -= rhs.y;
149    }
150}
151
152impl std::ops::Neg for Point {
153    type Output = Self;
154    fn neg(self) -> Self::Output {
155        Self {
156            x: -self.x,
157            y: -self.y,
158        }
159    }
160}
161
162impl From<(i64, i64)> for Point {
163    fn from(value: (i64, i64)) -> Self {
164        Self {
165            x: value.0,
166            y: value.1,
167        }
168    }
169}
170
171impl Mul<Point> for Point {
172    type Output = Self;
173
174    /// Multiplies the two points element wise.
175    fn mul(self, rhs: Point) -> Self::Output {
176        Self::new(self.x * rhs.x, self.y * rhs.y)
177    }
178}
179
180impl Mul<Dims> for Point {
181    type Output = Self;
182
183    /// Multiplies the x-coordinate of the point by the dimension's width,
184    /// and the y-coordinate of the point by the dimension's height.
185    fn mul(self, rhs: Dims) -> Self::Output {
186        Self::new(self.x * rhs.w(), self.y * rhs.h())
187    }
188}