1use std::fmt;
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5use std::str::FromStr;
6
7use crate::utilities::math_utilities::MathUtilities;
8use crate::utilities::span_helpers::InvariantF64;
9use crate::utilities::{FormatError, SpanStringTokenizer};
10use crate::{Matrix, Vector};
11
12#[derive(Clone, Copy, Debug, PartialEq, Default)]
14pub struct Point {
15 pub x: f64,
17 pub y: f64,
19}
20
21impl Point {
22 #[inline]
24 pub const fn new(x: f64, y: f64) -> Self {
25 Self { x, y }
26 }
27
28 #[inline]
30 pub fn distance(value1: Point, value2: Point) -> f64 {
31 let distance_squared = ((value2.x - value1.x) * (value2.x - value1.x))
32 + ((value2.y - value1.y) * (value2.y - value1.y));
33 distance_squared.sqrt()
34 }
35
36 pub fn parse(s: &str) -> Result<Self, FormatError> {
38 SpanStringTokenizer::with_message(s, "Invalid Point.")
39 .scope(|t| Ok(Point::new(t.read_double()?, t.read_double()?)))
40 }
41
42 #[inline]
45 pub fn equals(&self, other: Point) -> bool {
46 self.x == other.x && self.y == other.y
47 }
48
49 #[inline]
52 pub fn nearly_equals(&self, other: Point) -> bool {
53 MathUtilities::are_close(self.x, other.x) && MathUtilities::are_close(self.y, other.y)
54 }
55
56 #[inline]
58 pub fn transform(&self, transform: Matrix) -> Point {
59 transform.transform(*self)
60 }
61
62 #[inline]
64 pub const fn with_x(&self, x: f64) -> Point {
65 Point::new(x, self.y)
66 }
67
68 #[inline]
70 pub const fn with_y(&self, y: f64) -> Point {
71 Point::new(self.x, y)
72 }
73
74 #[inline]
76 pub const fn deconstruct(&self) -> (f64, f64) {
77 (self.x, self.y)
78 }
79}
80
81impl From<Point> for Vector {
83 #[inline]
84 fn from(p: Point) -> Vector {
85 Vector::new(p.x, p.y)
86 }
87}
88
89impl From<Point> for (f64, f64) {
90 #[inline]
91 fn from(p: Point) -> Self {
92 (p.x, p.y)
93 }
94}
95
96impl Neg for Point {
97 type Output = Point;
98 #[inline]
99 fn neg(self) -> Point {
100 Point::new(-self.x, -self.y)
101 }
102}
103
104impl Add for Point {
105 type Output = Point;
106 #[inline]
107 fn add(self, b: Point) -> Point {
108 Point::new(self.x + b.x, self.y + b.y)
109 }
110}
111
112impl Add<Vector> for Point {
113 type Output = Point;
114 #[inline]
115 fn add(self, b: Vector) -> Point {
116 Point::new(self.x + b.x, self.y + b.y)
117 }
118}
119
120impl Sub for Point {
121 type Output = Point;
122 #[inline]
123 fn sub(self, b: Point) -> Point {
124 Point::new(self.x - b.x, self.y - b.y)
125 }
126}
127
128impl Sub<Vector> for Point {
129 type Output = Point;
130 #[inline]
131 fn sub(self, b: Vector) -> Point {
132 Point::new(self.x - b.x, self.y - b.y)
133 }
134}
135
136impl Mul<f64> for Point {
137 type Output = Point;
138 #[inline]
139 fn mul(self, k: f64) -> Point {
140 Point::new(self.x * k, self.y * k)
141 }
142}
143
144impl Mul<Point> for f64 {
145 type Output = Point;
146 #[inline]
147 fn mul(self, p: Point) -> Point {
148 Point::new(p.x * self, p.y * self)
149 }
150}
151
152impl Div<f64> for Point {
153 type Output = Point;
154 #[inline]
155 fn div(self, k: f64) -> Point {
156 Point::new(self.x / k, self.y / k)
157 }
158}
159
160impl Mul<Matrix> for Point {
162 type Output = Point;
163 #[inline]
164 fn mul(self, matrix: Matrix) -> Point {
165 matrix.transform(self)
166 }
167}
168
169impl AddAssign for Point {
170 #[inline]
171 fn add_assign(&mut self, b: Point) {
172 *self = *self + b;
173 }
174}
175
176impl AddAssign<Vector> for Point {
177 #[inline]
178 fn add_assign(&mut self, b: Vector) {
179 *self = *self + b;
180 }
181}
182
183impl SubAssign for Point {
184 #[inline]
185 fn sub_assign(&mut self, b: Point) {
186 *self = *self - b;
187 }
188}
189
190impl SubAssign<Vector> for Point {
191 #[inline]
192 fn sub_assign(&mut self, b: Vector) {
193 *self = *self - b;
194 }
195}
196
197impl MulAssign<f64> for Point {
198 #[inline]
199 fn mul_assign(&mut self, k: f64) {
200 *self = *self * k;
201 }
202}
203
204impl DivAssign<f64> for Point {
205 #[inline]
206 fn div_assign(&mut self, k: f64) {
207 *self = *self / k;
208 }
209}
210
211impl MulAssign<Matrix> for Point {
212 #[inline]
213 fn mul_assign(&mut self, matrix: Matrix) {
214 *self = *self * matrix;
215 }
216}
217
218impl FromStr for Point {
219 type Err = FormatError;
220 #[inline]
221 fn from_str(s: &str) -> Result<Self, FormatError> {
222 Point::parse(s)
223 }
224}
225
226impl fmt::Display for Point {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 write!(f, "{}, {}", InvariantF64(self.x), InvariantF64(self.y))
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
237
238 #[test]
239 fn parse_and_display_round_trip() {
240 assert_eq!(Point::parse("1.5, -2").unwrap(), Point::new(1.5, -2.0));
241 assert_eq!("3 4".parse::<Point>().unwrap(), Point::new(3.0, 4.0));
242 assert_eq!(Point::new(1.5, -2.0).to_string(), "1.5, -2");
243 assert_eq!(Point::parse("1").unwrap_err().message(), "Invalid Point.");
244 assert!(Point::parse("1,2,3").is_err());
245 assert!(Point::parse("1,,2").is_err());
246 assert!(Point::parse("").is_err());
247 }
248
249 #[test]
250 fn operators() {
251 let p = Point::new(1.0, 2.0);
252 assert_eq!(-p, Point::new(-1.0, -2.0));
253 assert_eq!(p + Point::new(1.0, 1.0), Point::new(2.0, 3.0));
254 assert_eq!(p + Vector::new(1.0, 1.0), Point::new(2.0, 3.0));
255 assert_eq!(p - Point::new(1.0, 1.0), Point::new(0.0, 1.0));
256 assert_eq!(p - Vector::new(1.0, 1.0), Point::new(0.0, 1.0));
257 assert_eq!(p * 2.0, Point::new(2.0, 4.0));
258 assert_eq!(2.0 * p, Point::new(2.0, 4.0));
259 assert_eq!(p / 2.0, Point::new(0.5, 1.0));
260 assert_eq!(
261 p * Matrix::create_translation(1.0, 1.0),
262 Point::new(2.0, 3.0)
263 );
264 assert_eq!(Vector::from(p), Vector::new(1.0, 2.0));
265 assert_eq!(
266 Point::distance(Point::new(0.0, 0.0), Point::new(3.0, 4.0)),
267 5.0
268 );
269 }
270
271 #[test]
272 fn equality_is_exact_and_nearly_equals_is_tolerant() {
273 let a = Point::new(0.1 + 0.2, 1.0);
274 let b = Point::new(0.3, 1.0);
275 assert_ne!(a, b);
276 assert!(a.nearly_equals(b));
277 assert_ne!(Point::new(f64::NAN, 0.0), Point::new(f64::NAN, 0.0));
278 }
279}