Skip to main content

physdes/
point.rs

1use super::Vector2;
2use crate::generic::{Contain, Displacement, MinDist, Overlap};
3use crate::interval::{Enlarge, Hull, Intersect, Interval};
4use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
5use num_traits::Num;
6
7#[cfg(test)]
8use core::hash;
9
10/// Generic Point struct with x and y coordinates
11///
12/// This struct represents a point in 2D space with coordinates of potentially different types.
13/// It provides various operations and functionalities for working with points, such as
14/// comparison operators, arithmetic operators, flipping, overlap checking, distance calculation, and more.
15///
16/// ```svgbob
17///        y
18///        ^
19///        |
20///        |
21///   (x,y)*-----> x
22///        |
23///        |
24///        O-----> x
25/// ```
26///
27/// Properties:
28///
29/// * `xcoord`: The x-coordinate of the point
30/// * `ycoord`: The y-coordinate of the point
31///
32/// # Examples
33///
34/// ```
35/// use physdes::point::Point;
36///
37/// let p = Point::new(3, 4);
38/// assert_eq!(p.xcoord, 3);
39/// assert_eq!(p.ycoord, 4);
40/// ```
41#[derive(PartialEq, Eq, Copy, PartialOrd, Ord, Clone, Hash, Debug, Default)]
42#[repr(C)]
43#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
44pub struct Point<T1, T2> {
45    /// x portion of the Point object
46    pub xcoord: T1,
47    /// y portion of the Point object
48    pub ycoord: T2,
49}
50
51impl<T1, T2> Point<T1, T2> {
52    /// Creates a new Point with the given x and y coordinates
53    ///
54    /// # Arguments
55    ///
56    /// * `xcoord` - The x-coordinate of the point
57    /// * `ycoord` - The y-coordinate of the point
58    ///
59    /// # Examples
60    ///
61    /// ```
62    /// use physdes::point::Point;
63    /// assert_eq!(Point::new(3, 4).xcoord, 3);
64    /// assert_eq!(Point::new(3, 4).ycoord, 4);
65    /// ```
66    #[inline]
67    pub const fn new(xcoord: T1, ycoord: T2) -> Self {
68        Point { xcoord, ycoord }
69    }
70
71    /// Returns a reference to the x-coordinate
72    #[inline]
73    pub fn xcoord(&self) -> &T1 {
74        &self.xcoord
75    }
76
77    /// Returns a reference to the y-coordinate
78    #[inline]
79    pub fn ycoord(&self) -> &T2 {
80        &self.ycoord
81    }
82
83    /// Returns a mutable reference to the x-coordinate
84    #[inline]
85    pub fn xcoord_mut(&mut self) -> &mut T1 {
86        &mut self.xcoord
87    }
88
89    /// Returns a mutable reference to the y-coordinate
90    #[inline]
91    pub fn ycoord_mut(&mut self) -> &mut T2 {
92        &mut self.ycoord
93    }
94
95    /// Flips the coordinates according to xcoord-ycoord diagonal line
96    ///
97    /// $$(x, y) \to (y, x)$$
98    ///
99    /// Returns a new Point with x and y coordinates swapped
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use physdes::point::Point;
105    /// let p = Point::new(1, 2);
106    /// assert_eq!(p.flip_xy(), Point::new(2, 1));
107    /// ```
108    #[inline]
109    pub fn flip_xy(&self) -> Point<T2, T1>
110    where
111        T1: Clone,
112        T2: Clone,
113    {
114        Point {
115            xcoord: self.ycoord.clone(),
116            ycoord: self.xcoord.clone(),
117        }
118    }
119
120    /// Flips according to ycoord-axis (negates x-coordinate)
121    ///
122    /// $$(x, y) \to (-x, y)$$
123    ///
124    /// Returns a new Point with x-coordinate negated
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use physdes::point::Point;
130    /// let p = Point::new(3, 4);
131    /// assert_eq!(p.flip_y(), Point::new(-3, 4));
132    /// ```
133    #[inline]
134    pub fn flip_y(&self) -> Point<T1, T2>
135    where
136        T1: Clone + Neg<Output = T1>,
137        T2: Clone,
138    {
139        Point {
140            xcoord: -self.xcoord.clone(),
141            ycoord: self.ycoord.clone(),
142        }
143    }
144}
145
146impl<T1: std::fmt::Display, T2: std::fmt::Display> std::fmt::Display for Point<T1, T2> {
147    /// Formats the point as `(x, y)`.
148    #[inline]
149    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150        write!(f, "({}, {})", self.xcoord, self.ycoord)
151    }
152}
153
154impl<T1, T2, U1, U2> Overlap<Point<U1, U2>> for Point<T1, T2>
155where
156    T1: Overlap<U1>,
157    T2: Overlap<U2>,
158{
159    /// Points overlap iff both coordinates overlap: $x_1 \cap x_2 \land y_1 \cap y_2$
160    #[inline]
161    fn overlaps(&self, other: &Point<U1, U2>) -> bool {
162        self.xcoord.overlaps(&other.xcoord) && self.ycoord.overlaps(&other.ycoord)
163    }
164}
165
166impl<T1, T2, U1, U2> Contain<Point<U1, U2>> for Point<T1, T2>
167where
168    T1: Contain<U1>,
169    T2: Contain<U2>,
170{
171    #[inline]
172    fn contains(&self, other: &Point<U1, U2>) -> bool {
173        self.xcoord.contains(&other.xcoord) && self.ycoord.contains(&other.ycoord)
174    }
175}
176
177impl<T1, T2, U1, U2> MinDist<Point<U1, U2>> for Point<T1, T2>
178where
179    T1: MinDist<U1>,
180    T2: MinDist<U2>,
181{
182    /// Manhattan distance: $d = |x_1 - x_2| + |y_1 - y_2|$
183    #[inline]
184    fn min_dist_with(&self, other: &Point<U1, U2>) -> u32 {
185        self.xcoord.min_dist_with(&other.xcoord) + self.ycoord.min_dist_with(&other.ycoord)
186    }
187}
188
189impl<T1, T2> Displacement<Point<T1, T2>> for Point<T1, T2>
190where
191    T1: Displacement<T1, Output = T1>,
192    T2: Displacement<T2, Output = T2>,
193{
194    type Output = Vector2<T1, T2>;
195
196    /// Displacement vector between two points:
197    ///
198    /// $$\vec{d} = (x_1 - x_2,\; y_1 - y_2)$$
199    #[inline]
200    fn displace(&self, other: &Point<T1, T2>) -> Self::Output {
201        Self::Output::new(
202            self.xcoord.displace(&other.xcoord),
203            self.ycoord.displace(&other.ycoord),
204        )
205    }
206}
207
208impl<T1, T2> Hull<Point<T1, T2>> for Point<T1, T2>
209where
210    T1: Hull<T1>,
211    T2: Hull<T2>,
212{
213    type Output = Point<T1::Output, T2::Output>;
214
215    /// Component-wise hull (bounding box) of two points:
216    ///
217    /// $$\text{hull}(A,B) = (\min(A_x,B_x)..\max(A_x,B_x),\; \min(A_y,B_y)..\max(A_y,B_y))$$
218    #[inline]
219    fn hull_with(&self, other: &Point<T1, T2>) -> Self::Output {
220        Self::Output::new(
221            self.xcoord.hull_with(&other.xcoord),
222            self.ycoord.hull_with(&other.ycoord),
223        )
224    }
225}
226
227impl<T1, T2> Intersect<Point<T1, T2>> for Point<T1, T2>
228where
229    T1: Intersect<T1>,
230    T2: Intersect<T2>,
231{
232    type Output = Point<T1::Output, T2::Output>;
233
234    /// Component-wise intersection of two points (when coordinates are intervals):
235    ///
236    /// $$\text{intersect}(A,B) = (\max(A_x,B_x)..\min(A_x,B_x),\; \max(A_y,B_y)..\min(A_y,B_y))$$
237    #[inline]
238    fn intersect_with(&self, other: &Point<T1, T2>) -> Self::Output {
239        Self::Output::new(
240            self.xcoord.intersect_with(&other.xcoord),
241            self.ycoord.intersect_with(&other.ycoord),
242        )
243    }
244}
245
246impl<T1, T2, Alpha> Enlarge<Alpha> for Point<T1, T2>
247where
248    T1: Enlarge<Alpha, Output = Interval<T1>> + Copy,
249    T2: Enlarge<Alpha, Output = Interval<T2>> + Copy,
250    Alpha: Copy,
251{
252    type Output = Point<Interval<T1>, Interval<T2>>;
253
254    /// Enlarges a point to a rectangle: $x \to \[x-\alpha,\; x+\alpha\]$, $y \to \[y-\alpha,\; y+\alpha\]$
255    fn enlarge_with(&self, alpha: Alpha) -> Self::Output {
256        Self::Output::new(
257            self.xcoord.enlarge_with(alpha),
258            self.ycoord.enlarge_with(alpha),
259        )
260    }
261}
262
263// Macro implementations for arithmetic operations
264macro_rules! forward_xf_xf_binop {
265    (impl $imp:ident, $method:ident, $output:ty) => {
266        impl<'a, 'b, T1: Clone + Num, T2: Clone + Num> $imp<&'b Vector2<T1, T2>>
267            for &'a Point<T1, T2>
268        {
269            type Output = $output;
270
271            #[inline]
272            fn $method(self, other: &Vector2<T1, T2>) -> Self::Output {
273                self.clone().$method(other.clone())
274            }
275        }
276    };
277}
278
279macro_rules! forward_xf_val_binop {
280    (impl $imp:ident, $method:ident, $output:ty) => {
281        impl<'a, T1: Clone + Num, T2: Clone + Num> $imp<Vector2<T1, T2>> for &'a Point<T1, T2> {
282            type Output = $output;
283
284            #[inline]
285            fn $method(self, other: Vector2<T1, T2>) -> Self::Output {
286                self.clone().$method(other)
287            }
288        }
289    };
290}
291
292macro_rules! forward_val_xf_binop {
293    (impl $imp:ident, $method:ident, $output:ty) => {
294        impl<'a, T1: Clone + Num, T2: Clone + Num> $imp<&'a Vector2<T1, T2>> for Point<T1, T2> {
295            type Output = $output;
296
297            #[inline]
298            fn $method(self, other: &Vector2<T1, T2>) -> Self::Output {
299                self.$method(other.clone())
300            }
301        }
302    };
303}
304
305macro_rules! forward_all_binop {
306    (impl $imp:ident, $method:ident, $output:ty) => {
307        forward_xf_xf_binop!(impl $imp, $method, $output);
308        forward_xf_val_binop!(impl $imp, $method, $output);
309        forward_val_xf_binop!(impl $imp, $method, $output);
310    };
311}
312
313forward_all_binop!(impl Add, add, Point<T1, T2>);
314
315impl<T1: Clone + Num, T2: Clone + Num> Add<Vector2<T1, T2>> for Point<T1, T2> {
316    type Output = Self;
317
318    /// Translate a point by a vector
319    ///
320    /// $$P' = (x + v_x,\; y + v_y)$$
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// use physdes::point::Point;
326    /// use physdes::vector2::Vector2;
327    ///
328    /// assert_eq!(Point::new(3, 4) + Vector2::new(5, 3), Point::new(8, 7));
329    /// assert_eq!(Point::new(3, 4) + Vector2::new(-5, -3), Point::new(-2, 1));
330    /// assert_eq!(Point::new(3, 4) + Vector2::new(5, -3), Point::new(8, 1));
331    /// assert_eq!(Point::new(3, 4) + Vector2::new(-5, 3), Point::new(-2, 7));
332    /// assert_eq!(Point::new(3, 4) + Vector2::new(0, 0), Point::new(3, 4));
333    /// assert_eq!(Point::new(3, 4) + Vector2::new(0, 5), Point::new(3, 9));
334    /// ```
335    #[inline]
336    fn add(self, other: Vector2<T1, T2>) -> Self::Output {
337        Self::Output::new(self.xcoord + other.x_, self.ycoord + other.y_)
338    }
339}
340
341forward_all_binop!(impl Sub, sub, Point<T1, T2>);
342
343impl<T1: Clone + Num, T2: Clone + Num> Sub<Vector2<T1, T2>> for Point<T1, T2> {
344    type Output = Self;
345
346    /// Translate a point by a vector (subtraction)
347    ///
348    /// $$P' = (x - v_x,\; y - v_y)$$
349    ///
350    /// # Examples
351    ///
352    /// ```
353    /// use physdes::point::Point;
354    /// use physdes::vector2::Vector2;
355    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, 3), Point::new(-2, 1));
356    /// assert_eq!(Point::new(3, 4) - Vector2::new(-5, -3), Point::new(8, 7));
357    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, -3), Point::new(-2, 7));
358    /// assert_eq!(Point::new(3, 4) - Vector2::new(-5, 3), Point::new(8, 1));
359    /// assert_eq!(Point::new(3, 4) - Vector2::new(0, 0), Point::new(3, 4));
360    /// assert_eq!(Point::new(3, 4) - Vector2::new(0, 5), Point::new(3, -1));
361    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, 0), Point::new(-2, 4));
362    /// ```
363    #[inline]
364    fn sub(self, other: Vector2<T1, T2>) -> Self::Output {
365        Self::Output::new(self.xcoord - other.x_, self.ycoord - other.y_)
366    }
367}
368
369// Macro implementations for point-to-point subtraction
370impl<T1: Clone + Num, T2: Clone + Num> Sub for Point<T1, T2> {
371    type Output = Vector2<T1, T2>;
372
373    /// Calculate displacement vector between two points
374    ///
375    /// $$\vec{d} = (x_1 - x_2,\; y_1 - y_2)$$
376    ///
377    /// # Examples
378    ///
379    /// ```
380    /// use physdes::point::Point;
381    /// use physdes::vector2::Vector2;
382    ///
383    /// assert_eq!(Point::new(3, 4) - Point::new(5, 3), Vector2::new(-2, 1));
384    /// assert_eq!(Point::new(3, 4) - Point::new(-5, -3), Vector2::new(8, 7));
385    /// assert_eq!(Point::new(3, 4) - Point::new(5, -3), Vector2::new(-2, 7));
386    /// assert_eq!(Point::new(3, 4) - Point::new(-5, 3), Vector2::new(8, 1));
387    /// assert_eq!(Point::new(3, 4) - Point::new(0, 0), Vector2::new(3, 4));
388    /// ```
389    #[inline]
390    fn sub(self, other: Self) -> Self::Output {
391        Self::Output::new(self.xcoord - other.xcoord, self.ycoord - other.ycoord)
392    }
393}
394
395// Assignment operations
396
397/// Translates the point by adding a vector to its coordinates
398///
399/// $$P \mathrel{+}= (v_x, v_y) \implies (x + v_x,\; y + v_y)$$
400impl<T1: Clone + Num + AddAssign, T2: Clone + Num + AddAssign> AddAssign<Vector2<T1, T2>>
401    for Point<T1, T2>
402{
403    #[inline]
404    fn add_assign(&mut self, other: Vector2<T1, T2>) {
405        self.xcoord += other.x_;
406        self.ycoord += other.y_;
407    }
408}
409
410/// Translates the point by subtracting a vector from its coordinates
411///
412/// $$P \mathrel{-}= (v_x, v_y) \implies (x - v_x,\; y - v_y)$$
413impl<T1: Clone + Num + SubAssign, T2: Clone + Num + SubAssign> SubAssign<Vector2<T1, T2>>
414    for Point<T1, T2>
415{
416    #[inline]
417    fn sub_assign(&mut self, other: Vector2<T1, T2>) {
418        self.xcoord -= other.x_;
419        self.ycoord -= other.y_;
420    }
421}
422
423/// Translates the point by adding a vector reference to its coordinates
424impl<'a, T1: Clone + Num + AddAssign, T2: Clone + Num + AddAssign> AddAssign<&'a Vector2<T1, T2>>
425    for Point<T1, T2>
426{
427    #[inline]
428    fn add_assign(&mut self, other: &'a Vector2<T1, T2>) {
429        self.xcoord += other.x_.clone();
430        self.ycoord += other.y_.clone();
431    }
432}
433
434/// Translates the point by subtracting a vector reference from its coordinates
435impl<'a, T1: Clone + Num + SubAssign, T2: Clone + Num + SubAssign> SubAssign<&'a Vector2<T1, T2>>
436    for Point<T1, T2>
437{
438    #[inline]
439    fn sub_assign(&mut self, other: &'a Vector2<T1, T2>) {
440        self.xcoord -= other.x_.clone();
441        self.ycoord -= other.y_.clone();
442    }
443}
444
445// Negation
446impl<T1: Clone + Num + Neg<Output = T1>, T2: Clone + Num + Neg<Output = T2>> Neg for Point<T1, T2> {
447    type Output = Self;
448
449    /// Negate a Point
450    ///
451    /// $$-P = (-x,\; -y)$$
452    ///
453    /// # Examples
454    ///
455    /// ```
456    /// use physdes::point::Point;
457    ///
458    /// assert_eq!(-Point::new(3, 4), Point::new(-3, -4));
459    /// assert_eq!(-Point::new(0, 0), Point::new(0, 0));
460    /// ```
461    #[inline]
462    fn neg(self) -> Self::Output {
463        Self::Output::new(-self.xcoord, -self.ycoord)
464    }
465}
466
467impl<T1: Clone + Num + Neg<Output = T1>, T2: Clone + Num + Neg<Output = T2>> Neg
468    for &Point<T1, T2>
469{
470    type Output = Point<T1, T2>;
471
472    #[inline]
473    fn neg(self) -> Self::Output {
474        -self.clone()
475    }
476}
477
478impl Point<Interval<i32>, Interval<i32>> {
479    /// Returns the point on this rectangle that is nearest to `other`.
480    /// Clips each coordinate to the interval bounds:
481    ///
482    /// $$x' = \text{clip}(x,\; lb_x,\; ub_x), \quad y' = \text{clip}(y,\; lb_y,\; ub_y)$$
483    pub fn nearest_to(&self, other: &Point<i32, i32>) -> Point<i32, i32> {
484        Point::new(
485            self.xcoord.lb.max(other.xcoord.min(self.xcoord.ub)),
486            self.ycoord.lb.max(other.ycoord.min(self.ycoord.ub)),
487        )
488    }
489
490    /// Checks if this rectangle blocks the path represented by `other` rectangle.
491    /// A rectangle `self` blocks `other` if:
492    ///   self.x contains other.x AND other.y contains self.y
493    ///   OR
494    ///   self.y contains other.y AND other.x contains self.x
495    /// This matches the Python `blocks` method semantics and is distinct from
496    /// simple rectangle overlap — it catches paths that must cross the keepout
497    /// regardless of L-shape choice.
498    pub fn blocks(&self, other: &Self) -> bool {
499        let x_contain = self.xcoord.lb <= other.xcoord.lb && self.xcoord.ub >= other.xcoord.ub;
500        let y_contain = self.ycoord.lb <= other.ycoord.lb && self.ycoord.ub >= other.ycoord.ub;
501        let other_x_contain =
502            other.xcoord.lb <= self.xcoord.lb && other.xcoord.ub >= self.xcoord.ub;
503        let other_y_contain =
504            other.ycoord.lb <= self.ycoord.lb && other.ycoord.ub >= self.ycoord.ub;
505        (x_contain && other_y_contain) || (y_contain && other_x_contain)
506    }
507}
508
509#[cfg(test)]
510pub fn hash<T: hash::Hash>(item: &T) -> u64 {
511    use std::collections::hash_map::RandomState;
512    use std::hash::{BuildHasher, Hasher};
513    let mut hasher = <RandomState as BuildHasher>::Hasher::new();
514    item.hash(&mut hasher);
515    hasher.finish()
516}
517#[cfg(test)]
518mod test {
519    #![allow(non_upper_case_globals)]
520
521    use super::*;
522    use crate::generic::{Contain, Overlap};
523    use crate::interval::Interval;
524    use std::collections::hash_map::DefaultHasher;
525    use std::hash::{Hash, Hasher};
526
527    pub const _0_0p: Point<i32, i32> = Point {
528        xcoord: 0,
529        ycoord: 0,
530    };
531    pub const _1_0p: Point<i32, i32> = Point {
532        xcoord: 1,
533        ycoord: 0,
534    };
535    pub const _1_1p: Point<i32, i32> = Point {
536        xcoord: 1,
537        ycoord: 1,
538    };
539    pub const _0_1p: Point<i32, i32> = Point {
540        xcoord: 0,
541        ycoord: 1,
542    };
543    pub const _neg1_1p: Point<i32, i32> = Point {
544        xcoord: -1,
545        ycoord: 1,
546    };
547    pub const _4_2p: Point<i32, i32> = Point {
548        xcoord: 4,
549        ycoord: 2,
550    };
551
552    fn hash<T: Hash>(item: &T) -> u64 {
553        let mut hasher = DefaultHasher::new();
554        item.hash(&mut hasher);
555        hasher.finish()
556    }
557
558    #[test]
559    fn test_construction_and_accessors() {
560        let p1 = Point::new(1, 2);
561        assert_eq!(p1.xcoord(), &1);
562        assert_eq!(p1.ycoord(), &2);
563    }
564
565    #[test]
566    fn test_comparison() {
567        let p1 = Point::new(1, 2);
568        let p2 = Point::new(1, 2);
569        let p3 = Point::new(2, 3);
570
571        assert_eq!(p1, p2);
572        assert_ne!(p1, p3);
573        assert!(p1 < p3);
574    }
575
576    #[test]
577    fn test_arithmetic_operators() {
578        let p1 = Point::new(1, 2);
579        let v = Vector2::new(1, 1);
580        let p4 = p1 + v;
581        assert_eq!(p4, Point::new(2, 3));
582
583        let mut p5 = p4;
584        p5 -= v;
585        assert_eq!(p5, p1);
586
587        let p6 = p4 - v;
588        assert_eq!(p6, p1);
589    }
590
591    #[test]
592    fn test_flip() {
593        let p1 = Point::new(1, 2);
594        let p_flipped = p1.flip_xy();
595        assert_eq!(p_flipped, Point::new(2, 1));
596
597        let p_flipped_y = p1.flip_y();
598        assert_eq!(p_flipped_y, Point::new(-1, 2));
599    }
600
601    #[test]
602    fn test_overlaps_contains_intersects_hull() {
603        let p_interval1 = Point::new(Interval::new(0, 2), Interval::new(0, 2));
604        let p_interval2 = Point::new(Interval::new(1, 3), Interval::new(1, 3));
605        let p_interval3 = Point::new(Interval::new(3, 4), Interval::new(3, 4));
606
607        assert!(p_interval1.overlaps(&p_interval2));
608        assert!(!p_interval1.overlaps(&p_interval3));
609
610        assert!(p_interval1.contains(&Point::new(1, 1)));
611        assert!(!p_interval1.contains(&Point::new(3, 3)));
612
613        let intersection = p_interval1.intersect_with(&p_interval2);
614        assert_eq!(intersection.xcoord, Interval::new(1, 2));
615        assert_eq!(intersection.ycoord, Interval::new(1, 2));
616
617        let hull = p_interval1.hull_with(&p_interval2);
618        assert_eq!(hull.xcoord, Interval::new(0, 3));
619        assert_eq!(hull.ycoord, Interval::new(0, 3));
620    }
621
622    #[test]
623    fn test_min_distance() {
624        let p_interval1 = Point::new(Interval::new(0, 2), Interval::new(0, 2));
625        let p_interval2 = Point::new(Interval::new(4, 5), Interval::new(4, 5));
626
627        let dist = p_interval1.min_dist_with(&p_interval2);
628        assert_eq!(dist, 4);
629    }
630
631    #[test]
632    fn test_consts() {
633        // check our constants are what Point::new creates
634        fn test(pt: Point<i32, i32>, x_val: i32, y_val: i32) {
635            assert_eq!(pt, Point::new(x_val, y_val));
636        }
637        test(_0_0p, 0, 0);
638        test(_1_0p, 1, 0);
639        test(_1_1p, 1, 1);
640        test(_neg1_1p, -1, 1);
641    }
642
643    #[test]
644    fn test_hash() {
645        let pt_a = Point::new(0i32, 0i32);
646        let pt_b = Point::new(1i32, 0i32);
647        let pt_c = Point::new(0i32, 1i32);
648        assert!(hash(&pt_a) != hash(&pt_b));
649        assert!(hash(&pt_b) != hash(&pt_c));
650        assert!(hash(&pt_c) != hash(&pt_a));
651    }
652
653    #[test]
654    fn test_overlap() {
655        let pt_a = Point::new(0i32, 0i32);
656        let pt_b = Point::new(1i32, 0i32);
657        assert!(!pt_a.overlaps(&pt_b));
658    }
659
660    #[test]
661    fn test_contain() {
662        let pt_a = Point::new(0i32, 0i32);
663        let pt_b = Point::new(1i32, 0i32);
664        assert!(!pt_a.contains(&pt_b));
665    }
666
667    #[test]
668    fn test_min_dist_with() {
669        let pt_a = Point::new(3i32, 5i32);
670        let pt_b = Point::new(6i32, 4i32);
671        assert_eq!(pt_a.min_dist_with(&pt_b), 4);
672    }
673
674    #[test]
675    fn test_add() {
676        let pt_a = Point::new(0i32, 0i32);
677        let pt_b = Point::new(1i32, 0i32);
678        let vec = Vector2::new(5i32, 6i32);
679        assert_eq!(pt_a, pt_a + vec - vec);
680        assert_eq!(pt_b, pt_b - vec + vec);
681    }
682
683    #[test]
684    fn test_sub() {
685        let pt_a = Point::new(0i32, 0i32);
686        let pt_b = Point::new(1i32, 0i32);
687        let vec = Vector2::new(5i32, 6i32);
688        assert_eq!(pt_a, pt_a - vec + vec);
689        assert_eq!(pt_b, pt_b + vec - vec);
690    }
691
692    #[test]
693    fn test_neg() {
694        let pt_a = Point::new(0i32, 0i32);
695        let pt_b = Point::new(1i32, 0i32);
696        let pt_c = Point::new(0i32, 1i32);
697        assert_eq!(pt_a, -(-pt_a));
698        assert_eq!(pt_b, -(-pt_b));
699        assert_eq!(pt_c, -(-pt_c));
700    }
701
702    #[test]
703    fn test_add_assign() {
704        let mut pt_a = Point::new(1i32, 0i32);
705        let pt_b = Point::new(6i32, 6i32);
706        let vec = Vector2::new(5i32, 6i32);
707        pt_a += vec;
708        assert_eq!(pt_a, pt_b);
709    }
710
711    #[test]
712    fn test_sub_assign() {
713        let mut pt_a = Point::new(1i32, 0i32);
714        let pt_b = Point::new(-4i32, -6i32);
715        let vec = Vector2::new(5i32, 6i32);
716        pt_a -= vec;
717        assert_eq!(pt_a, pt_b);
718    }
719
720    #[test]
721    fn test_neg_assign() {
722        let mut pt_a = Point::new(1i32, 0i32);
723        let pt_b = Point::new(-1i32, 0i32);
724        let pt_c = Point::new(1i32, 0i32);
725        pt_a = -pt_a;
726        assert_eq!(pt_a, pt_b);
727        pt_a = -pt_a;
728        assert_eq!(pt_a, pt_c);
729    }
730
731    #[test]
732    fn test_point() {
733        let pt_a = Point::new(4, 8);
734        let pt_b = Point::new(5, 6);
735        assert!(pt_a < pt_b);
736        assert!(pt_a <= pt_b);
737        assert_ne!(pt_b, pt_a);
738    }
739
740    #[test]
741    fn test_point2() {
742        let pt_a = Point::new(3, 4);
743        let rect = Point::new(Interval::new(3, 4), Interval::new(5, 6)); // Rectangle
744        assert!(!rect.contains(&pt_a));
745        assert!(rect.contains(&Point::new(4, 5)));
746        assert!(!rect.overlaps(&pt_a));
747        assert!(rect.overlaps(&Point::new(4, 5)));
748        assert!(rect.overlaps(&Point::new(4, 6)));
749    }
750
751    #[test]
752    fn test_transform() {
753        let mut pt_a = Point::new(3, 5);
754        let vec_b = Vector2::new(5, 7);
755        assert_eq!(pt_a + vec_b, Point::new(8, 12));
756        assert_eq!(pt_a - vec_b, Point::new(-2, -2));
757        pt_a += vec_b;
758        assert_eq!(pt_a, Point::new(8, 12));
759        pt_a -= vec_b;
760        assert_eq!(pt_a, Point::new(3, 5));
761        assert_eq!(pt_a.flip_xy(), Point::new(5, 3));
762    }
763
764    #[test]
765    fn test_displacement() {
766        let pt_a = Point::new(3, 5);
767        let pt_b = Point::new(5, 7);
768        let pt_c = Point::new(7, 8);
769        assert_eq!(pt_a.displace(&pt_b), Vector2::new(-2, -2));
770        assert_eq!(pt_a.displace(&pt_c), Vector2::new(-4, -3));
771        assert_eq!(pt_b.displace(&pt_c), Vector2::new(-2, -1));
772    }
773
774    #[test]
775    fn test_enlarge() {
776        let pt_a = Point::new(3, 5);
777        let pt_b: Point<Interval<i32>, Interval<i32>> = pt_a.enlarge_with(2);
778        assert_eq!(pt_b, Point::new(Interval::new(1, 5), Interval::new(3, 7)));
779    }
780
781    #[test]
782    fn test_displace_more_cases() {
783        let pt_a = Point::new(0, 0);
784        let pt_b = Point::new(3, 4);
785        assert_eq!(pt_a.displace(&pt_b), Vector2::new(-3, -4));
786        let pt_c = Point::new(-3, -4);
787        assert_eq!(pt_a.displace(&pt_c), Vector2::new(3, 4));
788    }
789
790    #[test]
791    fn test_hull_more_cases() {
792        let pt_a = Point::new(0, 0);
793        let pt_b = Point::new(3, 4);
794        assert_eq!(
795            pt_a.hull_with(&pt_b),
796            Point::new(Interval::new(0, 3), Interval::new(0, 4))
797        );
798        let pt_c = Point::new(-3, -4);
799        assert_eq!(
800            pt_a.hull_with(&pt_c),
801            Point::new(Interval::new(-3, 0), Interval::new(-4, 0))
802        );
803    }
804
805    #[test]
806    fn test_intersect_with_more_cases() {
807        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
808        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
809        assert_eq!(
810            p1.intersect_with(&p2),
811            Point::new(Interval::new(3, 5), Interval::new(3, 5))
812        );
813
814        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
815        assert!(p1.intersect_with(&p3).xcoord.is_invalid());
816        assert!(p1.intersect_with(&p3).ycoord.is_invalid());
817    }
818
819    #[test]
820    fn test_overlaps_more_cases() {
821        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
822        let p2 = Point::new(Interval::new(5, 8), Interval::new(5, 8));
823        assert!(p1.overlaps(&p2));
824
825        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
826        assert!(!p1.overlaps(&p3));
827    }
828
829    #[test]
830    fn test_contains_more_cases() {
831        let p1 = Point::new(Interval::new(0, 10), Interval::new(0, 10));
832        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
833        assert!(p1.contains(&p2));
834
835        let p3 = Point::new(Interval::new(3, 12), Interval::new(3, 8));
836        assert!(!p1.contains(&p3));
837    }
838
839    #[test]
840    fn test_hull() {
841        let pt_a = Point::new(3, 5);
842        let pt_b = Point::new(5, 7);
843        assert_eq!(
844            pt_a.hull_with(&pt_b),
845            Point::new(Interval::new(3, 5), Interval::new(5, 7))
846        );
847    }
848
849    #[test]
850    fn test_min_dist_with2() {
851        let pt_a = Point::new(3, 5);
852        let pt_b = Point::new(5, 7);
853        assert_eq!(pt_a.min_dist_with(&pt_b), 4);
854    }
855
856    #[test]
857    #[allow(clippy::op_ref, clippy::clone_on_copy)]
858    fn test_ref_operators() {
859        let pt = Point::new(1, 2);
860        let vec = Vector2::new(3, 4);
861
862        assert_eq!(&pt + &vec, Point::new(4, 6));
863        assert_eq!(&pt - &vec, Point::new(-2, -2));
864        assert_eq!(&pt + vec.clone(), Point::new(4, 6));
865        assert_eq!(&pt - vec.clone(), Point::new(-2, -2));
866        assert_eq!(pt.clone() + &vec, Point::new(4, 6));
867        assert_eq!(pt.clone() - &vec, Point::new(-2, -2));
868    }
869
870    #[test]
871    fn test_display() {
872        let pt1 = Point::new(1, 2);
873        assert_eq!(format!("{}", pt1), "(1, 2)");
874    }
875
876    #[test]
877    fn test_displace_more() {
878        let pt_a = Point::new(3, 5);
879        let pt_b = Point::new(-5, 7);
880        let pt_c = Point::new(7, -8);
881        assert_eq!(pt_a.displace(&pt_b), Vector2::new(8, -2));
882        assert_eq!(pt_a.displace(&pt_c), Vector2::new(-4, 13));
883        assert_eq!(pt_b.displace(&pt_c), Vector2::new(-12, 15));
884    }
885
886    #[test]
887    fn test_hull_more() {
888        let pt_a = Point::new(3, 5);
889        let pt_b = Point::new(5, 7);
890        let pt_c = Point::new(-1, 9);
891        assert_eq!(
892            pt_a.hull_with(&pt_b),
893            Point::new(Interval::new(3, 5), Interval::new(5, 7))
894        );
895        assert_eq!(
896            pt_a.hull_with(&pt_c),
897            Point::new(Interval::new(-1, 3), Interval::new(5, 9))
898        );
899    }
900
901    #[test]
902    fn test_intersect_with() {
903        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
904        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
905        let p3 = Point::new(Interval::new(10, 12), Interval::new(10, 12));
906
907        assert_eq!(
908            p1.intersect_with(&p2),
909            Point::new(Interval::new(3, 5), Interval::new(3, 5))
910        );
911        assert_eq!(
912            p1.intersect_with(&p3),
913            Point::new(Interval::new(10, 5), Interval::new(10, 5))
914        );
915    }
916
917    #[test]
918    fn test_overlaps_more() {
919        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
920        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
921        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
922
923        assert!(p1.overlaps(&p2));
924        assert!(!p1.overlaps(&p3));
925    }
926
927    #[test]
928    fn test_contains_more() {
929        let p1 = Point::new(Interval::new(0, 10), Interval::new(0, 10));
930        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
931        let p3 = Point::new(Interval::new(6, 12), Interval::new(6, 12));
932
933        assert!(p1.contains(&p2));
934        assert!(!p1.contains(&p3));
935    }
936
937    #[test]
938    fn test_xcoord_mut() {
939        let mut pt = Point::new(1, 2);
940        *pt.xcoord_mut() = 5;
941        assert_eq!(pt.xcoord, 5);
942    }
943
944    #[test]
945    fn test_ycoord_mut() {
946        let mut pt = Point::new(1, 2);
947        *pt.ycoord_mut() = 7;
948        assert_eq!(pt.ycoord, 7);
949    }
950
951    #[test]
952    fn test_neg_ref() {
953        let pt = Point::new(1, 2);
954        assert_eq!(-&pt, Point::new(-1, -2));
955
956        let pt2 = Point::new(-3, 4);
957        assert_eq!(-&pt2, Point::new(3, -4));
958    }
959
960    #[test]
961    fn test_add_assign_ref() {
962        let mut pt = Point::new(1, 2);
963        let vec = Vector2::new(3, 4);
964        pt += &vec;
965        assert_eq!(pt, Point::new(4, 6));
966
967        pt -= &vec;
968        assert_eq!(pt, Point::new(1, 2));
969    }
970}