geo/algorithm/
densify_haversine.rs

1use num_traits::FromPrimitive;
2
3use crate::line_measures::Haversine;
4// Densify will soon be deprecated too, so let's just allow deprecated for now
5#[allow(deprecated)]
6use crate::HaversineLength;
7use crate::{
8    CoordFloat, Densify, Line, LineString, MultiLineString, MultiPolygon, Polygon, Rect, Triangle,
9};
10
11#[deprecated(
12    since = "0.29.0",
13    note = "Please use the `line.densify::<Haversine>()` via the `Densify` trait instead."
14)]
15/// Returns a new spherical geometry containing both existing and new interpolated coordinates with
16/// a maximum distance of `max_distance` between them.
17///
18/// Note: `max_distance` must be greater than 0.
19///
20/// ## Units
21///
22/// - `max_distance`: meters
23///
24/// # Examples
25/// ```
26/// use geo::{coord, Line, LineString};
27/// #[allow(deprecated)]
28/// use geo::DensifyHaversine;
29///
30/// let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 });
31/// // known output
32/// let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into();
33/// // densify
34/// let dense = line.densify_haversine(100000.0);
35/// assert_eq!(dense, output);
36///```
37pub trait DensifyHaversine<F: CoordFloat> {
38    type Output;
39
40    fn densify_haversine(&self, max_distance: F) -> Self::Output;
41}
42
43#[allow(deprecated)]
44impl<T> DensifyHaversine<T> for MultiPolygon<T>
45where
46    T: CoordFloat + FromPrimitive,
47    Line<T>: HaversineLength<T>,
48    LineString<T>: HaversineLength<T>,
49{
50    type Output = MultiPolygon<T>;
51
52    fn densify_haversine(&self, max_distance: T) -> Self::Output {
53        self.densify::<Haversine>(max_distance)
54    }
55}
56
57#[allow(deprecated)]
58impl<T> DensifyHaversine<T> for Polygon<T>
59where
60    T: CoordFloat + FromPrimitive,
61    Line<T>: HaversineLength<T>,
62    LineString<T>: HaversineLength<T>,
63{
64    type Output = Polygon<T>;
65
66    fn densify_haversine(&self, max_distance: T) -> Self::Output {
67        self.densify::<Haversine>(max_distance)
68    }
69}
70
71#[allow(deprecated)]
72impl<T> DensifyHaversine<T> for MultiLineString<T>
73where
74    T: CoordFloat + FromPrimitive,
75    Line<T>: HaversineLength<T>,
76    LineString<T>: HaversineLength<T>,
77{
78    type Output = MultiLineString<T>;
79
80    fn densify_haversine(&self, max_distance: T) -> Self::Output {
81        self.densify::<Haversine>(max_distance)
82    }
83}
84
85#[allow(deprecated)]
86impl<T> DensifyHaversine<T> for LineString<T>
87where
88    T: CoordFloat + FromPrimitive,
89    Line<T>: HaversineLength<T>,
90    LineString<T>: HaversineLength<T>,
91{
92    type Output = LineString<T>;
93
94    fn densify_haversine(&self, max_distance: T) -> Self::Output {
95        self.densify::<Haversine>(max_distance)
96    }
97}
98
99#[allow(deprecated)]
100impl<T> DensifyHaversine<T> for Line<T>
101where
102    T: CoordFloat + FromPrimitive,
103    Line<T>: HaversineLength<T>,
104    LineString<T>: HaversineLength<T>,
105{
106    type Output = LineString<T>;
107
108    fn densify_haversine(&self, max_distance: T) -> Self::Output {
109        self.densify::<Haversine>(max_distance)
110    }
111}
112
113#[allow(deprecated)]
114impl<T> DensifyHaversine<T> for Triangle<T>
115where
116    T: CoordFloat + FromPrimitive,
117    Line<T>: HaversineLength<T>,
118    LineString<T>: HaversineLength<T>,
119{
120    type Output = Polygon<T>;
121
122    fn densify_haversine(&self, max_distance: T) -> Self::Output {
123        self.densify::<Haversine>(max_distance)
124    }
125}
126
127#[allow(deprecated)]
128impl<T> DensifyHaversine<T> for Rect<T>
129where
130    T: CoordFloat + FromPrimitive,
131    Line<T>: HaversineLength<T>,
132    LineString<T>: HaversineLength<T>,
133{
134    type Output = Polygon<T>;
135
136    fn densify_haversine(&self, max_distance: T) -> Self::Output {
137        self.densify::<Haversine>(max_distance)
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use crate::{coord, CoordsIter};
145
146    #[test]
147    fn test_polygon_densify() {
148        let exterior: LineString = vec![
149            [4.925, 45.804],
150            [4.732, 45.941],
151            [4.935, 46.513],
152            [5.821, 46.103],
153            [5.627, 45.611],
154            [5.355, 45.883],
155            [4.925, 45.804],
156        ]
157        .into();
158
159        let polygon = Polygon::new(exterior, vec![]);
160
161        let output_exterior: LineString = vec![
162            [4.925, 45.804],
163            [4.732, 45.941],
164            [4.8329711649985505, 46.2270449096239],
165            [4.935, 46.513],
166            [5.379659133344039, 46.30885540136222],
167            [5.821, 46.103],
168            [5.723570877658867, 45.85704103535437],
169            [5.627, 45.611],
170            [5.355, 45.883],
171            [4.925, 45.804],
172        ]
173        .into();
174
175        #[allow(deprecated)]
176        let dense = polygon.densify_haversine(50000.0);
177        assert_relative_eq!(dense.exterior(), &output_exterior);
178    }
179
180    #[test]
181    fn test_linestring_densify() {
182        let linestring: LineString = vec![
183            [-3.202, 55.9471],
184            [-3.2012, 55.9476],
185            [-3.1994, 55.9476],
186            [-3.1977, 55.9481],
187            [-3.196, 55.9483],
188            [-3.1947, 55.9487],
189            [-3.1944, 55.9488],
190            [-3.1944, 55.949],
191        ]
192        .into();
193
194        let output: LineString = vec![
195            [-3.202, 55.9471],
196            [-3.2012, 55.9476],
197            [-3.2002999999999995, 55.94760000327935],
198            [-3.1994, 55.9476],
199            [-3.1985500054877773, 55.94785000292509],
200            [-3.1977, 55.9481],
201            [-3.196, 55.9483],
202            [-3.1947, 55.9487],
203            [-3.1944, 55.9488],
204            [-3.1944, 55.949],
205        ]
206        .into();
207
208        #[allow(deprecated)]
209        let dense = linestring.densify_haversine(110.0);
210        assert_relative_eq!(dense, output);
211    }
212
213    #[test]
214    fn test_line_densify() {
215        let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into();
216        let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 });
217        #[allow(deprecated)]
218        let dense = line.densify_haversine(100000.0);
219        assert_relative_eq!(dense, output);
220    }
221
222    #[test]
223    fn test_empty_linestring() {
224        let linestring: LineString<f64> = LineString::new(vec![]);
225        #[allow(deprecated)]
226        let dense = linestring.densify_haversine(10.0);
227        assert_eq!(0, dense.coords_count());
228    }
229}