From 63c596f2bdd7f1dc1384c9c70bd0daddb8085e95 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Thu, 5 Oct 2023 21:44:20 -0400 Subject: [PATCH 01/12] add DensifyHaversine trait --- geo/src/algorithm/densify_haversine.rs | 277 +++++++++++++++++++++++++ geo/src/algorithm/mod.rs | 4 + geo/src/lib.rs | 1 + 3 files changed, 282 insertions(+) create mode 100644 geo/src/algorithm/densify_haversine.rs diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs new file mode 100644 index 000000000..a90717d99 --- /dev/null +++ b/geo/src/algorithm/densify_haversine.rs @@ -0,0 +1,277 @@ +use num_traits::FromPrimitive; + +use crate::{ + CoordFloat, Line, LineString, MultiLineString, MultiPolygon, Point, Polygon, Rect, Triangle, +}; + +use crate::{HaversineIntermediate, HaversineLength}; + +/// Returns a new spherical geometry containing both existing and new interpolated coordinates with +/// a maximum distance of `max_distance` between them. +/// +/// Note: `max_distance` must be greater than 0. +/// +/// ## Units +/// +/// `max_distance`: meters +/// +/// # Examples +/// ``` +/// use geo::{coord, Line, LineString}; +/// use geo::DensifyHaversine; +/// +/// let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); +/// +/// // known output +/// let output: LineString = vec![ +/// [ 0.0, 0.0 ], +/// [ 1.0998995245640133, 1.1166572478004086 ], +/// [ 2.2006349325565924, 2.232902789521755 ], +/// [ 3.3030434132933286, 3.348323819287168 ], +/// [ 4.407964761668997, 4.462505328573322 ], +/// [ 5.516242665257213, 5.575028997290395 ], +/// [ 6.628725972011708, 6.685472075832087 ], +/// [ 7.746269931143995, 7.793406255233023 ], +/// [ 8.869737398913761, 8.898396522704935 ], +/// [ 10.0, 10.0 ] +/// ].into(); +/// let dense = line.densify_haversine(180000.0); +/// assert_eq!(dense, output); +///``` +pub trait DensifyHaversine { + type Output; + + fn densify_haversine(&self, max_distance: F) -> Self::Output; +} + +// Helper for densification trait +fn densify_line( + line: Line, + container: &mut Vec>, + max_distance: T, +) { + assert!(max_distance > T::zero()); + container.push(line.start_point()); + let num_segments = (line.haversine_length() / max_distance) + .ceil() + .to_u64() + .unwrap(); + // distance "unit" for this line segment + let frac = T::one() / T::from(num_segments).unwrap(); + for segment_idx in 1..num_segments { + let ratio = frac * T::from(segment_idx).unwrap(); + let start = line.start; + let end = line.end; + let interpolated_point = + Point::from(start).haversine_intermediate(&Point::from(end), ratio); + container.push(interpolated_point); + } +} + +impl DensifyHaversine for MultiPolygon +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = MultiPolygon; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + MultiPolygon::new( + self.iter() + .map(|polygon| polygon.densify_haversine(max_distance)) + .collect(), + ) + } +} + +impl DensifyHaversine for Polygon +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = Polygon; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + let densified_exterior = self.exterior().densify_haversine(max_distance); + let densified_interiors = self + .interiors() + .iter() + .map(|ring| ring.densify_haversine(max_distance)) + .collect(); + Polygon::new(densified_exterior, densified_interiors) + } +} + +impl DensifyHaversine for MultiLineString +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = MultiLineString; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + MultiLineString::new( + self.iter() + .map(|linestring| linestring.densify_haversine(max_distance)) + .collect(), + ) + } +} + +impl DensifyHaversine for LineString +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = LineString; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + let mut new_line = vec![]; + self.lines() + .for_each(|line| densify_line(line, &mut new_line, max_distance)); + // we're done, push the last coordinate on to finish + new_line.push(self.points().last().unwrap()); + LineString::from(new_line) + } +} + +impl DensifyHaversine for Line +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = LineString; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + let mut new_line = vec![]; + densify_line(*self, &mut new_line, max_distance); + // we're done, push the last coordinate on to finish + new_line.push(self.end_point()); + LineString::from(new_line) + } +} + +impl DensifyHaversine for Triangle +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = Polygon; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + self.to_polygon().densify_haversine(max_distance) + } +} + +impl DensifyHaversine for Rect +where + T: CoordFloat + FromPrimitive, + Line: HaversineLength, + LineString: HaversineLength, +{ + type Output = Polygon; + + fn densify_haversine(&self, max_distance: T) -> Self::Output { + self.to_polygon().densify_haversine(max_distance) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{coord, Coord}; + + #[test] + fn test_polygon_densify() { + let exterior: LineString = vec![ + [4.925, 45.804], + [4.732, 45.941], + [4.935, 46.513], + [5.821, 46.103], + [5.627, 45.611], + [5.355, 45.883], + [4.925, 45.804], + ] + .into(); + + let polygon = Polygon::new(exterior, vec![]); + + let output_exterior: LineString = vec![ + [4.925, 45.804], + [4.732, 45.941], + [4.8329711649985505, 46.2270449096239], + [4.935, 46.513], + [5.379659133344039, 46.30885540136222], + [5.821, 46.103], + [5.723570877658867, 45.85704103535437], + [5.627, 45.611], + [5.355, 45.883], + [4.925, 45.804], + ] + .into(); + + let dense = polygon.densify_haversine(50000.0); + + assert_eq!(dense.exterior(), &output_exterior); + } + + #[test] + fn test_linestring_densify() { + let linestring: LineString = vec![ + [-3.202, 55.9471], + [-3.2012, 55.9476], + [-3.1994, 55.9476], + [-3.1977, 55.9481], + [-3.196, 55.9483], + [-3.1947, 55.9487], + [-3.1944, 55.9488], + [-3.1944, 55.949], + ] + .into(); + + let output: LineString = vec![ + [-3.202, 55.9471], + [-3.2012, 55.9476], + [-3.2002999999999995, 55.94760000327935], + [-3.1994, 55.9476], + [-3.1985500054877773, 55.94785000292509], + [-3.1977, 55.9481], + [-3.196, 55.9483], + [-3.1947, 55.9487], + [-3.1944, 55.9488], + [-3.1944, 55.949], + ] + .into(); + + let dense = linestring.densify_haversine(110.0); + assert_eq!(dense, output); + } + + #[test] + fn test_line_densify() { + let output: LineString = vec![ + [0.0, 0.0], + [1.0998995245640133, 1.1166572478004086], + [2.2006349325565924, 2.232902789521755], + [3.3030434132933286, 3.348323819287168], + [4.407964761668997, 4.462505328573322], + [5.516242665257213, 5.575028997290395], + [6.628725972011708, 6.685472075832087], + [7.746269931143995, 7.793406255233023], + [8.869737398913761, 8.898396522704935], + [10.0, 10.0], + ] + .into(); + + let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); + + let dense = line.densify_haversine(180000.0); + assert_eq!(dense, output); + } +} diff --git a/geo/src/algorithm/mod.rs b/geo/src/algorithm/mod.rs index 734cab939..a9457faaa 100644 --- a/geo/src/algorithm/mod.rs +++ b/geo/src/algorithm/mod.rs @@ -80,6 +80,10 @@ pub use coords_iter::CoordsIter; pub mod densify; pub use densify::Densify; +/// Densify spherical geometry components +pub mod densify_haversine; +pub use densify_haversine::DensifyHaversine; + /// Dimensionality of a geometry and its boundary, based on OGC-SFA. pub mod dimensions; pub use dimensions::HasDimensions; diff --git a/geo/src/lib.rs b/geo/src/lib.rs index f6ebe2136..f9eacb12e 100644 --- a/geo/src/lib.rs +++ b/geo/src/lib.rs @@ -154,6 +154,7 @@ //! - **[`Centroid`](Centroid)**: Calculate the centroid of a geometry //! - **[`ChaikinSmoothing`](ChaikinSmoothing)**: Smoothen `LineString`, `Polygon`, `MultiLineString` and `MultiPolygon` using Chaikin's algorithm. //! - **[`Densify`](Densify)**: Densify linear geometry components by interpolating points +//! - **[`DensifyHaversine`](DensifyHaversine)**: Densify spherical geometry by interpolating points on a sphere //! - **[`GeodesicDestination`](GeodesicDestination)**: Given a start point, bearing, and distance, calculate the destination point on a [geodesic](https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid) //! - **[`GeodesicIntermediate`](GeodesicIntermediate)**: Calculate intermediate points on a [geodesic](https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid) //! - **[`HaversineDestination`]**: Given a start point, bearing, and distance, calculate the destination point on a sphere From 046b1b9ee98b7494783b6232d59f049909051144 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Thu, 5 Oct 2023 21:51:58 -0400 Subject: [PATCH 02/12] update changelog --- geo/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/geo/CHANGES.md b/geo/CHANGES.md index 77e98bfda..ae6b19a23 100644 --- a/geo/CHANGES.md +++ b/geo/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased +* Add `DensifyHaversine` trait to densify spherical line geometry * Add `LineStringSegmentize` trait to split a single `LineString` into `n` `LineStrings` as a `MultiLineString` * Add `EuclideanDistance` implementations for all remaining geometries. * From edc296e2420f5b6711a0b86d931b32c1f9f90f08 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Thu, 5 Oct 2023 22:03:42 -0400 Subject: [PATCH 03/12] address lintr --- geo/src/algorithm/densify_haversine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index a90717d99..25a12affb 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -185,7 +185,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{coord, Coord}; + use crate::coord; #[test] fn test_polygon_densify() { From 6b595b0448e195ad40038b810492536c806119a4 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 08:30:45 -0400 Subject: [PATCH 04/12] update tests to use relative equality --- geo/src/algorithm/densify_haversine.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 25a12affb..51aadc639 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -218,7 +218,7 @@ mod tests { let dense = polygon.densify_haversine(50000.0); - assert_eq!(dense.exterior(), &output_exterior); + assert_relative_eq!(dense.exterior(), &output_exterior, epsilon = f64::EPSILON); } #[test] @@ -250,7 +250,7 @@ mod tests { .into(); let dense = linestring.densify_haversine(110.0); - assert_eq!(dense, output); + assert_relative_eq!(dense, output, epsilon = f64::EPSILON); } #[test] @@ -272,6 +272,6 @@ mod tests { let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); let dense = line.densify_haversine(180000.0); - assert_eq!(dense, output); + assert_relative_eq!(dense, output, epsilon = f64::EPSILON); } } From b6aa485b416f16191765cf56bdf085355b0b925d Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 09:06:58 -0400 Subject: [PATCH 05/12] increase tolerance for test_line_densify() --- geo/src/algorithm/densify_haversine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 51aadc639..520e4e5d4 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -272,6 +272,6 @@ mod tests { let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); let dense = line.densify_haversine(180000.0); - assert_relative_eq!(dense, output, epsilon = f64::EPSILON); + assert_relative_eq!(dense, output, epsilon = 1e-14f64); } } From d443dedecf4c9fec3ae508cadb6f92a6aebecfad Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 09:19:44 -0400 Subject: [PATCH 06/12] loosen tolerance. off at the 15th decimal place. --- geo/src/algorithm/densify_haversine.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 520e4e5d4..5b7620129 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -217,7 +217,6 @@ mod tests { .into(); let dense = polygon.densify_haversine(50000.0); - assert_relative_eq!(dense.exterior(), &output_exterior, epsilon = f64::EPSILON); } @@ -250,7 +249,7 @@ mod tests { .into(); let dense = linestring.densify_haversine(110.0); - assert_relative_eq!(dense, output, epsilon = f64::EPSILON); + assert_relative_eq!(dense, output, epsilon = 1e-12f64); } #[test] @@ -272,6 +271,6 @@ mod tests { let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); let dense = line.densify_haversine(180000.0); - assert_relative_eq!(dense, output, epsilon = 1e-14f64); + assert_relative_eq!(dense, output, epsilon = 1e-12f64); } } From df733022d1e0ef3971d7c69f589f741fce387758 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 09:51:54 -0400 Subject: [PATCH 07/12] simplify test to use a straight line --- geo/src/algorithm/densify_haversine.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 5b7620129..364341c73 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -249,28 +249,21 @@ mod tests { .into(); let dense = linestring.densify_haversine(110.0); - assert_relative_eq!(dense, output, epsilon = 1e-12f64); + assert_relative_eq!(dense, output, epsilon = f64::EPSILON); } #[test] fn test_line_densify() { let output: LineString = vec![ [0.0, 0.0], - [1.0998995245640133, 1.1166572478004086], - [2.2006349325565924, 2.232902789521755], - [3.3030434132933286, 3.348323819287168], - [4.407964761668997, 4.462505328573322], - [5.516242665257213, 5.575028997290395], - [6.628725972011708, 6.685472075832087], - [7.746269931143995, 7.793406255233023], - [8.869737398913761, 8.898396522704935], - [10.0, 10.0], + [0.0, 0.5], + [0.0, 1.0], ] .into(); - let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); + let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); - let dense = line.densify_haversine(180000.0); - assert_relative_eq!(dense, output, epsilon = 1e-12f64); + let dense = line.densify_haversine(100000.0); + assert_relative_eq!(dense, output, epsilon = f64::EPSILON); } } From 99d7823d8a00a118de96e3a8085a4ba47611c946 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 09:56:21 -0400 Subject: [PATCH 08/12] lint --- geo/src/algorithm/densify_haversine.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 364341c73..b553d9f3f 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -254,12 +254,7 @@ mod tests { #[test] fn test_line_densify() { - let output: LineString = vec![ - [0.0, 0.0], - [0.0, 0.5], - [0.0, 1.0], - ] - .into(); + let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into(); let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); From 93b15eeee1cfb13b4b2272effff8cc12c49a2061 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 10:13:59 -0400 Subject: [PATCH 09/12] update doc example which should fix CI --- geo/src/algorithm/densify_haversine.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index b553d9f3f..821b709c0 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -19,24 +19,13 @@ use crate::{HaversineIntermediate, HaversineLength}; /// ``` /// use geo::{coord, Line, LineString}; /// use geo::DensifyHaversine; -/// -/// let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 10.0, y: 10.0 }); -/// +/// +/// let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); /// // known output -/// let output: LineString = vec![ -/// [ 0.0, 0.0 ], -/// [ 1.0998995245640133, 1.1166572478004086 ], -/// [ 2.2006349325565924, 2.232902789521755 ], -/// [ 3.3030434132933286, 3.348323819287168 ], -/// [ 4.407964761668997, 4.462505328573322 ], -/// [ 5.516242665257213, 5.575028997290395 ], -/// [ 6.628725972011708, 6.685472075832087 ], -/// [ 7.746269931143995, 7.793406255233023 ], -/// [ 8.869737398913761, 8.898396522704935 ], -/// [ 10.0, 10.0 ] -/// ].into(); -/// let dense = line.densify_haversine(180000.0); -/// assert_eq!(dense, output); +/// let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into(); +/// // densify +/// let dense = line.densify_haversine(100000.0); +/// assert_relative_eq!(dense, output, epsilon = f64::EPSILON); ///``` pub trait DensifyHaversine { type Output; @@ -255,9 +244,7 @@ mod tests { #[test] fn test_line_densify() { let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into(); - let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); - let dense = line.densify_haversine(100000.0); assert_relative_eq!(dense, output, epsilon = f64::EPSILON); } From 491d6dd21002cc83016e6b922676a13f976d17d4 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 10:26:25 -0400 Subject: [PATCH 10/12] ci compliance --- geo/src/algorithm/densify_haversine.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 821b709c0..386c1e85c 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -19,13 +19,13 @@ use crate::{HaversineIntermediate, HaversineLength}; /// ``` /// use geo::{coord, Line, LineString}; /// use geo::DensifyHaversine; -/// +/// /// let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); /// // known output /// let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into(); /// // densify /// let dense = line.densify_haversine(100000.0); -/// assert_relative_eq!(dense, output, epsilon = f64::EPSILON); +/// assert_eq!(dense, output); ///``` pub trait DensifyHaversine { type Output; From c04eecb09d3279fa198a9c9868bc615ddcabdc20 Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 13:06:01 -0400 Subject: [PATCH 11/12] remove f64::epsilon --- geo/src/algorithm/densify_haversine.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 386c1e85c..5324baa20 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -206,7 +206,7 @@ mod tests { .into(); let dense = polygon.densify_haversine(50000.0); - assert_relative_eq!(dense.exterior(), &output_exterior, epsilon = f64::EPSILON); + assert_relative_eq!(dense.exterior(), &output_exterior); } #[test] @@ -238,7 +238,7 @@ mod tests { .into(); let dense = linestring.densify_haversine(110.0); - assert_relative_eq!(dense, output, epsilon = f64::EPSILON); + assert_relative_eq!(dense, output); } #[test] @@ -246,6 +246,6 @@ mod tests { let output: LineString = vec![[0.0, 0.0], [0.0, 0.5], [0.0, 1.0]].into(); let line = Line::new(coord! {x: 0.0, y: 0.0}, coord! { x: 0.0, y: 1.0 }); let dense = line.densify_haversine(100000.0); - assert_relative_eq!(dense, output, epsilon = f64::EPSILON); + assert_relative_eq!(dense, output); } } From f170bbe6bb7f0e54fb2ca7efc2e2225698b9f32f Mon Sep 17 00:00:00 2001 From: Josiah Parry Date: Fri, 6 Oct 2023 13:42:10 -0400 Subject: [PATCH 12/12] add check in linestring impl for empty geometry. add associated test --- geo/src/algorithm/densify_haversine.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/geo/src/algorithm/densify_haversine.rs b/geo/src/algorithm/densify_haversine.rs index 5324baa20..bd7cb9436 100644 --- a/geo/src/algorithm/densify_haversine.rs +++ b/geo/src/algorithm/densify_haversine.rs @@ -1,7 +1,8 @@ use num_traits::FromPrimitive; use crate::{ - CoordFloat, Line, LineString, MultiLineString, MultiPolygon, Point, Polygon, Rect, Triangle, + CoordFloat, CoordsIter, Line, LineString, MultiLineString, MultiPolygon, Point, Polygon, Rect, + Triangle, }; use crate::{HaversineIntermediate, HaversineLength}; @@ -119,6 +120,10 @@ where type Output = LineString; fn densify_haversine(&self, max_distance: T) -> Self::Output { + if self.coords_count() == 0 { + return LineString::new(vec![]); + } + let mut new_line = vec![]; self.lines() .for_each(|line| densify_line(line, &mut new_line, max_distance)); @@ -248,4 +253,11 @@ mod tests { let dense = line.densify_haversine(100000.0); assert_relative_eq!(dense, output); } + + #[test] + fn test_empty_linestring() { + let linestring: LineString = LineString::new(vec![]); + let dense = linestring.densify_haversine(10.0); + assert_eq!(0, dense.coords_count()); + } }