geo/algorithm/sweep/
point.rs

1use std::{cmp::Ordering, ops::Deref};
2
3use geo_types::Coord;
4
5use crate::GeoNum;
6
7/// A lexicographically ordered point.
8///
9/// A wrapper around [`Coord`] to order the point by `x`, and then by `y`.
10/// Implements `Ord` and `Eq`, allowing usage in ordered collections such as
11/// `BinaryHeap`.
12///
13/// Note that the scalar type `T` is only required to implement `PartialOrd`.
14/// Thus, it is a logical error to construct this struct unless the coords are
15/// guaranteed to be orderable.
16#[derive(PartialEq, Clone, Copy)]
17pub struct SweepPoint<T: GeoNum>(Coord<T>);
18
19impl<T: GeoNum> std::fmt::Debug for SweepPoint<T> {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.debug_tuple("SPt")
22            .field(&self.0.x)
23            .field(&self.0.y)
24            .finish()
25    }
26}
27
28/// Implement lexicographic ordering by `x` and then by `y`
29/// coordinate.
30impl<T: GeoNum> PartialOrd for SweepPoint<T> {
31    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
32        match self.0.x.partial_cmp(&other.0.x) {
33            Some(Ordering::Equal) => self.0.y.partial_cmp(&other.0.y),
34            o => o,
35        }
36    }
37}
38
39/// Derive `Ord` from `PartialOrd` and expect to not fail.
40impl<T: GeoNum> Ord for SweepPoint<T> {
41    fn cmp(&self, other: &Self) -> Ordering {
42        self.partial_cmp(other).unwrap()
43    }
44}
45
46/// We derive `Eq` manually to not require `T: Eq`.
47impl<T: GeoNum> Eq for SweepPoint<T> {}
48
49/// Conversion from type that can be converted to a `Coord`.
50impl<T: GeoNum, X: Into<Coord<T>>> From<X> for SweepPoint<T> {
51    fn from(pt: X) -> Self {
52        SweepPoint(pt.into())
53    }
54}
55
56impl<T: GeoNum> Deref for SweepPoint<T> {
57    type Target = Coord<T>;
58
59    fn deref(&self) -> &Self::Target {
60        &self.0
61    }
62}
63
64// Note: We keep it immutable for now, for better hygeine.
65// impl<T: GeoNum> DerefMut for SweepPoint<T> {
66//     fn deref_mut(&mut self) -> &mut Self::Target {
67//         &mut self.0
68//     }
69// }
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_sweep_point_ordering() {
77        let p1 = SweepPoint::from(Coord { x: 0., y: 0. });
78        let p2 = SweepPoint::from(Coord { x: 1., y: 0. });
79        let p3 = SweepPoint::from(Coord { x: 1., y: 1. });
80        let p4 = SweepPoint::from(Coord { x: 1., y: 1. });
81
82        assert!(p1 < p2);
83        assert!(p1 < p3);
84        assert!(p2 < p3);
85        assert!(p3 <= p4);
86    }
87}