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    /// Returns a new Point with x and y coordinates swapped
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use physdes::point::Point;
103    /// let p = Point::new(1, 2);
104    /// assert_eq!(p.flip_xy(), Point::new(2, 1));
105    /// ```
106    #[inline]
107    pub fn flip_xy(&self) -> Point<T2, T1>
108    where
109        T1: Clone,
110        T2: Clone,
111    {
112        Point {
113            xcoord: self.ycoord.clone(),
114            ycoord: self.xcoord.clone(),
115        }
116    }
117
118    /// Flips according to ycoord-axis (negates x-coordinate)
119    ///
120    /// Returns a new Point with x-coordinate negated
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use physdes::point::Point;
126    /// let p = Point::new(3, 4);
127    /// assert_eq!(p.flip_y(), Point::new(-3, 4));
128    /// ```
129    #[inline]
130    pub fn flip_y(&self) -> Point<T1, T2>
131    where
132        T1: Clone + Neg<Output = T1>,
133        T2: Clone,
134    {
135        Point {
136            xcoord: -self.xcoord.clone(),
137            ycoord: self.ycoord.clone(),
138        }
139    }
140}
141
142impl<T1: std::fmt::Display, T2: std::fmt::Display> std::fmt::Display for Point<T1, T2> {
143    #[inline]
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        write!(f, "({}, {})", self.xcoord, self.ycoord)
146    }
147}
148
149impl<T1, T2, U1, U2> Overlap<Point<U1, U2>> for Point<T1, T2>
150where
151    T1: Overlap<U1>,
152    T2: Overlap<U2>,
153{
154    #[inline]
155    fn overlaps(&self, other: &Point<U1, U2>) -> bool {
156        self.xcoord.overlaps(&other.xcoord) && self.ycoord.overlaps(&other.ycoord)
157    }
158}
159
160impl<T1, T2, U1, U2> Contain<Point<U1, U2>> for Point<T1, T2>
161where
162    T1: Contain<U1>,
163    T2: Contain<U2>,
164{
165    #[inline]
166    fn contains(&self, other: &Point<U1, U2>) -> bool {
167        self.xcoord.contains(&other.xcoord) && self.ycoord.contains(&other.ycoord)
168    }
169}
170
171impl<T1, T2, U1, U2> MinDist<Point<U1, U2>> for Point<T1, T2>
172where
173    T1: MinDist<U1>,
174    T2: MinDist<U2>,
175{
176    #[inline]
177    fn min_dist_with(&self, other: &Point<U1, U2>) -> u32 {
178        self.xcoord.min_dist_with(&other.xcoord) + self.ycoord.min_dist_with(&other.ycoord)
179    }
180}
181
182impl<T1, T2> Displacement<Point<T1, T2>> for Point<T1, T2>
183where
184    T1: Displacement<T1, Output = T1>,
185    T2: Displacement<T2, Output = T2>,
186{
187    type Output = Vector2<T1, T2>;
188
189    #[inline]
190    fn displace(&self, other: &Point<T1, T2>) -> Self::Output {
191        Self::Output::new(
192            self.xcoord.displace(&other.xcoord),
193            self.ycoord.displace(&other.ycoord),
194        )
195    }
196}
197
198impl<T1, T2> Hull<Point<T1, T2>> for Point<T1, T2>
199where
200    T1: Hull<T1>,
201    T2: Hull<T2>,
202{
203    type Output = Point<T1::Output, T2::Output>;
204
205    #[inline]
206    fn hull_with(&self, other: &Point<T1, T2>) -> Self::Output {
207        Self::Output::new(
208            self.xcoord.hull_with(&other.xcoord),
209            self.ycoord.hull_with(&other.ycoord),
210        )
211    }
212}
213
214impl<T1, T2> Intersect<Point<T1, T2>> for Point<T1, T2>
215where
216    T1: Intersect<T1>,
217    T2: Intersect<T2>,
218{
219    type Output = Point<T1::Output, T2::Output>;
220
221    #[inline]
222    fn intersect_with(&self, other: &Point<T1, T2>) -> Self::Output {
223        Self::Output::new(
224            self.xcoord.intersect_with(&other.xcoord),
225            self.ycoord.intersect_with(&other.ycoord),
226        )
227    }
228}
229
230impl<T1, T2, Alpha> Enlarge<Alpha> for Point<T1, T2>
231where
232    T1: Enlarge<Alpha, Output = Interval<T1>> + Copy,
233    T2: Enlarge<Alpha, Output = Interval<T2>> + Copy,
234    Alpha: Copy,
235{
236    type Output = Point<Interval<T1>, Interval<T2>>;
237
238    fn enlarge_with(&self, alpha: Alpha) -> Self::Output {
239        Self::Output::new(
240            self.xcoord.enlarge_with(alpha),
241            self.ycoord.enlarge_with(alpha),
242        )
243    }
244}
245
246// Macro implementations for arithmetic operations
247macro_rules! forward_xf_xf_binop {
248    (impl $imp:ident, $method:ident, $output:ty) => {
249        impl<'a, 'b, T1: Clone + Num, T2: Clone + Num> $imp<&'b Vector2<T1, T2>>
250            for &'a Point<T1, T2>
251        {
252            type Output = $output;
253
254            #[inline]
255            fn $method(self, other: &Vector2<T1, T2>) -> Self::Output {
256                self.clone().$method(other.clone())
257            }
258        }
259    };
260}
261
262macro_rules! forward_xf_val_binop {
263    (impl $imp:ident, $method:ident, $output:ty) => {
264        impl<'a, T1: Clone + Num, T2: Clone + Num> $imp<Vector2<T1, T2>> for &'a Point<T1, T2> {
265            type Output = $output;
266
267            #[inline]
268            fn $method(self, other: Vector2<T1, T2>) -> Self::Output {
269                self.clone().$method(other)
270            }
271        }
272    };
273}
274
275macro_rules! forward_val_xf_binop {
276    (impl $imp:ident, $method:ident, $output:ty) => {
277        impl<'a, T1: Clone + Num, T2: Clone + Num> $imp<&'a Vector2<T1, T2>> for Point<T1, T2> {
278            type Output = $output;
279
280            #[inline]
281            fn $method(self, other: &Vector2<T1, T2>) -> Self::Output {
282                self.$method(other.clone())
283            }
284        }
285    };
286}
287
288macro_rules! forward_all_binop {
289    (impl $imp:ident, $method:ident, $output:ty) => {
290        forward_xf_xf_binop!(impl $imp, $method, $output);
291        forward_xf_val_binop!(impl $imp, $method, $output);
292        forward_val_xf_binop!(impl $imp, $method, $output);
293    };
294}
295
296forward_all_binop!(impl Add, add, Point<T1, T2>);
297
298impl<T1: Clone + Num, T2: Clone + Num> Add<Vector2<T1, T2>> for Point<T1, T2> {
299    type Output = Self;
300
301    /// Translate a point by a vector
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// use physdes::point::Point;
307    /// use physdes::vector2::Vector2;
308    ///
309    /// assert_eq!(Point::new(3, 4) + Vector2::new(5, 3), Point::new(8, 7));
310    /// assert_eq!(Point::new(3, 4) + Vector2::new(-5, -3), Point::new(-2, 1));
311    /// assert_eq!(Point::new(3, 4) + Vector2::new(5, -3), Point::new(8, 1));
312    /// assert_eq!(Point::new(3, 4) + Vector2::new(-5, 3), Point::new(-2, 7));
313    /// assert_eq!(Point::new(3, 4) + Vector2::new(0, 0), Point::new(3, 4));
314    /// assert_eq!(Point::new(3, 4) + Vector2::new(0, 5), Point::new(3, 9));
315    /// ```
316    #[inline]
317    fn add(self, other: Vector2<T1, T2>) -> Self::Output {
318        Self::Output::new(self.xcoord + other.x_, self.ycoord + other.y_)
319    }
320}
321
322forward_all_binop!(impl Sub, sub, Point<T1, T2>);
323
324impl<T1: Clone + Num, T2: Clone + Num> Sub<Vector2<T1, T2>> for Point<T1, T2> {
325    type Output = Self;
326
327    /// Translate a point by a vector (subtraction)
328    ///
329    /// # Examples
330    ///
331    /// ```
332    /// use physdes::point::Point;
333    /// use physdes::vector2::Vector2;
334    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, 3), Point::new(-2, 1));
335    /// assert_eq!(Point::new(3, 4) - Vector2::new(-5, -3), Point::new(8, 7));
336    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, -3), Point::new(-2, 7));
337    /// assert_eq!(Point::new(3, 4) - Vector2::new(-5, 3), Point::new(8, 1));
338    /// assert_eq!(Point::new(3, 4) - Vector2::new(0, 0), Point::new(3, 4));
339    /// assert_eq!(Point::new(3, 4) - Vector2::new(0, 5), Point::new(3, -1));
340    /// assert_eq!(Point::new(3, 4) - Vector2::new(5, 0), Point::new(-2, 4));
341    /// ```
342    #[inline]
343    fn sub(self, other: Vector2<T1, T2>) -> Self::Output {
344        Self::Output::new(self.xcoord - other.x_, self.ycoord - other.y_)
345    }
346}
347
348// Macro implementations for point-to-point subtraction
349impl<T1: Clone + Num, T2: Clone + Num> Sub for Point<T1, T2> {
350    type Output = Vector2<T1, T2>;
351
352    /// Calculate displacement vector between two points
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use physdes::point::Point;
358    /// use physdes::vector2::Vector2;
359    ///
360    /// assert_eq!(Point::new(3, 4) - Point::new(5, 3), Vector2::new(-2, 1));
361    /// assert_eq!(Point::new(3, 4) - Point::new(-5, -3), Vector2::new(8, 7));
362    /// assert_eq!(Point::new(3, 4) - Point::new(5, -3), Vector2::new(-2, 7));
363    /// assert_eq!(Point::new(3, 4) - Point::new(-5, 3), Vector2::new(8, 1));
364    /// assert_eq!(Point::new(3, 4) - Point::new(0, 0), Vector2::new(3, 4));
365    /// ```
366    #[inline]
367    fn sub(self, other: Self) -> Self::Output {
368        Self::Output::new(self.xcoord - other.xcoord, self.ycoord - other.ycoord)
369    }
370}
371
372// Assignment operations
373
374/// Translates the point by adding a vector to its coordinates
375impl<T1: Clone + Num + AddAssign, T2: Clone + Num + AddAssign> AddAssign<Vector2<T1, T2>>
376    for Point<T1, T2>
377{
378    #[inline]
379    fn add_assign(&mut self, other: Vector2<T1, T2>) {
380        self.xcoord += other.x_;
381        self.ycoord += other.y_;
382    }
383}
384
385/// Translates the point by subtracting a vector from its coordinates
386impl<T1: Clone + Num + SubAssign, T2: Clone + Num + SubAssign> SubAssign<Vector2<T1, T2>>
387    for Point<T1, T2>
388{
389    #[inline]
390    fn sub_assign(&mut self, other: Vector2<T1, T2>) {
391        self.xcoord -= other.x_;
392        self.ycoord -= other.y_;
393    }
394}
395
396/// Translates the point by adding a vector reference to its coordinates
397impl<'a, T1: Clone + Num + AddAssign, T2: Clone + Num + AddAssign> AddAssign<&'a Vector2<T1, T2>>
398    for Point<T1, T2>
399{
400    #[inline]
401    fn add_assign(&mut self, other: &'a Vector2<T1, T2>) {
402        self.xcoord += other.x_.clone();
403        self.ycoord += other.y_.clone();
404    }
405}
406
407/// Translates the point by subtracting a vector reference from its coordinates
408impl<'a, T1: Clone + Num + SubAssign, T2: Clone + Num + SubAssign> SubAssign<&'a Vector2<T1, T2>>
409    for Point<T1, T2>
410{
411    #[inline]
412    fn sub_assign(&mut self, other: &'a Vector2<T1, T2>) {
413        self.xcoord -= other.x_.clone();
414        self.ycoord -= other.y_.clone();
415    }
416}
417
418// Negation
419impl<T1: Clone + Num + Neg<Output = T1>, T2: Clone + Num + Neg<Output = T2>> Neg for Point<T1, T2> {
420    type Output = Self;
421
422    /// Negate a Point
423    ///
424    /// # Examples
425    ///
426    /// ```
427    /// use physdes::point::Point;
428    ///
429    /// assert_eq!(-Point::new(3, 4), Point::new(-3, -4));
430    /// assert_eq!(-Point::new(0, 0), Point::new(0, 0));
431    /// ```
432    #[inline]
433    fn neg(self) -> Self::Output {
434        Self::Output::new(-self.xcoord, -self.ycoord)
435    }
436}
437
438impl<T1: Clone + Num + Neg<Output = T1>, T2: Clone + Num + Neg<Output = T2>> Neg
439    for &Point<T1, T2>
440{
441    type Output = Point<T1, T2>;
442
443    #[inline]
444    fn neg(self) -> Self::Output {
445        -self.clone()
446    }
447}
448
449#[cfg(test)]
450pub fn hash<T: hash::Hash>(item: &T) -> u64 {
451    use std::collections::hash_map::RandomState;
452    use std::hash::{BuildHasher, Hasher};
453    let mut hasher = <RandomState as BuildHasher>::Hasher::new();
454    item.hash(&mut hasher);
455    hasher.finish()
456}
457#[cfg(test)]
458mod test {
459    #![allow(non_upper_case_globals)]
460
461    use super::*;
462    use crate::generic::{Contain, Overlap};
463    use crate::interval::Interval;
464    use std::collections::hash_map::DefaultHasher;
465    use std::hash::{Hash, Hasher};
466
467    pub const _0_0p: Point<i32, i32> = Point {
468        xcoord: 0,
469        ycoord: 0,
470    };
471    pub const _1_0p: Point<i32, i32> = Point {
472        xcoord: 1,
473        ycoord: 0,
474    };
475    pub const _1_1p: Point<i32, i32> = Point {
476        xcoord: 1,
477        ycoord: 1,
478    };
479    pub const _0_1p: Point<i32, i32> = Point {
480        xcoord: 0,
481        ycoord: 1,
482    };
483    pub const _neg1_1p: Point<i32, i32> = Point {
484        xcoord: -1,
485        ycoord: 1,
486    };
487    pub const _4_2p: Point<i32, i32> = Point {
488        xcoord: 4,
489        ycoord: 2,
490    };
491
492    fn hash<T: Hash>(item: &T) -> u64 {
493        let mut hasher = DefaultHasher::new();
494        item.hash(&mut hasher);
495        hasher.finish()
496    }
497
498    #[test]
499    fn test_construction_and_accessors() {
500        let p1 = Point::new(1, 2);
501        assert_eq!(p1.xcoord(), &1);
502        assert_eq!(p1.ycoord(), &2);
503    }
504
505    #[test]
506    fn test_comparison() {
507        let p1 = Point::new(1, 2);
508        let p2 = Point::new(1, 2);
509        let p3 = Point::new(2, 3);
510
511        assert_eq!(p1, p2);
512        assert_ne!(p1, p3);
513        assert!(p1 < p3);
514    }
515
516    #[test]
517    fn test_arithmetic_operators() {
518        let p1 = Point::new(1, 2);
519        let v = Vector2::new(1, 1);
520        let p4 = p1 + v;
521        assert_eq!(p4, Point::new(2, 3));
522
523        let mut p5 = p4;
524        p5 -= v;
525        assert_eq!(p5, p1);
526
527        let p6 = p4 - v;
528        assert_eq!(p6, p1);
529    }
530
531    #[test]
532    fn test_flip() {
533        let p1 = Point::new(1, 2);
534        let p_flipped = p1.flip_xy();
535        assert_eq!(p_flipped, Point::new(2, 1));
536
537        let p_flipped_y = p1.flip_y();
538        assert_eq!(p_flipped_y, Point::new(-1, 2));
539    }
540
541    #[test]
542    fn test_overlaps_contains_intersects_hull() {
543        let p_interval1 = Point::new(Interval::new(0, 2), Interval::new(0, 2));
544        let p_interval2 = Point::new(Interval::new(1, 3), Interval::new(1, 3));
545        let p_interval3 = Point::new(Interval::new(3, 4), Interval::new(3, 4));
546
547        assert!(p_interval1.overlaps(&p_interval2));
548        assert!(!p_interval1.overlaps(&p_interval3));
549
550        assert!(p_interval1.contains(&Point::new(1, 1)));
551        assert!(!p_interval1.contains(&Point::new(3, 3)));
552
553        let intersection = p_interval1.intersect_with(&p_interval2);
554        assert_eq!(intersection.xcoord, Interval::new(1, 2));
555        assert_eq!(intersection.ycoord, Interval::new(1, 2));
556
557        let hull = p_interval1.hull_with(&p_interval2);
558        assert_eq!(hull.xcoord, Interval::new(0, 3));
559        assert_eq!(hull.ycoord, Interval::new(0, 3));
560    }
561
562    #[test]
563    fn test_min_distance() {
564        let p_interval1 = Point::new(Interval::new(0, 2), Interval::new(0, 2));
565        let p_interval2 = Point::new(Interval::new(4, 5), Interval::new(4, 5));
566
567        let dist = p_interval1.min_dist_with(&p_interval2);
568        assert_eq!(dist, 4);
569    }
570
571    #[test]
572    fn test_consts() {
573        // check our constants are what Point::new creates
574        fn test(pt: Point<i32, i32>, x_val: i32, y_val: i32) {
575            assert_eq!(pt, Point::new(x_val, y_val));
576        }
577        test(_0_0p, 0, 0);
578        test(_1_0p, 1, 0);
579        test(_1_1p, 1, 1);
580        test(_neg1_1p, -1, 1);
581    }
582
583    #[test]
584    fn test_hash() {
585        let pt_a = Point::new(0i32, 0i32);
586        let pt_b = Point::new(1i32, 0i32);
587        let pt_c = Point::new(0i32, 1i32);
588        assert!(hash(&pt_a) != hash(&pt_b));
589        assert!(hash(&pt_b) != hash(&pt_c));
590        assert!(hash(&pt_c) != hash(&pt_a));
591    }
592
593    #[test]
594    fn test_overlap() {
595        let pt_a = Point::new(0i32, 0i32);
596        let pt_b = Point::new(1i32, 0i32);
597        assert!(!pt_a.overlaps(&pt_b));
598    }
599
600    #[test]
601    fn test_contain() {
602        let pt_a = Point::new(0i32, 0i32);
603        let pt_b = Point::new(1i32, 0i32);
604        assert!(!pt_a.contains(&pt_b));
605    }
606
607    #[test]
608    fn test_min_dist_with() {
609        let pt_a = Point::new(3i32, 5i32);
610        let pt_b = Point::new(6i32, 4i32);
611        assert_eq!(pt_a.min_dist_with(&pt_b), 4);
612    }
613
614    #[test]
615    fn test_add() {
616        let pt_a = Point::new(0i32, 0i32);
617        let pt_b = Point::new(1i32, 0i32);
618        let vec = Vector2::new(5i32, 6i32);
619        assert_eq!(pt_a, pt_a + vec - vec);
620        assert_eq!(pt_b, pt_b - vec + vec);
621    }
622
623    #[test]
624    fn test_sub() {
625        let pt_a = Point::new(0i32, 0i32);
626        let pt_b = Point::new(1i32, 0i32);
627        let vec = Vector2::new(5i32, 6i32);
628        assert_eq!(pt_a, pt_a - vec + vec);
629        assert_eq!(pt_b, pt_b + vec - vec);
630    }
631
632    #[test]
633    fn test_neg() {
634        let pt_a = Point::new(0i32, 0i32);
635        let pt_b = Point::new(1i32, 0i32);
636        let pt_c = Point::new(0i32, 1i32);
637        assert_eq!(pt_a, -(-pt_a));
638        assert_eq!(pt_b, -(-pt_b));
639        assert_eq!(pt_c, -(-pt_c));
640    }
641
642    #[test]
643    fn test_add_assign() {
644        let mut pt_a = Point::new(1i32, 0i32);
645        let pt_b = Point::new(6i32, 6i32);
646        let vec = Vector2::new(5i32, 6i32);
647        pt_a += vec;
648        assert_eq!(pt_a, pt_b);
649    }
650
651    #[test]
652    fn test_sub_assign() {
653        let mut pt_a = Point::new(1i32, 0i32);
654        let pt_b = Point::new(-4i32, -6i32);
655        let vec = Vector2::new(5i32, 6i32);
656        pt_a -= vec;
657        assert_eq!(pt_a, pt_b);
658    }
659
660    #[test]
661    fn test_neg_assign() {
662        let mut pt_a = Point::new(1i32, 0i32);
663        let pt_b = Point::new(-1i32, 0i32);
664        let pt_c = Point::new(1i32, 0i32);
665        pt_a = -pt_a;
666        assert_eq!(pt_a, pt_b);
667        pt_a = -pt_a;
668        assert_eq!(pt_a, pt_c);
669    }
670
671    #[test]
672    fn test_point() {
673        let pt_a = Point::new(4, 8);
674        let pt_b = Point::new(5, 6);
675        assert!(pt_a < pt_b);
676        assert!(pt_a <= pt_b);
677        assert_ne!(pt_b, pt_a);
678    }
679
680    #[test]
681    fn test_point2() {
682        let pt_a = Point::new(3, 4);
683        let rect = Point::new(Interval::new(3, 4), Interval::new(5, 6)); // Rectangle
684        assert!(!rect.contains(&pt_a));
685        assert!(rect.contains(&Point::new(4, 5)));
686        assert!(!rect.overlaps(&pt_a));
687        assert!(rect.overlaps(&Point::new(4, 5)));
688        assert!(rect.overlaps(&Point::new(4, 6)));
689    }
690
691    #[test]
692    fn test_transform() {
693        let mut pt_a = Point::new(3, 5);
694        let vec_b = Vector2::new(5, 7);
695        assert_eq!(pt_a + vec_b, Point::new(8, 12));
696        assert_eq!(pt_a - vec_b, Point::new(-2, -2));
697        pt_a += vec_b;
698        assert_eq!(pt_a, Point::new(8, 12));
699        pt_a -= vec_b;
700        assert_eq!(pt_a, Point::new(3, 5));
701        assert_eq!(pt_a.flip_xy(), Point::new(5, 3));
702    }
703
704    #[test]
705    fn test_displacement() {
706        let pt_a = Point::new(3, 5);
707        let pt_b = Point::new(5, 7);
708        let pt_c = Point::new(7, 8);
709        assert_eq!(pt_a.displace(&pt_b), Vector2::new(-2, -2));
710        assert_eq!(pt_a.displace(&pt_c), Vector2::new(-4, -3));
711        assert_eq!(pt_b.displace(&pt_c), Vector2::new(-2, -1));
712    }
713
714    #[test]
715    fn test_enlarge() {
716        let pt_a = Point::new(3, 5);
717        let pt_b: Point<Interval<i32>, Interval<i32>> = pt_a.enlarge_with(2);
718        assert_eq!(pt_b, Point::new(Interval::new(1, 5), Interval::new(3, 7)));
719    }
720
721    #[test]
722    fn test_displace_more_cases() {
723        let pt_a = Point::new(0, 0);
724        let pt_b = Point::new(3, 4);
725        assert_eq!(pt_a.displace(&pt_b), Vector2::new(-3, -4));
726        let pt_c = Point::new(-3, -4);
727        assert_eq!(pt_a.displace(&pt_c), Vector2::new(3, 4));
728    }
729
730    #[test]
731    fn test_hull_more_cases() {
732        let pt_a = Point::new(0, 0);
733        let pt_b = Point::new(3, 4);
734        assert_eq!(
735            pt_a.hull_with(&pt_b),
736            Point::new(Interval::new(0, 3), Interval::new(0, 4))
737        );
738        let pt_c = Point::new(-3, -4);
739        assert_eq!(
740            pt_a.hull_with(&pt_c),
741            Point::new(Interval::new(-3, 0), Interval::new(-4, 0))
742        );
743    }
744
745    #[test]
746    fn test_intersect_with_more_cases() {
747        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
748        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
749        assert_eq!(
750            p1.intersect_with(&p2),
751            Point::new(Interval::new(3, 5), Interval::new(3, 5))
752        );
753
754        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
755        assert!(p1.intersect_with(&p3).xcoord.is_invalid());
756        assert!(p1.intersect_with(&p3).ycoord.is_invalid());
757    }
758
759    #[test]
760    fn test_overlaps_more_cases() {
761        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
762        let p2 = Point::new(Interval::new(5, 8), Interval::new(5, 8));
763        assert!(p1.overlaps(&p2));
764
765        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
766        assert!(!p1.overlaps(&p3));
767    }
768
769    #[test]
770    fn test_contains_more_cases() {
771        let p1 = Point::new(Interval::new(0, 10), Interval::new(0, 10));
772        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
773        assert!(p1.contains(&p2));
774
775        let p3 = Point::new(Interval::new(3, 12), Interval::new(3, 8));
776        assert!(!p1.contains(&p3));
777    }
778
779    #[test]
780    fn test_hull() {
781        let pt_a = Point::new(3, 5);
782        let pt_b = Point::new(5, 7);
783        assert_eq!(
784            pt_a.hull_with(&pt_b),
785            Point::new(Interval::new(3, 5), Interval::new(5, 7))
786        );
787    }
788
789    #[test]
790    fn test_min_dist_with2() {
791        let pt_a = Point::new(3, 5);
792        let pt_b = Point::new(5, 7);
793        assert_eq!(pt_a.min_dist_with(&pt_b), 4);
794    }
795
796    #[test]
797    fn test_flip_xy() {
798        let pt1 = Point::new(1, 2);
799        assert_eq!(pt1.flip_xy(), Point::new(2, 1));
800    }
801
802    #[test]
803    fn test_display() {
804        let pt1 = Point::new(1, 2);
805        assert_eq!(format!("{}", pt1), "(1, 2)");
806    }
807
808    #[test]
809    fn test_displace_more() {
810        let pt_a = Point::new(3, 5);
811        let pt_b = Point::new(-5, 7);
812        let pt_c = Point::new(7, -8);
813        assert_eq!(pt_a.displace(&pt_b), Vector2::new(8, -2));
814        assert_eq!(pt_a.displace(&pt_c), Vector2::new(-4, 13));
815        assert_eq!(pt_b.displace(&pt_c), Vector2::new(-12, 15));
816    }
817
818    #[test]
819    fn test_hull_more() {
820        let pt_a = Point::new(3, 5);
821        let pt_b = Point::new(5, 7);
822        let pt_c = Point::new(-1, 9);
823        assert_eq!(
824            pt_a.hull_with(&pt_b),
825            Point::new(Interval::new(3, 5), Interval::new(5, 7))
826        );
827        assert_eq!(
828            pt_a.hull_with(&pt_c),
829            Point::new(Interval::new(-1, 3), Interval::new(5, 9))
830        );
831    }
832
833    #[test]
834    fn test_intersect_with() {
835        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
836        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
837        let p3 = Point::new(Interval::new(10, 12), Interval::new(10, 12));
838
839        assert_eq!(
840            p1.intersect_with(&p2),
841            Point::new(Interval::new(3, 5), Interval::new(3, 5))
842        );
843        assert_eq!(
844            p1.intersect_with(&p3),
845            Point::new(Interval::new(10, 5), Interval::new(10, 5))
846        );
847    }
848
849    #[test]
850    fn test_overlaps_more() {
851        let p1 = Point::new(Interval::new(0, 5), Interval::new(0, 5));
852        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
853        let p3 = Point::new(Interval::new(6, 8), Interval::new(6, 8));
854
855        assert!(p1.overlaps(&p2));
856        assert!(!p1.overlaps(&p3));
857    }
858
859    #[test]
860    fn test_contains_more() {
861        let p1 = Point::new(Interval::new(0, 10), Interval::new(0, 10));
862        let p2 = Point::new(Interval::new(3, 8), Interval::new(3, 8));
863        let p3 = Point::new(Interval::new(6, 12), Interval::new(6, 12));
864
865        assert!(p1.contains(&p2));
866        assert!(!p1.contains(&p3));
867    }
868}