diff --git a/geo-types/CHANGES.md b/geo-types/CHANGES.md index 5d1728b1a..8b34c1a9f 100644 --- a/geo-types/CHANGES.md +++ b/geo-types/CHANGES.md @@ -4,6 +4,8 @@ * Add `Polygon::try_exterior_mut` and `Polygon::try_interiors_mut`. +* Add `wkt!` macro to define geometries at compile time. + ## 0.7.11 * Bump rstar dependency diff --git a/geo-types/src/geometry/multi_line_string.rs b/geo-types/src/geometry/multi_line_string.rs index 0e05673af..11b0c8ff8 100644 --- a/geo-types/src/geometry/multi_line_string.rs +++ b/geo-types/src/geometry/multi_line_string.rs @@ -197,29 +197,21 @@ where #[cfg(test)] mod test { use super::*; - use crate::line_string; + use crate::{line_string, wkt}; #[test] fn test_iter() { - let multi: Vec> = vec![ - line_string![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)], - line_string![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)], - ]; - let multi: MultiLineString = MultiLineString::new(multi); + let multi: MultiLineString = wkt! { + MULTILINESTRING((0 0,2 0,1 2,0 0), (10 10,12 10,11 12,10 10)) + }; let mut first = true; for p in &multi { if first { - assert_eq!( - p, - &line_string![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)] - ); + assert_eq!(p, &wkt! { LINESTRING(0 0,2 0,1 2,0 0) }); first = false; } else { - assert_eq!( - p, - &line_string![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)] - ); + assert_eq!(p, &wkt! { LINESTRING(10 10,12 10,11 12,10 10) }); } } @@ -227,16 +219,10 @@ mod test { first = true; for p in &multi { if first { - assert_eq!( - p, - &line_string![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)] - ); + assert_eq!(p, &wkt! { LINESTRING(0 0,2 0,1 2,0 0) }); first = false; } else { - assert_eq!( - p, - &line_string![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)] - ); + assert_eq!(p, &wkt! { LINESTRING(10 10,12 10,11 12,10 10) }); } } } diff --git a/geo-types/src/geometry/multi_point.rs b/geo-types/src/geometry/multi_point.rs index d28e59d8e..1391da78e 100644 --- a/geo-types/src/geometry/multi_point.rs +++ b/geo-types/src/geometry/multi_point.rs @@ -178,11 +178,11 @@ where #[cfg(test)] mod test { use super::*; - use crate::point; + use crate::{point, wkt}; #[test] fn test_iter() { - let multi = MultiPoint::new(vec![point![x: 0, y: 0], point![x: 10, y: 10]]); + let multi = wkt! { MULTIPOINT(0 0,10 10) }; let mut first = true; for p in &multi { @@ -208,7 +208,7 @@ mod test { #[test] fn test_iter_mut() { - let mut multi = MultiPoint::new(vec![point![x: 0, y: 0], point![x: 10, y: 10]]); + let mut multi = wkt! { MULTIPOINT(0 0,10 10) }; for point in &mut multi { point.0.x += 1; @@ -235,26 +235,25 @@ mod test { fn test_relative_eq() { let delta = 1e-6; - let multi = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.]]); + let multi = wkt! { MULTIPOINT(0. 0.,10. 10.) }; + + let mut multi_x = multi.clone(); + *multi_x.0[0].x_mut() += delta; - let multi_x = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10.+delta, y: 10.]]); assert!(multi.relative_eq(&multi_x, 1e-2, 1e-2)); assert!(multi.relative_ne(&multi_x, 1e-12, 1e-12)); - let multi_y = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.+delta]]); + let mut multi_y = multi.clone(); + *multi_y.0[0].y_mut() += delta; assert!(multi.relative_eq(&multi_y, 1e-2, 1e-2)); assert!(multi.relative_ne(&multi_y, 1e-12, 1e-12)); // Under-sized but otherwise equal. - let multi_undersized = MultiPoint::new(vec![point![x: 0., y: 0.]]); + let multi_undersized = wkt! { MULTIPOINT(0. 0.) }; assert!(multi.relative_ne(&multi_undersized, 1., 1.)); // Over-sized but otherwise equal. - let multi_oversized = MultiPoint::new(vec![ - point![x: 0., y: 0.], - point![x: 10., y: 10.], - point![x: 10., y:100.], - ]); + let multi_oversized = wkt! { MULTIPOINT(0. 0.,10. 10.,10. 100.) }; assert!(multi.relative_ne(&multi_oversized, 1., 1.)); } @@ -262,26 +261,24 @@ mod test { fn test_abs_diff_eq() { let delta = 1e-6; - let multi = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.]]); + let multi = wkt! { MULTIPOINT(0. 0.,10. 10.) }; - let multi_x = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10.+delta, y: 10.]]); + let mut multi_x = multi.clone(); + *multi_x.0[0].x_mut() += delta; assert!(multi.abs_diff_eq(&multi_x, 1e-2)); assert!(multi.abs_diff_ne(&multi_x, 1e-12)); - let multi_y = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.+delta]]); + let mut multi_y = multi.clone(); + *multi_y.0[0].y_mut() += delta; assert!(multi.abs_diff_eq(&multi_y, 1e-2)); assert!(multi.abs_diff_ne(&multi_y, 1e-12)); // Under-sized but otherwise equal. - let multi_undersized = MultiPoint::new(vec![point![x: 0., y: 0.]]); + let multi_undersized = wkt! { MULTIPOINT(0. 0.) }; assert!(multi.abs_diff_ne(&multi_undersized, 1.)); // Over-sized but otherwise equal. - let multi_oversized = MultiPoint::new(vec![ - point![x: 0., y: 0.], - point![x: 10., y: 10.], - point![x: 10., y:100.], - ]); + let multi_oversized = wkt! { MULTIPOINT(0. 0.,10. 10.,10. 100.) }; assert!(multi.abs_diff_ne(&multi_oversized, 1.)); } } diff --git a/geo-types/src/lib.rs b/geo-types/src/lib.rs index 8d5c490d7..4b6a4fdfc 100644 --- a/geo-types/src/lib.rs +++ b/geo-types/src/lib.rs @@ -130,6 +130,9 @@ pub use error::Error; #[macro_use] mod macros; +#[macro_use] +mod wkt_macro; + #[cfg(feature = "arbitrary")] mod arbitrary; @@ -147,8 +150,6 @@ pub mod _alloc { //! Needed to access these types from `alloc` in macros when the std feature is //! disabled and the calling context is missing `extern crate alloc`. These are //! _not_ meant for public use. - - pub use ::alloc::boxed::Box; pub use ::alloc::vec; } diff --git a/geo-types/src/macros.rs b/geo-types/src/macros.rs index 491a8e73a..170d382cb 100644 --- a/geo-types/src/macros.rs +++ b/geo-types/src/macros.rs @@ -123,7 +123,7 @@ macro_rules! coord { /// [`LineString`]: ./line_string/struct.LineString.html #[macro_export] macro_rules! line_string { - () => { $crate::LineString::new(vec![]) }; + () => { $crate::LineString::new($crate::_alloc::vec![]) }; ( $(( $($tag:tt : $val:expr),* $(,)? )),* $(,)? @@ -139,11 +139,9 @@ macro_rules! line_string { $(,)? ) => { $crate::LineString::new( - <[_]>::into_vec( - $crate::_alloc::Box::new( - [$($coord), *] - ) - ) + $crate::_alloc::vec![ + $($coord),* + ] ) }; } @@ -216,7 +214,7 @@ macro_rules! line_string { /// [`Polygon`]: ./struct.Polygon.html #[macro_export] macro_rules! polygon { - () => { $crate::Polygon::new($crate::line_string![], vec![]) }; + () => { $crate::Polygon::new($crate::line_string![], $crate::_alloc::vec![]) }; ( exterior: [ $(( $($exterior_tag:tt : $exterior_val:expr),* $(,)? )),* @@ -262,15 +260,11 @@ macro_rules! polygon { $crate::line_string![ $($exterior_coord), * ], - <[_]>::into_vec( - $crate::_alloc::Box::new( - [ - $( - $crate::line_string![$($interior_coord),*] - ), * - ] - ) - ) + $crate::_alloc::vec![ + $( + $crate::line_string![$($interior_coord),*] + ), * + ] ) }; ( diff --git a/geo-types/src/wkt_macro.rs b/geo-types/src/wkt_macro.rs new file mode 100644 index 000000000..df39e2667 --- /dev/null +++ b/geo-types/src/wkt_macro.rs @@ -0,0 +1,328 @@ +/// Creates a [`crate::geometry`] from a +/// [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) literal. +/// +/// This is evaluated at compile time, so you don't need to worry about runtime errors from inavlid +/// WKT syntax. +/// +/// Note that `POINT EMPTY` is not accepted because it is not representable as a `geo_types::Point`. +/// +/// ``` +/// use geo_types::wkt; +/// let point = wkt! { POINT(1.0 2.0) }; +/// assert_eq!(point.x(), 1.0); +/// assert_eq!(point.y(), 2.0); +/// +/// let geometry_collection = wkt! { +/// GEOMETRYCOLLECTION( +/// POINT(1.0 2.0), +/// LINESTRING EMPTY, +/// POLYGON((0.0 0.0,1.0 0.0,1.0 1.0,0.0 0.0)) +/// ) +/// }; +/// assert_eq!(geometry_collection.len(), 3); +/// ``` +#[macro_export] +macro_rules! wkt { + // Hide distracting implementation details from the generated rustdoc. + ($($wkt:tt)+) => { + { + $crate::wkt_internal!($($wkt)+) + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! wkt_internal { + (POINT EMPTY) => { + compile_error!("EMPTY points are not supported in geo-types") + }; + (POINT($x: literal $y: literal)) => { + $crate::point!(x: $x, y: $y) + }; + (POINT $($tail: tt)*) => { + compile_error!("Invalid POINT wkt"); + }; + (LINESTRING EMPTY) => { + $crate::line_string![] + }; + (LINESTRING ($($x: literal $y: literal),+)) => { + $crate::line_string![ + $($crate::coord!(x: $x, y: $y)),* + ] + }; + (LINESTRING ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (LINESTRING $($tail: tt)*) => { + compile_error!("Invalid LINESTRING wkt"); + }; + (POLYGON EMPTY) => { + $crate::polygon![] + }; + (POLYGON ( $exterior_tt: tt )) => { + $crate::Polygon::new($crate::wkt!(LINESTRING $exterior_tt), $crate::_alloc::vec![]) + }; + (POLYGON( $exterior_tt: tt, $($interiors_tt: tt),+ )) => { + $crate::Polygon::new( + $crate::wkt!(LINESTRING $exterior_tt), + $crate::_alloc::vec![ + $($crate::wkt!(LINESTRING $interiors_tt)),* + ] + ) + }; + (POLYGON ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (POLYGON $($tail: tt)*) => { + compile_error!("Invalid POLYGON wkt"); + }; + (MULTIPOINT EMPTY) => { + $crate::MultiPoint($crate::_alloc::vec![]) + }; + (MULTIPOINT ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (MULTIPOINT ($($x: literal $y: literal),* )) => { + $crate::MultiPoint( + $crate::_alloc::vec![$($crate::point!(x: $x, y: $y)),*] + ) + }; + (MULTIPOINT $($tail: tt)*) => { + compile_error!("Invalid MULTIPOINT wkt"); + }; + (MULTILINESTRING EMPTY) => { + $crate::MultiLineString($crate::_alloc::vec![]) + }; + (MULTILINESTRING ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (MULTILINESTRING ( $($line_string_tt: tt),* )) => { + $crate::MultiLineString($crate::_alloc::vec![ + $($crate::wkt!(LINESTRING $line_string_tt)),* + ]) + }; + (MULTILINESTRING $($tail: tt)*) => { + compile_error!("Invalid MULTILINESTRING wkt"); + }; + (MULTIPOLYGON EMPTY) => { + $crate::MultiPolygon($crate::_alloc::vec![]) + }; + (MULTIPOLYGON ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (MULTIPOLYGON ( $($polygon_tt: tt),* )) => { + $crate::MultiPolygon($crate::_alloc::vec![ + $($crate::wkt!(POLYGON $polygon_tt)),* + ]) + }; + (MULTIPOLYGON $($tail: tt)*) => { + compile_error!("Invalid MULTIPOLYGON wkt"); + }; + (GEOMETRYCOLLECTION EMPTY) => { + $crate::GeometryCollection($crate::_alloc::vec![]) + }; + (GEOMETRYCOLLECTION ()) => { + compile_error!("use `EMPTY` instead of () for an empty collection") + }; + (GEOMETRYCOLLECTION ( $($el_type:tt $el_tt: tt),* )) => { + $crate::GeometryCollection($crate::_alloc::vec![ + $($crate::Geometry::from($crate::wkt!($el_type $el_tt))),* + ]) + }; + (GEOMETRYCOLLECTION $($tail: tt)*) => { + compile_error!("Invalid GEOMETRYCOLLECTION wkt"); + }; + ($name: ident ($($tail: tt)*)) => { + compile_error!("Unknown type. Must be one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, or GEOMETRYCOLLECTION"); + }; +} + +#[cfg(test)] +mod test { + use crate::geometry::*; + use alloc::vec; + + #[test] + fn point() { + let point = wkt! { POINT(1.0 2.0) }; + assert_eq!(point.x(), 1.0); + assert_eq!(point.y(), 2.0); + + let point = wkt! { POINT(1.0 2.0) }; + assert_eq!(point.x(), 1.0); + assert_eq!(point.y(), 2.0); + + // This (rightfully) fails to compile because geo-types doesn't support "empty" points + // wkt! { POINT EMPTY } + } + + #[test] + fn empty_line_string() { + let line_string: LineString = wkt! { LINESTRING EMPTY }; + assert_eq!(line_string.0.len(), 0); + + // This (rightfully) fails to compile because its invalid wkt + // wkt! { LINESTRING() } + } + + #[test] + fn line_string() { + let line_string = wkt! { LINESTRING(1.0 2.0,3.0 4.0) }; + assert_eq!(line_string.0.len(), 2); + assert_eq!(line_string[0], coord! { x: 1.0, y: 2.0 }); + } + + #[test] + fn empty_polygon() { + let polygon: Polygon = wkt! { POLYGON EMPTY }; + assert_eq!(polygon.exterior().0.len(), 0); + assert_eq!(polygon.interiors().len(), 0); + + // This (rightfully) fails to compile because its invalid wkt + // wkt! { POLYGON() } + } + + #[test] + fn polygon() { + let polygon = wkt! { POLYGON((1.0 2.0)) }; + assert_eq!(polygon.exterior().0.len(), 1); + assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 }); + + let polygon = wkt! { POLYGON((1.0 2.0,3.0 4.0)) }; + // Note: an extra coord is added to close the linestring + assert_eq!(polygon.exterior().0.len(), 3); + assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 }); + assert_eq!(polygon.exterior().0[1], coord! { x: 3.0, y: 4.0 }); + assert_eq!(polygon.exterior().0[2], coord! { x: 1.0, y: 2.0 }); + + let polygon = wkt! { POLYGON((1.0 2.0), (1.1 2.1)) }; + assert_eq!(polygon.exterior().0.len(), 1); + assert_eq!(polygon.interiors().len(), 1); + + assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 }); + assert_eq!(polygon.interiors()[0].0[0], coord! { x: 1.1, y: 2.1 }); + + let polygon = wkt! { POLYGON((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)) }; + assert_eq!(polygon.exterior().0.len(), 3); + assert_eq!(polygon.interiors().len(), 2); + assert_eq!(polygon.interiors()[1][1], coord! { x: 3.2, y: 4.2 }); + } + + #[test] + fn empty_multi_point() { + let multipoint: MultiPoint = wkt! { MULTIPOINT EMPTY }; + assert!(multipoint.0.is_empty()); + // This (rightfully) fails to compile because its invalid wkt + // wkt! { MULTIPOINT() } + } + + #[test] + fn multi_point() { + let multi_point = wkt! { MULTIPOINT(1.0 2.0) }; + assert_eq!(multi_point.0, vec![point! { x: 1.0, y: 2.0}]); + + let multi_point = wkt! { MULTIPOINT(1.0 2.0,3.0 4.0) }; + assert_eq!( + multi_point.0, + vec![point! { x: 1.0, y: 2.0}, point! { x: 3.0, y: 4.0}] + ); + } + + #[test] + fn empty_multi_line_string() { + let multi_line_string: MultiLineString = wkt! { MULTILINESTRING EMPTY }; + assert_eq!(multi_line_string.0, vec![]); + // This (rightfully) fails to compile because its invalid wkt + // wkt! { MULTILINESTRING() } + } + #[test] + fn multi_line_string() { + let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0)) }; + assert_eq!(multi_line_string.0.len(), 1); + assert_eq!(multi_line_string.0[0].0[1], coord! { x: 3.0, y: 4.0 }); + let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0),(5.0 6.0,7.0 8.0)) }; + assert_eq!(multi_line_string.0.len(), 2); + assert_eq!(multi_line_string.0[1].0[1], coord! { x: 7.0, y: 8.0 }); + + let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0),EMPTY) }; + assert_eq!(multi_line_string.0.len(), 2); + assert_eq!(multi_line_string.0[1].0.len(), 0); + } + + #[test] + fn empty_multi_polygon() { + let multi_polygon: MultiPolygon = wkt! { MULTIPOLYGON EMPTY }; + assert!(multi_polygon.0.is_empty()); + + // This (rightfully) fails to compile because its invalid wkt + // wkt! { MULTIPOLYGON() } + } + + #[test] + fn multi_line_polygon() { + let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0))) }; + assert_eq!(multi_polygon.0.len(), 1); + assert_eq!(multi_polygon.0[0].exterior().0[0], coord! { x: 1.0, y: 2.0}); + + let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)),((1.0 2.0))) }; + assert_eq!(multi_polygon.0.len(), 2); + assert_eq!( + multi_polygon.0[0].interiors()[1].0[0], + coord! { x: 1.2, y: 2.2} + ); + + let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)), EMPTY) }; + assert_eq!(multi_polygon.0.len(), 2); + assert_eq!( + multi_polygon.0[0].interiors()[1].0[0], + coord! { x: 1.2, y: 2.2} + ); + assert!(multi_polygon.0[1].exterior().0.is_empty()); + } + + #[test] + fn empty_geometry_collection() { + let geometry_collection: GeometryCollection = wkt! { GEOMETRYCOLLECTION EMPTY }; + assert!(geometry_collection.is_empty()); + + // This (rightfully) fails to compile because its invalid wkt + // wkt! { MULTIPOLYGON() } + } + + #[test] + fn geometry_collection() { + let geometry_collection = wkt! { + GEOMETRYCOLLECTION ( + POINT (40.0 10.0), + LINESTRING (10.0 10.0, 20.0 20.0, 10.0 40.0), + POLYGON ((40.0 40.0, 20.0 45.0, 45.0 30.0, 40.0 40.0)) + ) + }; + assert_eq!(geometry_collection.len(), 3); + + let line_string = match &geometry_collection[1] { + Geometry::LineString(line_string) => line_string, + _ => panic!( + "unexpected geometry: {geometry:?}", + geometry = geometry_collection[1] + ), + }; + assert_eq!(line_string.0[1], coord! {x: 20.0, y: 20.0 }); + } + + #[test] + fn other_numeric_types() { + let point: Point = wkt!(POINT(1 2)); + assert_eq!(point.x(), 1i32); + assert_eq!(point.y(), 2i32); + + let point: Point = wkt!(POINT(1 2)); + assert_eq!(point.x(), 1u64); + assert_eq!(point.y(), 2u64); + + let point: Point = wkt!(POINT(1.0 2.0)); + assert_eq!(point.x(), 1.0f32); + assert_eq!(point.y(), 2.0f32); + } +} diff --git a/geo/CHANGES.md b/geo/CHANGES.md index 83c2faee3..9b603ecf0 100644 --- a/geo/CHANGES.md +++ b/geo/CHANGES.md @@ -26,6 +26,8 @@ * * Fix coordinate wrapping in `HaversineDestination` * +* Add `wkt!` macro to define geometries at compile time. + ## 0.26.0 diff --git a/geo/src/algorithm/affine_ops.rs b/geo/src/algorithm/affine_ops.rs index 790a69da4..81bff4142 100644 --- a/geo/src/algorithm/affine_ops.rs +++ b/geo/src/algorithm/affine_ops.rs @@ -500,7 +500,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{polygon, Point}; + use crate::{wkt, Point}; // given a matrix with the shape // [[a, b, xoff], @@ -540,10 +540,10 @@ mod tests { #[test] fn affine_transformed() { let transform = AffineTransform::translate(1.0, 1.0).scaled(2.0, 2.0, (0.0, 0.0)); - let mut poly = polygon![(x: 0.0, y: 0.0), (x: 0.0, y: 2.0), (x: 1.0, y: 2.0)]; + let mut poly = wkt! { POLYGON((0.0 0.0,0.0 2.0,1.0 2.0)) }; poly.affine_transform_mut(&transform); - let expected = polygon![(x: 1.0, y: 1.0), (x: 1.0, y: 5.0), (x: 3.0, y: 5.0)]; + let expected = wkt! { POLYGON((1.0 1.0,1.0 5.0,3.0 5.0)) }; assert_eq!(expected, poly); } #[test] @@ -554,7 +554,7 @@ mod tests { // test really only needs this, but let's be sure assert!(identity.is_identity()); - let mut poly = polygon![(x: 0.0, y: 0.0), (x: 0.0, y: 2.0), (x: 1.0, y: 2.0)]; + let mut poly = wkt! { POLYGON((0.0 0.0,0.0 2.0,1.0 2.0)) }; let expected = poly.clone(); poly.affine_transform_mut(&identity); assert_eq!(expected, poly); diff --git a/geo/src/algorithm/area.rs b/geo/src/algorithm/area.rs index 744112f13..6aec9d21a 100644 --- a/geo/src/algorithm/area.rs +++ b/geo/src/algorithm/area.rs @@ -262,7 +262,7 @@ where #[cfg(test)] mod test { use crate::Area; - use crate::{coord, polygon, Line, MultiPolygon, Polygon, Rect, Triangle}; + use crate::{coord, polygon, wkt, Line, MultiPolygon, Polygon, Rect, Triangle}; // Area of the polygon #[test] @@ -273,18 +273,12 @@ mod test { #[test] fn area_one_point_polygon_test() { - let poly = polygon![(x: 1., y: 0.)]; + let poly = wkt! { POLYGON((1. 0.)) }; assert_relative_eq!(poly.signed_area(), 0.); } #[test] fn area_polygon_test() { - let polygon = polygon![ - (x: 0., y: 0.), - (x: 5., y: 0.), - (x: 5., y: 6.), - (x: 0., y: 6.), - (x: 0., y: 0.) - ]; + let polygon = wkt! { POLYGON((0. 0.,5. 0.,5. 6.,0. 6.,0. 0.)) }; assert_relative_eq!(polygon.signed_area(), 30.); } #[test] diff --git a/geo/src/algorithm/centroid.rs b/geo/src/algorithm/centroid.rs index a7e2d0c3f..8718295f5 100644 --- a/geo/src/algorithm/centroid.rs +++ b/geo/src/algorithm/centroid.rs @@ -692,7 +692,7 @@ impl WeightedCentroid { #[cfg(test)] mod test { use super::*; - use crate::{coord, line_string, point, polygon}; + use crate::{coord, line_string, point, polygon, wkt}; /// small helper to create a coordinate fn c(x: T, y: T) -> Coord { @@ -783,10 +783,13 @@ mod test { } #[test] fn multilinestring_test() { - let v1 = line_string![(x: 0.0, y: 0.0), (x: 1.0, y: 10.0)]; - let v2 = line_string![(x: 1.0, y: 10.0), (x: 2.0, y: 0.0), (x: 3.0, y: 1.0)]; - let v3 = line_string![(x: -12.0, y: -100.0), (x: 7.0, y: 8.0)]; - let mls = MultiLineString::new(vec![v1, v2, v3]); + let mls = wkt! { + MULTILINESTRING( + (0.0 0.0,1.0 10.0), + (1.0 10.0,2.0 0.0,3.0 1.0), + (-12.0 -100.0,7.0 8.0) + ) + }; assert_relative_eq!( mls.centroid().unwrap(), point![x: -1.9097834383655845, y: -37.683866439745714] @@ -801,9 +804,7 @@ mod test { #[test] fn polygon_one_point_test() { let p = point![ x: 2., y: 1. ]; - let v = Vec::new(); - let linestring = line_string![p.0]; - let poly = Polygon::new(linestring, v); + let poly = polygon![p.0]; assert_relative_eq!(poly.centroid().unwrap(), p); } @@ -857,68 +858,42 @@ mod test { #[test] fn polygon_hole_test() { // hexagon - let ls1 = LineString::from(vec![ - (5.0, 1.0), - (4.0, 2.0), - (4.0, 3.0), - (5.0, 4.0), - (6.0, 4.0), - (7.0, 3.0), - (7.0, 2.0), - (6.0, 1.0), - (5.0, 1.0), - ]); - - let ls2 = LineString::from(vec![(5.0, 1.3), (5.5, 2.0), (6.0, 1.3), (5.0, 1.3)]); - - let ls3 = LineString::from(vec![(5., 2.3), (5.5, 3.0), (6., 2.3), (5., 2.3)]); - - let p1 = Polygon::new(ls1, vec![ls2, ls3]); + let p1 = wkt! { POLYGON( + (5.0 1.0,4.0 2.0,4.0 3.0,5.0 4.0,6.0 4.0,7.0 3.0,7.0 2.0,6.0 1.0,5.0 1.0), + (5.0 1.3,5.5 2.0,6.0 1.3,5.0 1.3), + (5.0 2.3,5.5 3.0,6.0 2.3,5.0 2.3) + ) }; let centroid = p1.centroid().unwrap(); assert_relative_eq!(centroid, point!(x: 5.5, y: 2.5518518518518523)); } #[test] fn flat_polygon_test() { - let poly = Polygon::new( - LineString::from(vec![p(0., 1.), p(1., 1.), p(0., 1.)]), - vec![], - ); + let poly = wkt! { POLYGON((0. 1.,1. 1.,0. 1.)) }; assert_eq!(poly.centroid(), Some(p(0.5, 1.))); } #[test] fn multi_poly_with_flat_polygon_test() { - let poly = Polygon::new( - LineString::from(vec![p(0., 0.), p(1., 0.), p(0., 0.)]), - vec![], - ); - let multipoly = MultiPolygon::new(vec![poly]); + let multipoly = wkt! { MULTIPOLYGON(((0. 0.,1. 0.,0. 0.))) }; assert_eq!(multipoly.centroid(), Some(p(0.5, 0.))); } #[test] fn multi_poly_with_multiple_flat_polygon_test() { - let p1 = Polygon::new( - LineString::from(vec![p(1., 1.), p(1., 3.), p(1., 1.)]), - vec![], - ); - let p2 = Polygon::new( - LineString::from(vec![p(2., 2.), p(6., 2.), p(2., 2.)]), - vec![], - ); - let multipoly = MultiPolygon::new(vec![p1, p2]); + let multipoly = wkt! { MULTIPOLYGON( + ((1. 1.,1. 3.,1. 1.)), + ((2. 2.,6. 2.,2. 2.)) + )}; + assert_eq!(multipoly.centroid(), Some(p(3., 2.))); } #[test] fn multi_poly_with_only_points_test() { - let p1 = Polygon::new( - LineString::from(vec![p(1., 1.), p(1., 1.), p(1., 1.)]), - vec![], - ); + let p1 = wkt! { POLYGON((1. 1.,1. 1.,1. 1.)) }; assert_eq!(p1.centroid(), Some(p(1., 1.))); - let p2 = Polygon::new( - LineString::from(vec![p(2., 2.), p(2., 2.), p(2., 2.)]), - vec![], - ); - let multipoly = MultiPolygon::new(vec![p1, p2]); + + let multipoly = wkt! { MULTIPOLYGON( + ((1. 1.,1. 1.,1. 1.)), + ((2. 2., 2. 2.,2. 2.)) + ) }; assert_eq!(multipoly.centroid(), Some(p(1.5, 1.5))); } #[test] diff --git a/geo/src/lib.rs b/geo/src/lib.rs index 51acb557d..6606c4134 100644 --- a/geo/src/lib.rs +++ b/geo/src/lib.rs @@ -213,7 +213,7 @@ extern crate serde; pub use crate::algorithm::*; pub use crate::types::Closest; -pub use geo_types::{coord, line_string, point, polygon, CoordFloat, CoordNum}; +pub use geo_types::{coord, line_string, point, polygon, wkt, CoordFloat, CoordNum}; pub mod geometry; pub use geometry::*;