Skip to main content

rstared/rstar/
geo_types.rs

1//! Support for types from [`geo-types`](https://crates.io/crates/geo-types).
2//!
3//! Gated behind the `geo` feature. These impls live here because `rstar` is
4//! vendored inside `rstared`; the crates.io `geo-types` `rstar_0_*` features
5//! target a different `rstar` crate and cannot apply to these types.
6
7use crate::rstar::primitives::Line as RstarLine;
8use crate::rstar::{AABB, Envelope, Point as RTreePoint, PointDistance, RTreeNum, RTreeObject};
9
10use geo_types::{Coord, CoordNum, Line, LineString, Point, Polygon, Rect};
11
12impl<T> RTreePoint for Coord<T>
13where
14    T: CoordNum + RTreeNum,
15{
16    type Scalar = T;
17
18    const DIMENSIONS: usize = 2;
19
20    fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
21        Coord {
22            x: generator(0),
23            y: generator(1),
24        }
25    }
26
27    fn nth(&self, index: usize) -> Self::Scalar {
28        match index {
29            0 => self.x,
30            1 => self.y,
31            _ => unreachable!(),
32        }
33    }
34
35    fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
36        match index {
37            0 => &mut self.x,
38            1 => &mut self.y,
39            _ => unreachable!(),
40        }
41    }
42}
43
44impl<T> RTreePoint for Point<T>
45where
46    T: CoordNum + RTreeNum,
47{
48    type Scalar = T;
49
50    const DIMENSIONS: usize = 2;
51
52    fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
53        Point::new(generator(0), generator(1))
54    }
55
56    fn nth(&self, index: usize) -> Self::Scalar {
57        match index {
58            0 => self.x(),
59            1 => self.y(),
60            _ => unreachable!(),
61        }
62    }
63
64    fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
65        match index {
66            0 => &mut self.0.x,
67            1 => &mut self.0.y,
68            _ => unreachable!(),
69        }
70    }
71}
72
73impl<T> RTreeObject for Line<T>
74where
75    T: CoordNum + RTreeNum,
76{
77    type Envelope = AABB<Point<T>>;
78
79    fn envelope(&self) -> Self::Envelope {
80        AABB::from_corners(self.start_point(), self.end_point())
81    }
82}
83
84impl<T> PointDistance for Line<T>
85where
86    T: CoordNum + RTreeNum,
87{
88    fn distance_2(&self, point: &Point<T>) -> T {
89        RstarLine::new(self.start_point(), self.end_point()).distance_2(point)
90    }
91}
92
93impl<T> RTreeObject for LineString<T>
94where
95    T: CoordNum + RTreeNum,
96{
97    type Envelope = AABB<Point<T>>;
98
99    fn envelope(&self) -> Self::Envelope {
100        let mut iter = self.points();
101
102        let Some(first) = iter.next() else {
103            return AABB::from_corners(
104                Point::new(T::MIN_EXTENDED, T::MIN_EXTENDED),
105                Point::new(T::MAX_EXTENDED, T::MAX_EXTENDED),
106            );
107        };
108
109        let mut result = AABB::from_point(first);
110
111        for point in iter {
112            result.merge(&AABB::from_point(point));
113        }
114
115        result
116    }
117}
118
119impl<T> PointDistance for LineString<T>
120where
121    T: CoordNum + RTreeNum,
122{
123    fn distance_2(&self, point: &Point<T>) -> T {
124        if self.0.is_empty() {
125            return <T as numlike::elem::Zero>::zero();
126        }
127
128        self.lines()
129            .map(|line| RstarLine::new(line.start_point(), line.end_point()).distance_2(point))
130            .fold(T::MAX_EXTENDED, |accum, distance| {
131                if distance < accum { distance } else { accum }
132            })
133    }
134}
135
136impl<T> RTreeObject for Polygon<T>
137where
138    T: CoordNum + RTreeNum,
139{
140    type Envelope = AABB<Point<T>>;
141
142    fn envelope(&self) -> Self::Envelope {
143        self.exterior().envelope()
144    }
145}
146
147impl<T> RTreeObject for Rect<T>
148where
149    T: CoordNum + RTreeNum,
150{
151    type Envelope = AABB<Point<T>>;
152
153    fn envelope(&self) -> Self::Envelope {
154        AABB::from_corners(self.min().into(), self.max().into())
155    }
156}
157
158impl<T> PointDistance for Rect<T>
159where
160    T: CoordNum + RTreeNum,
161{
162    fn distance_2(&self, point: &Point<T>) -> T {
163        self.envelope().distance_2(point)
164    }
165}