diff --git a/Cargo.toml b/Cargo.toml index d551e4b69d..2560f911b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ members = ["geo", "geo-types", "geo-postgis", "geo-test-fixtures", "jts-test-run # Ensure any transitive dependencies also use the local geo/geo-types geo = { path = "geo" } -geo-types = { path = "geo-types" } +# Uncomment this after geo-types 0.8+ is published with TZM support +# geo-types = { path = "geo-types" } diff --git a/geo-postgis/Cargo.toml b/geo-postgis/Cargo.toml index c8b597be65..ca1d7b701c 100644 --- a/geo-postgis/Cargo.toml +++ b/geo-postgis/Cargo.toml @@ -12,4 +12,6 @@ edition = "2021" [dependencies] postgis = { version = ">=0.7.0, <0.9.0" } -geo-types = { version = "0.7", path = "../geo-types" } +geo-types = { version = "0.7.4" } +# Use this after geo-types 0.8+ is published with TZM support +#geo-types = { version = "0.8", path = "../geo-types" } diff --git a/geo-test-fixtures/Cargo.toml b/geo-test-fixtures/Cargo.toml index a4e5a7b773..be5235fe9e 100644 --- a/geo-test-fixtures/Cargo.toml +++ b/geo-test-fixtures/Cargo.toml @@ -6,4 +6,6 @@ publish = false [dependencies] wkt = { version = "0.10.0", default-features = false } -geo-types = { path = "../geo-types" } +geo-types = "0.7.4" +# Use this after geo-types 0.8+ is published with TZM support +#geo-types = { version = "0.8", path = "../geo-types" } diff --git a/geo-types/CHANGES.md b/geo-types/CHANGES.md index 11018c3ba0..acc999f90f 100644 --- a/geo-types/CHANGES.md +++ b/geo-types/CHANGES.md @@ -1,5 +1,29 @@ # Changes +## Unreleased + +* BREAKING: Remove deprecated functions on the `Geometry`: + * `into_point` - Switch to `std::convert::TryInto` + * `into_line_string` - Switch to `std::convert::TryInto` + * `into_line` - Switch to `std::convert::TryInto` + * `into_polygon` - Switch to `std::convert::TryInto` + * `into_multi_point` - Switch to `std::convert::TryInto` + * `into_multi_line_string` - Switch to `std::convert::TryInto` + * `into_multi_polygon` - Switch to `std::convert::TryInto` +* BREAKING: Remove deprecated `CoordinateType` trait. Use `CoordFloat` or `CoordNum` instead. +* BREAKING: Remove deprecated functions from `LineString` + * Remove `points_iter()` -- use `points()` instead. + * Remove `num_coords()` -- use `geo::algorithm::coords_iter::CoordsIter::coords_count` instead. +* BREAKING: Remove deprecated functions from `Point` + * Remove `lng()` -- use `x()` instead. + * Remove `set_lng()` -- use `set_x()` instead. + * Remove `lat()` -- use `y()` instead. + * Remove `set_lat()` -- use `set_y()` instead. +* BREAKING: Remove deprecated `Polygon::is_convex()` -- use `geo::is_convex` on `poly.exterior()` instead. +* BREAKING: Remove deprecated `Rect::try_new()` -- use `Rect::new` instead, since `Rect::try_new` will never Error. Also removes corresponding `InvalidRectCoordinatesError`. +* BREAKING: Remove `GeometryCollection::new(value)`, replace it with `GeometryCollection::new(value)`, and deprecate `GeometryCollection::new_from(value)`. + * The old `GeometryCollection::new()` is no longer available, and should be replaced with `GeometryCollection::default()` if an empty `GeometryCollection` is needed. + ## 0.7.4 * BREAKING: Make `Rect::to_lines` return lines in winding order for `Rect::to_polygon`. diff --git a/geo-types/src/arbitrary.rs b/geo-types/src/arbitrary.rs index bc0f3426a9..39b2ba0053 100644 --- a/geo-types/src/arbitrary.rs +++ b/geo-types/src/arbitrary.rs @@ -1,36 +1,45 @@ use crate::{ - CoordFloat, Coordinate, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, - MultiPolygon, Point, Polygon, Rect, Triangle, + CoordFloat, CoordTZM, GeometryCollectionTZM, GeometryTZM, LineStringTZM, Measure, + MultiLineStringTZM, MultiPointTZM, MultiPolygonTZM, PointTZM, PolygonTZM, RectTZM, TriangleTZM, + ZCoord, }; use std::mem; -impl<'a, T> arbitrary::Arbitrary<'a> for Coordinate +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for CoordTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(coord! { x: u.arbitrary::()?, y: u.arbitrary::()?, + z: u.arbitrary::()?, + m: u.arbitrary::()?, }) } } -impl<'a, T> arbitrary::Arbitrary<'a> for Point +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for PointTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - u.arbitrary::>().map(Self) + u.arbitrary::>().map(Self) } } -impl<'a, T> arbitrary::Arbitrary<'a> for LineString +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for LineStringTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let coords = u.arbitrary::>>()?; + let coords = u.arbitrary::>>()?; if coords.len() < 2 { Err(arbitrary::Error::IncorrectFormat) } else { @@ -39,86 +48,105 @@ where } fn size_hint(_depth: usize) -> (usize, Option) { - (mem::size_of::() * 2, None) + ( + mem::size_of::() * 2 + mem::size_of::() + mem::size_of::(), + None, + ) } } -impl<'a, T> arbitrary::Arbitrary<'a> for Polygon +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for PolygonTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self::new( - u.arbitrary::>()?, - u.arbitrary::>>()?, + u.arbitrary::>()?, + u.arbitrary::>>()?, )) } } -impl<'a, T> arbitrary::Arbitrary<'a> for MultiPoint +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for MultiPointTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - u.arbitrary::>>().map(Self) + u.arbitrary::>>().map(Self) } } -impl<'a, T> arbitrary::Arbitrary<'a> for MultiLineString +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for MultiLineStringTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - u.arbitrary::>>().map(Self) + u.arbitrary::>>().map(Self) } } -impl<'a, T> arbitrary::Arbitrary<'a> for MultiPolygon +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for MultiPolygonTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - u.arbitrary::>>().map(Self) + u.arbitrary::>>().map(Self) } } -impl<'a, T> arbitrary::Arbitrary<'a> for GeometryCollection +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for GeometryCollectionTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { u.arbitrary() } } -impl<'a, T> arbitrary::Arbitrary<'a> for Rect +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for RectTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self::new( - u.arbitrary::>()?, - u.arbitrary::>()?, + u.arbitrary::>()?, + u.arbitrary::>()?, )) } } -impl<'a, T> arbitrary::Arbitrary<'a> for Triangle +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for TriangleTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self( - u.arbitrary::>()?, - u.arbitrary::>()?, - u.arbitrary::>()?, + u.arbitrary::>()?, + u.arbitrary::>()?, + u.arbitrary::>()?, )) } } -impl<'a, T> arbitrary::Arbitrary<'a> for Geometry +impl<'a, T, Z, M> arbitrary::Arbitrary<'a> for GeometryTZM where T: arbitrary::Arbitrary<'a> + CoordFloat, + Z: arbitrary::Arbitrary<'a> + ZCoord, + M: arbitrary::Arbitrary<'a> + Measure, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let n = u.int_in_range(0..=8)?; diff --git a/geo-types/src/coordinate.rs b/geo-types/src/coordinate.rs index 9b720d910c..17fcc9973b 100644 --- a/geo-types/src/coordinate.rs +++ b/geo-types/src/coordinate.rs @@ -1,4 +1,5 @@ -use crate::{coord, CoordNum, Point}; +use crate::{coord, CoordNum, Measure, NoValue, PointTZM, ZCoord}; +use std::fmt::Debug; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq, UlpsEq}; @@ -25,11 +26,25 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; /// [vector space]: //en.wikipedia.org/wiki/Vector_space #[derive(Eq, PartialEq, Clone, Copy, Debug, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Coordinate { +pub struct CoordTZM { pub x: T, pub y: T, + pub z: Z, + pub m: M, } +impl CoordTZM { + pub fn new(x: T, y: T, z: Z, m: M) -> Self { + Self { x, y, z, m } + } +} + +pub type Coordinate = CoordTZM; +pub type Coord = CoordTZM; +pub type CoordM = CoordTZM; +pub type CoordZ = CoordTZM; +pub type CoordZM = CoordTZM; + impl From<(T, T)> for Coordinate { fn from(coords: (T, T)) -> Self { coord! { @@ -48,28 +63,25 @@ impl From<[T; 2]> for Coordinate { } } -impl From> for Coordinate { - fn from(point: Point) -> Self { - coord! { - x: point.x(), - y: point.y(), - } +impl From> for CoordTZM { + fn from(point: PointTZM) -> Self { + point.0 } } -impl From> for (T, T) { - fn from(coord: Coordinate) -> Self { +impl From> for (T, T) { + fn from(coord: CoordTZM) -> Self { (coord.x, coord.y) } } -impl From> for [T; 2] { - fn from(coord: Coordinate) -> Self { +impl From> for [T; 2] { + fn from(coord: CoordTZM) -> Self { [coord.x, coord.y] } } -impl Coordinate { +impl CoordTZM { /// Returns a tuple that contains the x/horizontal & y/vertical component of the coordinate. /// /// # Examples @@ -106,9 +118,11 @@ use std::ops::{Add, Div, Mul, Neg, Sub}; /// assert_eq!(q.x, -p.x); /// assert_eq!(q.y, -p.y); /// ``` -impl Neg for Coordinate +impl Neg for CoordTZM where T: CoordNum + Neg, + Z: ZCoord + Neg, + M: Measure + Neg, { type Output = Self; @@ -116,6 +130,8 @@ where coord! { x: -self.x, y: -self.y, + z: -self.z, + m: -self.m, } } } @@ -134,13 +150,15 @@ where /// assert_eq!(sum.x, 2.75); /// assert_eq!(sum.y, 5.0); /// ``` -impl Add for Coordinate { +impl Add for CoordTZM { type Output = Self; fn add(self, rhs: Self) -> Self { coord! { x: self.x + rhs.x, y: self.y + rhs.y, + z: self.z + rhs.z, + m: self.m + rhs.m, } } } @@ -159,13 +177,15 @@ impl Add for Coordinate { /// assert_eq!(diff.x, 0.25); /// assert_eq!(diff.y, 0.); /// ``` -impl Sub for Coordinate { +impl Sub for CoordTZM { type Output = Self; fn sub(self, rhs: Self) -> Self { coord! { x: self.x - rhs.x, y: self.y - rhs.y, + z: self.z - rhs.z, + m: self.m - rhs.m, } } } @@ -183,13 +203,20 @@ impl Sub for Coordinate { /// assert_eq!(q.x, 5.0); /// assert_eq!(q.y, 10.0); /// ``` -impl Mul for Coordinate { +impl Mul for CoordTZM +where + T: CoordNum, + Z: ZCoord + Mul, + M: Measure + Mul, +{ type Output = Self; fn mul(self, rhs: T) -> Self { coord! { x: self.x * rhs, y: self.y * rhs, + z: self.z * rhs, + m: self.m * rhs, } } } @@ -207,13 +234,20 @@ impl Mul for Coordinate { /// assert_eq!(q.x, 1.25); /// assert_eq!(q.y, 2.5); /// ``` -impl Div for Coordinate { +impl Div for CoordTZM +where + T: CoordNum, + Z: ZCoord + Div, + M: Measure + Div, +{ type Output = Self; fn div(self, rhs: T) -> Self { coord! { x: self.x / rhs, y: self.y / rhs, + z: self.z / rhs, + m: self.m / rhs, } } } @@ -232,21 +266,23 @@ use num_traits::Zero; /// assert_eq!(p.x, 0.); /// assert_eq!(p.y, 0.); /// ``` -impl Coordinate { +impl CoordTZM { pub fn zero() -> Self { coord! { x: T::zero(), y: T::zero(), + z: Z::zero(), + m: M::zero(), } } } -impl Zero for Coordinate { +impl Zero for CoordTZM { fn zero() -> Self { Self::zero() } fn is_zero(&self) -> bool { - self.x.is_zero() && self.y.is_zero() + self.x.is_zero() && self.y.is_zero() && self.z.is_zero() && self.m.is_zero() } } @@ -365,3 +401,35 @@ where } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_coordinates() { + let p = coord! { x: 1.0, y: 2.0 }; + assert_relative_eq!(p.x, 1.0); + assert_relative_eq!(p.y, 2.0); + assert_eq!(p.z, NoValue); + assert_eq!(p.m, NoValue); + + let p = coord! { x: 1.0, y: 2.0, z: 3.0 }; + assert_relative_eq!(p.x, 1.0); + assert_relative_eq!(p.y, 2.0); + assert_relative_eq!(p.z, 3.0); + assert_eq!(p.m, NoValue); + + let p = coord! { x: 1.0, y: 2.0, m: 4_u8 }; + assert_relative_eq!(p.x, 1.0); + assert_relative_eq!(p.y, 2.0); + assert_eq!(p.z, NoValue); + assert_eq!(p.m, 4_u8); + + let p = coord! { x: 1_i32, y: 2_i32, z: 3_i32, m: 4.0_f64 }; + assert_eq!(p.x, 1); + assert_eq!(p.y, 2); + assert_eq!(p.z, 3); + assert_relative_eq!(p.m, 4.0); + } +} diff --git a/geo-types/src/error.rs b/geo-types/src/error.rs index 50301ec2ca..76622d5ea2 100644 --- a/geo-types/src/error.rs +++ b/geo-types/src/error.rs @@ -38,7 +38,7 @@ mod test { let failure = Point::try_from(rect_geometry).unwrap_err(); assert_eq!( failure.to_string(), - "Expected a geo_types::point::Point, but found a geo_types::rect::Rect" + "Expected a geo_types::point::PointTZM, but found a geo_types::rect::RectTZM" ); } } diff --git a/geo-types/src/geometry.rs b/geo-types/src/geometry.rs index 1df6215ccb..4767786540 100644 --- a/geo-types/src/geometry.rs +++ b/geo-types/src/geometry.rs @@ -1,6 +1,6 @@ use crate::{ - CoordNum, Error, GeometryCollection, Line, LineString, MultiLineString, MultiPoint, - MultiPolygon, Point, Polygon, Rect, Triangle, + CoordNum, Error, GeometryCollectionTZM, LineStringTZM, LineTZM, Measure, MultiLineStringTZM, + MultiPointTZM, MultiPolygonTZM, NoValue, PointTZM, PolygonTZM, RectTZM, TriangleTZM, ZCoord, }; #[cfg(any(feature = "approx", test))] @@ -26,178 +26,88 @@ use std::convert::TryFrom; /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Geometry { - Point(Point), - Line(Line), - LineString(LineString), - Polygon(Polygon), - MultiPoint(MultiPoint), - MultiLineString(MultiLineString), - MultiPolygon(MultiPolygon), - GeometryCollection(GeometryCollection), - Rect(Rect), - Triangle(Triangle), +pub enum GeometryTZM { + Point(PointTZM), + Line(LineTZM), + LineString(LineStringTZM), + Polygon(PolygonTZM), + MultiPoint(MultiPointTZM), + MultiLineString(MultiLineStringTZM), + MultiPolygon(MultiPolygonTZM), + GeometryCollection(GeometryCollectionTZM), + Rect(RectTZM), + Triangle(TriangleTZM), } -impl From> for Geometry { - fn from(x: Point) -> Self { +pub type Geometry = GeometryTZM; +pub type GeometryM = GeometryTZM; +pub type GeometryZ = GeometryTZM; +pub type GeometryZM = GeometryTZM; + +impl From> for GeometryTZM { + fn from(x: PointTZM) -> Self { Self::Point(x) } } -impl From> for Geometry { - fn from(x: Line) -> Self { +impl From> for GeometryTZM { + fn from(x: LineTZM) -> Self { Self::Line(x) } } -impl From> for Geometry { - fn from(x: LineString) -> Self { +impl From> for GeometryTZM { + fn from(x: LineStringTZM) -> Self { Self::LineString(x) } } -impl From> for Geometry { - fn from(x: Polygon) -> Self { +impl From> for GeometryTZM { + fn from(x: PolygonTZM) -> Self { Self::Polygon(x) } } -impl From> for Geometry { - fn from(x: MultiPoint) -> Self { +impl From> for GeometryTZM { + fn from(x: MultiPointTZM) -> Self { Self::MultiPoint(x) } } -impl From> for Geometry { - fn from(x: MultiLineString) -> Self { +impl From> + for GeometryTZM +{ + fn from(x: MultiLineStringTZM) -> Self { Self::MultiLineString(x) } } -impl From> for Geometry { - fn from(x: MultiPolygon) -> Self { +impl From> for GeometryTZM { + fn from(x: MultiPolygonTZM) -> Self { Self::MultiPolygon(x) } } -impl From> for Geometry { - fn from(x: Rect) -> Self { +impl From> for GeometryTZM { + fn from(x: RectTZM) -> Self { Self::Rect(x) } } -impl From> for Geometry { - fn from(x: Triangle) -> Self { +impl From> for GeometryTZM { + fn from(x: TriangleTZM) -> Self { Self::Triangle(x) } } -impl Geometry { - /// If this Geometry is a Point, then return that, else None. - /// - /// # Examples - /// - /// ``` - /// use geo_types::*; - /// use std::convert::TryInto; - /// - /// let g = Geometry::Point(Point::new(0., 0.)); - /// let p2: Point = g.try_into().unwrap(); - /// assert_eq!(p2, Point::new(0., 0.,)); - /// ``` - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_point(self) -> Option> { - if let Geometry::Point(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a LineString, then return that LineString, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_line_string(self) -> Option> { - if let Geometry::LineString(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a Line, then return that Line, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_line(self) -> Option> { - if let Geometry::Line(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a Polygon, then return that, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_polygon(self) -> Option> { - if let Geometry::Polygon(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a MultiPoint, then return that, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_multi_point(self) -> Option> { - if let Geometry::MultiPoint(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a MultiLineString, then return that, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_multi_line_string(self) -> Option> { - if let Geometry::MultiLineString(x) = self { - Some(x) - } else { - None - } - } - - /// If this Geometry is a MultiPolygon, then return that, else None. - #[deprecated( - note = "Will be removed in an upcoming version. Switch to std::convert::TryInto" - )] - pub fn into_multi_polygon(self) -> Option> { - if let Geometry::MultiPolygon(x) = self { - Some(x) - } else { - None - } - } -} - macro_rules! try_from_geometry_impl { - ($($type: ident),+) => { + ($(($type: ident, $typeTZM: ident)),+ $(,)? ) => { $( /// Convert a Geometry enum into its inner type. /// /// Fails if the enum case does not match the type you are trying to convert it to. - impl TryFrom> for $type { + impl TryFrom> for $typeTZM { type Error = Error; - fn try_from(geom: Geometry) -> Result { + fn try_from(geom: GeometryTZM) -> Result { match geom { - Geometry::$type(g) => Ok(g), + GeometryTZM::$type(g) => Ok(g), other => Err(Error::MismatchedGeometry { - expected: type_name::<$type>(), + expected: type_name::<$typeTZM>(), found: inner_type_name(other) }) } @@ -207,33 +117,33 @@ macro_rules! try_from_geometry_impl { } } +// `concat_idents` is not available, so hacking around it try_from_geometry_impl!( - Point, - Line, - LineString, - Polygon, - MultiPoint, - MultiLineString, - MultiPolygon, - Rect, - Triangle + (Point, PointTZM), + (Line, LineTZM), + (LineString, LineStringTZM), + (Polygon, PolygonTZM), + (MultiPoint, MultiPointTZM), + (MultiLineString, MultiLineStringTZM), + (MultiPolygon, MultiPolygonTZM), + (Rect, RectTZM), + (Triangle, TriangleTZM), ); -fn inner_type_name(geometry: Geometry) -> &'static str -where - T: CoordNum, -{ +fn inner_type_name( + geometry: GeometryTZM, +) -> &'static str { match geometry { - Geometry::Point(_) => type_name::>(), - Geometry::Line(_) => type_name::>(), - Geometry::LineString(_) => type_name::>(), - Geometry::Polygon(_) => type_name::>(), - Geometry::MultiPoint(_) => type_name::>(), - Geometry::MultiLineString(_) => type_name::>(), - Geometry::MultiPolygon(_) => type_name::>(), - Geometry::GeometryCollection(_) => type_name::>(), - Geometry::Rect(_) => type_name::>(), - Geometry::Triangle(_) => type_name::>(), + GeometryTZM::Point(_) => type_name::>(), + GeometryTZM::Line(_) => type_name::>(), + GeometryTZM::LineString(_) => type_name::>(), + GeometryTZM::Polygon(_) => type_name::>(), + GeometryTZM::MultiPoint(_) => type_name::>(), + GeometryTZM::MultiLineString(_) => type_name::>(), + GeometryTZM::MultiPolygon(_) => type_name::>(), + GeometryTZM::GeometryCollection(_) => type_name::>(), + GeometryTZM::Rect(_) => type_name::>(), + GeometryTZM::Triangle(_) => type_name::>(), } } diff --git a/geo-types/src/geometry_collection.rs b/geo-types/src/geometry_collection.rs index 8abc544a90..b8cf9c6889 100644 --- a/geo-types/src/geometry_collection.rs +++ b/geo-types/src/geometry_collection.rs @@ -1,4 +1,4 @@ -use crate::{CoordNum, Geometry}; +use crate::{CoordNum, GeometryTZM, Measure, NoValue, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -25,7 +25,7 @@ use std::ops::{Index, IndexMut}; /// use geo_types::{Point, point, Geometry, GeometryCollection}; /// let p = point!(x: 1.0, y: 1.0); /// let pe = Geometry::Point(p); -/// let gc = GeometryCollection::new_from(vec![pe]); +/// let gc = GeometryCollection::new(vec![pe]); /// for geom in gc { /// println!("{:?}", Point::try_from(geom).unwrap().x()); /// } @@ -37,7 +37,7 @@ use std::ops::{Index, IndexMut}; /// use geo_types::{Point, point, Geometry, GeometryCollection}; /// let p = point!(x: 1.0, y: 1.0); /// let pe = Geometry::Point(p); -/// let gc = GeometryCollection::new_from(vec![pe]); +/// let gc = GeometryCollection::new(vec![pe]); /// gc.iter().for_each(|geom| println!("{:?}", geom)); /// ``` /// @@ -48,7 +48,7 @@ use std::ops::{Index, IndexMut}; /// use geo_types::{Point, point, Geometry, GeometryCollection}; /// let p = point!(x: 1.0, y: 1.0); /// let pe = Geometry::Point(p); -/// let mut gc = GeometryCollection::new_from(vec![pe]); +/// let mut gc = GeometryCollection::new(vec![pe]); /// gc.iter_mut().for_each(|geom| { /// if let Geometry::Point(p) = geom { /// p.set_x(0.2); @@ -65,35 +65,30 @@ use std::ops::{Index, IndexMut}; /// use geo_types::{Point, point, Geometry, GeometryCollection}; /// let p = point!(x: 1.0, y: 1.0); /// let pe = Geometry::Point(p); -/// let gc = GeometryCollection::new_from(vec![pe]); +/// let gc = GeometryCollection::new(vec![pe]); /// println!("{:?}", gc[0]); /// ``` /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct GeometryCollection(pub Vec>); +pub struct GeometryCollectionTZM(pub Vec>); + +pub type GeometryCollection = GeometryCollectionTZM; +pub type GeometryCollectionM = GeometryCollectionTZM; +pub type GeometryCollectionZ = GeometryCollectionTZM; +pub type GeometryCollectionZM = GeometryCollectionTZM; // Implementing Default by hand because T does not have Default restriction // todo: consider adding Default as a CoordNum requirement -impl Default for GeometryCollection { +impl Default for GeometryCollectionTZM { fn default() -> Self { Self(Vec::new()) } } -impl GeometryCollection { - /// Return an empty GeometryCollection - #[deprecated( - note = "Will be replaced with a parametrized version in upcoming version. Use GeometryCollection::default() instead" - )] - pub fn new() -> Self { - GeometryCollection::default() - } - - /// DO NOT USE! - /// This fn will be renamed to `new` in the upcoming version. - /// This fn is not marked as deprecated because it would require extensive refactoring of the geo code. - pub fn new_from(value: Vec>) -> Self { +impl GeometryCollectionTZM { + /// Instantiate Self from the raw content value + pub fn new(value: Vec>) -> Self { Self(value) } @@ -110,44 +105,48 @@ impl GeometryCollection { /// Convert any Geometry (or anything that can be converted to a Geometry) into a /// GeometryCollection -impl>> From for GeometryCollection { +impl>> From + for GeometryCollectionTZM +{ fn from(x: IG) -> Self { Self(vec![x.into()]) } } /// Collect Geometries (or what can be converted to a Geometry) into a GeometryCollection -impl>> FromIterator for GeometryCollection { +impl>> FromIterator + for GeometryCollectionTZM +{ fn from_iter>(iter: I) -> Self { Self(iter.into_iter().map(|g| g.into()).collect()) } } -impl Index for GeometryCollection { - type Output = Geometry; +impl Index for GeometryCollectionTZM { + type Output = GeometryTZM; - fn index(&self, index: usize) -> &Geometry { + fn index(&self, index: usize) -> &GeometryTZM { self.0.index(index) } } -impl IndexMut for GeometryCollection { - fn index_mut(&mut self, index: usize) -> &mut Geometry { +impl IndexMut for GeometryCollectionTZM { + fn index_mut(&mut self, index: usize) -> &mut GeometryTZM { self.0.index_mut(index) } } // structure helper for consuming iterator #[derive(Debug)] -pub struct IntoIteratorHelper { - iter: ::std::vec::IntoIter>, +pub struct IntoIteratorHelper { + iter: ::std::vec::IntoIter>, } // implement the IntoIterator trait for a consuming iterator. Iteration will // consume the GeometryCollection -impl IntoIterator for GeometryCollection { - type Item = Geometry; - type IntoIter = IntoIteratorHelper; +impl IntoIterator for GeometryCollectionTZM { + type Item = GeometryTZM; + type IntoIter = IntoIteratorHelper; // note that into_iter() is consuming self fn into_iter(self) -> Self::IntoIter { @@ -158,8 +157,8 @@ impl IntoIterator for GeometryCollection { } // implement Iterator trait for the helper struct, to be used by adapters -impl Iterator for IntoIteratorHelper { - type Item = Geometry; +impl Iterator for IntoIteratorHelper { + type Item = GeometryTZM; // just return the reference fn next(&mut self) -> Option { @@ -169,15 +168,15 @@ impl Iterator for IntoIteratorHelper { // structure helper for non-consuming iterator #[derive(Debug)] -pub struct IterHelper<'a, T: CoordNum> { - iter: ::std::slice::Iter<'a, Geometry>, +pub struct IterHelper<'a, T: CoordNum, Z: ZCoord, M: Measure> { + iter: ::std::slice::Iter<'a, GeometryTZM>, } // implement the IntoIterator trait for a non-consuming iterator. Iteration will // borrow the GeometryCollection -impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection { - type Item = &'a Geometry; - type IntoIter = IterHelper<'a, T>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a GeometryCollectionTZM { + type Item = &'a GeometryTZM; + type IntoIter = IterHelper<'a, T, Z, M>; // note that into_iter() is consuming self fn into_iter(self) -> Self::IntoIter { @@ -188,8 +187,8 @@ impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection { } // implement the Iterator trait for the helper struct, to be used by adapters -impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> { - type Item = &'a Geometry; +impl<'a, T: CoordNum, Z: 'a + ZCoord, M: 'a + Measure> Iterator for IterHelper<'a, T, Z, M> { + type Item = &'a GeometryTZM; // just return the str reference fn next(&mut self) -> Option { @@ -199,15 +198,17 @@ impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> { // structure helper for mutable non-consuming iterator #[derive(Debug)] -pub struct IterMutHelper<'a, T: CoordNum> { - iter: ::std::slice::IterMut<'a, Geometry>, +pub struct IterMutHelper<'a, T: CoordNum, Z: ZCoord, M: Measure> { + iter: ::std::slice::IterMut<'a, GeometryTZM>, } // implement the IntoIterator trait for a mutable non-consuming iterator. Iteration will // mutably borrow the GeometryCollection -impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection { - type Item = &'a mut Geometry; - type IntoIter = IterMutHelper<'a, T>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator + for &'a mut GeometryCollectionTZM +{ + type Item = &'a mut GeometryTZM; + type IntoIter = IterMutHelper<'a, T, Z, M>; // note that into_iter() is consuming self fn into_iter(self) -> Self::IntoIter { @@ -218,8 +219,8 @@ impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection { } // implement the Iterator trait for the helper struct, to be used by adapters -impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> { - type Item = &'a mut Geometry; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> Iterator for IterMutHelper<'a, T, Z, M> { + type Item = &'a mut GeometryTZM; // just return the str reference fn next(&mut self) -> Option { @@ -227,12 +228,12 @@ impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> { } } -impl<'a, T: CoordNum> GeometryCollection { - pub fn iter(&'a self) -> IterHelper<'a, T> { +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> GeometryCollectionTZM { + pub fn iter(&'a self) -> IterHelper<'a, T, Z, M> { self.into_iter() } - pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T> { + pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T, Z, M> { self.into_iter() } } @@ -254,8 +255,8 @@ where /// ``` /// use geo_types::{GeometryCollection, point}; /// - /// let a = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.0].into()]); - /// let b = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.01].into()]); + /// let a = GeometryCollection::new(vec![point![x: 1.0, y: 2.0].into()]); + /// let b = GeometryCollection::new(vec![point![x: 1.0, y: 2.01].into()]); /// /// approx::assert_relative_eq!(a, b, max_relative=0.1); /// approx::assert_relative_ne!(a, b, max_relative=0.0001); @@ -296,8 +297,8 @@ where /// ``` /// use geo_types::{GeometryCollection, point}; /// - /// let a = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.0].into()]); - /// let b = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.1].into()]); + /// let a = GeometryCollection::new(vec![point![x: 0.0, y: 0.0].into()]); + /// let b = GeometryCollection::new(vec![point![x: 0.0, y: 0.1].into()]); /// /// approx::abs_diff_eq!(a, b, epsilon=0.1); /// approx::abs_diff_ne!(a, b, epsilon=0.001); diff --git a/geo-types/src/lib.rs b/geo-types/src/lib.rs index 546e68360b..4779f9a320 100644 --- a/geo-types/src/lib.rs +++ b/geo-types/src/lib.rs @@ -50,7 +50,7 @@ //! [rstar]: https://github.com/Stoeoef/rstar //! [Serde]: https://serde.rs/ extern crate num_traits; -use num_traits::{Float, Num, NumCast}; +use num_traits::{Float, Num, NumCast, NumOps, Zero}; use std::fmt::Debug; #[cfg(feature = "serde")] @@ -64,61 +64,72 @@ extern crate rstar_0_8; #[macro_use] extern crate approx; -#[deprecated(since = "0.7.0", note = "use `CoordFloat` or `CoordNum` instead")] -pub trait CoordinateType: Num + Copy + NumCast + PartialOrd + Debug {} -#[allow(deprecated)] -impl CoordinateType for T {} - /// The type of an x or y value of a point/coordinate. /// /// Floats (`f32` and `f64`) and Integers (`u8`, `i32` etc.) implement this. /// /// For algorithms which only make sense for floating point, like area or length calculations, /// see [CoordFloat](trait.CoordFloat.html). -#[allow(deprecated)] -pub trait CoordNum: CoordinateType + Debug {} -#[allow(deprecated)] -impl CoordNum for T {} +pub trait CoordNum: Num + Copy + NumCast + PartialOrd + Debug {} +impl CoordNum for T {} pub trait CoordFloat: CoordNum + Float {} impl CoordFloat for T {} +pub trait ZCoord: NumOps + Zero + Copy + PartialEq + PartialOrd + Debug {} +impl ZCoord for Z {} + +pub trait Measure: NumOps + Zero + Copy + PartialEq + PartialOrd + Debug {} +impl Measure for M {} + +mod novalue; +pub use crate::novalue::NoValue; + mod coordinate; -pub use crate::coordinate::Coordinate; +pub use crate::coordinate::{Coord, CoordM, CoordTZM, CoordZ, CoordZM, Coordinate}; mod point; -pub use crate::point::Point; +pub use crate::point::{Point, PointM, PointTZM, PointZ, PointZM}; mod multi_point; -pub use crate::multi_point::MultiPoint; +pub use crate::multi_point::{MultiPoint, MultiPointM, MultiPointTZM, MultiPointZ, MultiPointZM}; mod line; -pub use crate::line::Line; +pub use crate::line::{Line, LineM, LineTZM, LineZ, LineZM}; mod line_string; -pub use crate::line_string::{LineString, PointsIter}; +pub use crate::line_string::{ + LineString, LineStringM, LineStringTZM, LineStringZ, LineStringZM, PointsIter, PointsIterM, + PointsIterTZM, PointsIterZ, PointsIterZM, +}; mod multi_line_string; -pub use crate::multi_line_string::MultiLineString; +pub use crate::multi_line_string::{ + MultiLineString, MultiLineStringM, MultiLineStringTZM, MultiLineStringZ, MultiLineStringZM, +}; mod polygon; -pub use crate::polygon::Polygon; +pub use crate::polygon::{Polygon, PolygonM, PolygonTZM, PolygonZ, PolygonZM}; mod multi_polygon; -pub use crate::multi_polygon::MultiPolygon; +pub use crate::multi_polygon::{ + MultiPolygon, MultiPolygonM, MultiPolygonTZM, MultiPolygonZ, MultiPolygonZM, +}; mod geometry; -pub use crate::geometry::Geometry; +pub use crate::geometry::{Geometry, GeometryM, GeometryTZM, GeometryZ, GeometryZM}; mod geometry_collection; -pub use crate::geometry_collection::GeometryCollection; +pub use crate::geometry_collection::{ + GeometryCollection, GeometryCollectionM, GeometryCollectionTZM, GeometryCollectionZ, + GeometryCollectionZM, +}; mod triangle; -pub use crate::triangle::Triangle; +pub use crate::triangle::{Triangle, TriangleM, TriangleTZM, TriangleZ, TriangleZM}; mod rect; -#[allow(deprecated)] -pub use crate::rect::{InvalidRectCoordinatesError, Rect}; +pub use crate::rect::{Rect, RectM, RectTZM, RectZ, RectZM}; mod error; pub use error::Error; @@ -147,7 +158,7 @@ mod tests { let p = Point::from(c); - let Point(c2) = p; + let PointTZM(c2) = p; assert_eq!(c, c2); assert_relative_eq!(c.x, c2.x); assert_relative_eq!(c.y, c2.y); diff --git a/geo-types/src/line.rs b/geo-types/src/line.rs index fbee02a9d3..3ef39cb553 100644 --- a/geo-types/src/line.rs +++ b/geo-types/src/line.rs @@ -1,4 +1,4 @@ -use crate::{CoordNum, Coordinate, Point}; +use crate::{CoordNum, CoordTZM, Measure, NoValue, PointTZM, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -11,36 +11,46 @@ use approx::{AbsDiffEq, RelativeEq}; /// `LineString` with the two end points. #[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Line { - pub start: Coordinate, - pub end: Coordinate, +pub struct LineTZM { + pub start: CoordTZM, + pub end: CoordTZM, } -impl Line { +pub type Line = LineTZM; +pub type LineM = LineTZM; +pub type LineZ = LineTZM; +pub type LineZM = LineTZM; + +impl LineTZM { /// Creates a new line segment. /// /// # Examples /// /// ``` - /// use geo_types::{coord, Line}; + /// use geo_types::{coord, Line, LineZM}; /// /// let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 2. }); - /// /// assert_eq!(line.start, coord! { x: 0., y: 0. }); /// assert_eq!(line.end, coord! { x: 1., y: 2. }); + /// + /// let line = LineZM::new(coord! { x: 0., y: 0., z: 0., m: 1 }, coord! { x: 1., y: 2., z: 3., m: 4 }); + /// assert_eq!(line.start, coord! { x: 0., y: 0., z: 0., m: 1 }); + /// assert_eq!(line.end, coord! { x: 1., y: 2., z: 3., m: 4 }); /// ``` pub fn new(start: C, end: C) -> Self where - C: Into>, + C: Into>, { Self { start: start.into(), end: end.into(), } } +} +impl LineTZM { /// Calculate the difference in coordinates (Δx, Δy). - pub fn delta(&self) -> Coordinate { + pub fn delta(&self) -> CoordTZM { self.end - self.start } @@ -82,6 +92,28 @@ impl Line { self.delta().y } + /// Calculate the difference in ‘z’ components (Δz). + /// + /// Equivalent to: + /// + /// ```rust + /// # use geo_types::{LineZ, point}; + /// # let line = LineZ::new( + /// # point! { x: 1., y: 3., z: 5. }, + /// # point! { x: 0., y: 9., z: 4. }, + /// # ); + /// # assert_eq!( + /// # line.dz(), + /// line.end.z - line.start.z + /// # ); + /// ``` + pub fn dz(&self) -> Z { + self.delta().z + } +} + +/// Implementations for 2D lines with optional Measure +impl LineM { /// Calculate the slope (Δy/Δx). /// /// Equivalent to: @@ -141,16 +173,18 @@ impl Line { pub fn determinant(&self) -> T { self.start.x * self.end.y - self.start.y * self.end.x } +} - pub fn start_point(&self) -> Point { - Point::from(self.start) +impl LineTZM { + pub fn start_point(&self) -> PointTZM { + PointTZM::from(self.start) } - pub fn end_point(&self) -> Point { - Point::from(self.end) + pub fn end_point(&self) -> PointTZM { + PointTZM::from(self.end) } - pub fn points(&self) -> (Point, Point) { + pub fn points(&self) -> (PointTZM, PointTZM) { (self.start_point(), self.end_point()) } } @@ -224,11 +258,11 @@ impl + CoordNum> AbsDiffEq for Line { #[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))] macro_rules! impl_rstar_line { ($rstar:ident) => { - impl ::$rstar::RTreeObject for Line + impl ::$rstar::RTreeObject for crate::Line where T: ::num_traits::Float + ::$rstar::RTreeNum, { - type Envelope = ::$rstar::AABB>; + type Envelope = ::$rstar::AABB>; fn envelope(&self) -> Self::Envelope { let bounding_rect = crate::private_utils::line_bounding_rect(*self); @@ -236,11 +270,11 @@ macro_rules! impl_rstar_line { } } - impl ::$rstar::PointDistance for Line + impl ::$rstar::PointDistance for crate::Line where T: ::num_traits::Float + ::$rstar::RTreeNum, { - fn distance_2(&self, point: &Point) -> T { + fn distance_2(&self, point: &crate::Point) -> T { let d = crate::private_utils::point_line_euclidean_distance(*point, *self); d.powi(2) } diff --git a/geo-types/src/line_string.rs b/geo-types/src/line_string.rs index 594d057821..d486e1bb71 100644 --- a/geo-types/src/line_string.rs +++ b/geo-types/src/line_string.rs @@ -1,7 +1,4 @@ -#[cfg(any(feature = "approx", test))] -use approx::{AbsDiffEq, RelativeEq}; - -use crate::{CoordNum, Coordinate, Line, Point, Triangle}; +use crate::{CoordNum, CoordTZM, LineTZM, Measure, NoValue, PointTZM, TriangleTZM, ZCoord}; use std::iter::FromIterator; use std::ops::{Index, IndexMut}; @@ -132,17 +129,36 @@ use std::ops::{Index, IndexMut}; #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LineString(pub Vec>); +pub struct LineStringTZM(pub Vec>); + +pub type LineString = LineStringTZM; +pub type LineStringM = LineStringTZM; +pub type LineStringZ = LineStringTZM; +pub type LineStringZM = LineStringTZM; /// A [`Point`] iterator returned by the `points` method #[derive(Debug)] -pub struct PointsIter<'a, T: CoordNum + 'a>(::std::slice::Iter<'a, Coordinate>); +pub struct PointsIterTZM<'a, T, Z, M>(::std::slice::Iter<'a, CoordTZM>) +where + T: CoordNum + 'a, + Z: ZCoord + 'a, + M: Measure + 'a; -impl<'a, T: CoordNum> Iterator for PointsIter<'a, T> { - type Item = Point; +pub type PointsIter<'a, T> = PointsIterTZM<'a, T, NoValue, NoValue>; +pub type PointsIterM<'a, T, M> = PointsIterTZM<'a, T, NoValue, M>; +pub type PointsIterZ<'a, T> = PointsIterTZM<'a, T, T, NoValue>; +pub type PointsIterZM<'a, T, M> = PointsIterTZM<'a, T, T, M>; + +impl<'a, T, Z, M> Iterator for PointsIterTZM<'a, T, Z, M> +where + T: CoordNum + 'a, + Z: ZCoord + 'a, + M: Measure + 'a, +{ + type Item = PointTZM; fn next(&mut self) -> Option { - self.0.next().map(|c| Point::from(*c)) + self.0.next().map(|c| PointTZM::from(*c)) } fn size_hint(&self) -> (usize, Option) { @@ -150,24 +166,26 @@ impl<'a, T: CoordNum> Iterator for PointsIter<'a, T> { } } -impl<'a, T: CoordNum> ExactSizeIterator for PointsIter<'a, T> { +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> ExactSizeIterator for PointsIterTZM<'a, T, Z, M> { fn len(&self) -> usize { self.0.len() } } -impl<'a, T: CoordNum> DoubleEndedIterator for PointsIter<'a, T> { +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> DoubleEndedIterator for PointsIterTZM<'a, T, Z, M> { fn next_back(&mut self) -> Option { - self.0.next_back().map(|c| Point::from(*c)) + self.0.next_back().map(|c| PointTZM::from(*c)) } } /// A [`Coordinate`] iterator used by the `into_iter` method on a [`LineString`] #[derive(Debug)] -pub struct CoordinatesIter<'a, T: CoordNum + 'a>(::std::slice::Iter<'a, Coordinate>); +pub struct CoordinatesIter<'a, T: CoordNum + 'a, Z: ZCoord + 'a, M: Measure + 'a>( + ::std::slice::Iter<'a, CoordTZM>, +); -impl<'a, T: CoordNum> Iterator for CoordinatesIter<'a, T> { - type Item = &'a Coordinate; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> Iterator for CoordinatesIter<'a, T, Z, M> { + type Item = &'a CoordTZM; fn next(&mut self) -> Option { self.0.next() @@ -178,52 +196,46 @@ impl<'a, T: CoordNum> Iterator for CoordinatesIter<'a, T> { } } -impl<'a, T: CoordNum> ExactSizeIterator for CoordinatesIter<'a, T> { +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> ExactSizeIterator for CoordinatesIter<'a, T, Z, M> { fn len(&self) -> usize { self.0.len() } } -impl<'a, T: CoordNum> DoubleEndedIterator for CoordinatesIter<'a, T> { +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> DoubleEndedIterator for CoordinatesIter<'a, T, Z, M> { fn next_back(&mut self) -> Option { self.0.next_back() } } -impl LineString { +impl LineStringTZM { /// Instantiate Self from the raw content value - pub fn new(value: Vec>) -> Self { + pub fn new(value: Vec>) -> Self { Self(value) } /// Return an iterator yielding the coordinates of a [`LineString`] as [`Point`]s - #[deprecated(note = "Use points() instead")] - pub fn points_iter(&self) -> PointsIter { - PointsIter(self.0.iter()) - } - - /// Return an iterator yielding the coordinates of a [`LineString`] as [`Point`]s - pub fn points(&self) -> PointsIter { - PointsIter(self.0.iter()) + pub fn points(&self) -> PointsIterTZM { + PointsIterTZM(self.0.iter()) } /// Return an iterator yielding the members of a [`LineString`] as [`Coordinate`]s - pub fn coords(&self) -> impl Iterator> { + pub fn coords(&self) -> impl Iterator> { self.0.iter() } /// Return an iterator yielding the coordinates of a [`LineString`] as mutable [`Coordinate`]s - pub fn coords_mut(&mut self) -> impl Iterator> { + pub fn coords_mut(&mut self) -> impl Iterator> { self.0.iter_mut() } /// Return the coordinates of a [`LineString`] as a [`Vec`] of [`Point`]s - pub fn into_points(self) -> Vec> { - self.0.into_iter().map(Point::from).collect() + pub fn into_points(self) -> Vec> { + self.0.into_iter().map(PointTZM::from).collect() } /// Return the coordinates of a [`LineString`] as a [`Vec`] of [`Coordinate`]s - pub fn into_inner(self) -> Vec> { + pub fn into_inner(self) -> Vec> { self.0 } @@ -255,19 +267,21 @@ impl LineString { /// ); /// assert!(lines.next().is_none()); /// ``` - pub fn lines(&'_ self) -> impl ExactSizeIterator + Iterator> + '_ { + pub fn lines(&'_ self) -> impl ExactSizeIterator + Iterator> + '_ { self.0.windows(2).map(|w| { // slice::windows(N) is guaranteed to yield a slice with exactly N elements - unsafe { Line::new(*w.get_unchecked(0), *w.get_unchecked(1)) } + unsafe { LineTZM::new(*w.get_unchecked(0), *w.get_unchecked(1)) } }) } /// An iterator which yields the coordinates of a [`LineString`] as [Triangle]s - pub fn triangles(&'_ self) -> impl ExactSizeIterator + Iterator> + '_ { + pub fn triangles( + &'_ self, + ) -> impl ExactSizeIterator + Iterator> + '_ { self.0.windows(3).map(|w| { // slice::windows(N) is guaranteed to yield a slice with exactly N elements unsafe { - Triangle::new( + TriangleTZM::new( *w.get_unchecked(0), *w.get_unchecked(1), *w.get_unchecked(2), @@ -287,26 +301,6 @@ impl LineString { } } - /// Return the number of coordinates in the [`LineString`]. - /// - /// # Examples - /// - /// ``` - /// use geo_types::LineString; - /// - /// let mut coords = vec![(0., 0.), (5., 0.), (7., 9.)]; - /// let line_string: LineString = coords.into_iter().collect(); - /// - /// # #[allow(deprecated)] - /// # { - /// assert_eq!(3, line_string.num_coords()); - /// # } - /// ``` - #[deprecated(note = "Use geo::algorithm::coords_iter::CoordsIter::coords_count instead")] - pub fn num_coords(&self) -> usize { - self.0.len() - } - /// Checks if the linestring is closed; i.e. it is /// either empty or, the first and last points are the /// same. @@ -336,38 +330,42 @@ impl LineString { } /// Turn a [`Vec`] of [`Point`]-like objects into a [`LineString`]. -impl>> From> for LineString { +impl>> From> + for LineStringTZM +{ fn from(v: Vec) -> Self { Self(v.into_iter().map(|c| c.into()).collect()) } } -impl From> for LineString { - fn from(line: Line) -> Self { +impl From> for LineStringTZM { + fn from(line: LineTZM) -> Self { Self(vec![line.start, line.end]) } } /// Turn an iterator of [`Point`]-like objects into a [`LineString`]. -impl>> FromIterator for LineString { +impl>> FromIterator + for LineStringTZM +{ fn from_iter>(iter: I) -> Self { Self(iter.into_iter().map(|c| c.into()).collect()) } } /// Iterate over all the [`Coordinate`]s in this [`LineString`]. -impl IntoIterator for LineString { - type Item = Coordinate; - type IntoIter = ::std::vec::IntoIter>; +impl IntoIterator for LineStringTZM { + type Item = CoordTZM; + type IntoIter = ::std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a LineString { - type Item = &'a Coordinate; - type IntoIter = CoordinatesIter<'a, T>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a LineStringTZM { + type Item = &'a CoordTZM; + type IntoIter = CoordinatesIter<'a, T, Z, M>; fn into_iter(self) -> Self::IntoIter { CoordinatesIter(self.0.iter()) @@ -375,33 +373,33 @@ impl<'a, T: CoordNum> IntoIterator for &'a LineString { } /// Mutably iterate over all the [`Coordinate`]s in this [`LineString`] -impl<'a, T: CoordNum> IntoIterator for &'a mut LineString { - type Item = &'a mut Coordinate; - type IntoIter = ::std::slice::IterMut<'a, Coordinate>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a mut LineStringTZM { + type Item = &'a mut CoordTZM; + type IntoIter = ::std::slice::IterMut<'a, CoordTZM>; - fn into_iter(self) -> ::std::slice::IterMut<'a, Coordinate> { + fn into_iter(self) -> ::std::slice::IterMut<'a, CoordTZM> { self.0.iter_mut() } } -impl Index for LineString { - type Output = Coordinate; +impl Index for LineStringTZM { + type Output = CoordTZM; - fn index(&self, index: usize) -> &Coordinate { + fn index(&self, index: usize) -> &CoordTZM { self.0.index(index) } } -impl IndexMut for LineString { - fn index_mut(&mut self, index: usize) -> &mut Coordinate { +impl IndexMut for LineStringTZM { + fn index_mut(&mut self, index: usize) -> &mut CoordTZM { self.0.index_mut(index) } } #[cfg(any(feature = "approx", test))] -impl RelativeEq for LineString +impl approx::RelativeEq for LineString where - T: AbsDiffEq + CoordNum + RelativeEq, + T: approx::AbsDiffEq + CoordNum + approx::RelativeEq, { #[inline] fn default_max_relative() -> Self::Epsilon { @@ -446,7 +444,7 @@ where } #[cfg(any(feature = "approx", test))] -impl + CoordNum> AbsDiffEq for LineString { +impl + CoordNum> approx::AbsDiffEq for LineString { type Epsilon = T; #[inline] @@ -485,19 +483,19 @@ macro_rules! impl_rstar_line_string { where T: ::num_traits::Float + ::$rstar::RTreeNum, { - type Envelope = ::$rstar::AABB>; + type Envelope = ::$rstar::AABB>; fn envelope(&self) -> Self::Envelope { use num_traits::Bounded; let bounding_rect = crate::private_utils::line_string_bounding_rect(self); match bounding_rect { None => ::$rstar::AABB::from_corners( - Point::new(Bounded::min_value(), Bounded::min_value()), - Point::new(Bounded::max_value(), Bounded::max_value()), + crate::Point::new(Bounded::min_value(), Bounded::min_value()), + crate::Point::new(Bounded::max_value(), Bounded::max_value()), ), Some(b) => ::$rstar::AABB::from_corners( - Point::new(b.min().x, b.min().y), - Point::new(b.max().x, b.max().y), + crate::Point::new(b.min().x, b.min().y), + crate::Point::new(b.max().x, b.max().y), ), } } @@ -507,7 +505,7 @@ macro_rules! impl_rstar_line_string { where T: ::num_traits::Float + ::$rstar::RTreeNum, { - fn distance_2(&self, point: &Point) -> T { + fn distance_2(&self, point: &crate::Point) -> T { let d = crate::private_utils::point_line_string_euclidean_distance(*point, self); if d == T::zero() { d @@ -528,8 +526,8 @@ impl_rstar_line_string!(rstar_0_9); #[cfg(test)] mod test { use super::*; - use crate::coord; - use approx::AbsDiffEq; + use crate::{coord, Line}; + use approx::{AbsDiffEq, RelativeEq}; #[test] fn test_exact_size() { diff --git a/geo-types/src/macros.rs b/geo-types/src/macros.rs index 558525f7a2..ffcebc53f7 100644 --- a/geo-types/src/macros.rs +++ b/geo-types/src/macros.rs @@ -1,6 +1,7 @@ /// Creates a [`Point`] from the given coordinates. /// /// ```txt +/// point!(, ) /// point! { x: , y: } /// point!() /// ``` @@ -30,7 +31,7 @@ macro_rules! point { $crate::point! ( $crate::coord! { $( $tag: $val , )* } ) }; ( $coord:expr $(,)? ) => { - $crate::Point::from($coord) + $crate::PointTZM::from($coord) }; } @@ -55,8 +56,22 @@ macro_rules! point { /// [`Coordinate`]: ./struct.Point.html #[macro_export] macro_rules! coord { - (x: $x:expr, y: $y:expr $(,)?) => { - $crate::Coordinate { x: $x, y: $y } + (x: $x:expr, y: $y:expr $(,)* ) => { + $crate::CoordTZM::new( + $x, + $y, + $crate::NoValue::default(), + $crate::NoValue::default(), + ) + }; + (x: $x:expr, y: $y:expr, z: $z:expr $(,)* ) => { + $crate::CoordTZM::new($x, $y, $z, $crate::NoValue::default()) + }; + (x: $x:expr, y: $y:expr, m: $m:expr $(,)* ) => { + $crate::CoordTZM::new($x, $y, $crate::NoValue::default(), $m) + }; + (x: $x:expr, y: $y:expr, z: $z:expr, m: $m:expr $(,)* ) => { + $crate::CoordTZM::new($x, $y, $z, $m) }; } @@ -123,7 +138,7 @@ macro_rules! coord { /// [`LineString`]: ./line_string/struct.LineString.html #[macro_export] macro_rules! line_string { - () => { $crate::LineString(vec![]) }; + () => { $crate::LineStringTZM::new(vec![]) }; ( $(( $($tag:tt : $val:expr),* $(,)? )),* $(,)? @@ -138,7 +153,7 @@ macro_rules! line_string { $($coord:expr),* $(,)? ) => { - $crate::LineString( + $crate::LineStringTZM::new( <[_]>::into_vec( ::std::boxed::Box::new( [$($coord), *] @@ -216,7 +231,7 @@ macro_rules! line_string { /// [`Polygon`]: ./struct.Polygon.html #[macro_export] macro_rules! polygon { - () => { $crate::Polygon::new(line_string![], vec![]) }; + () => { $crate::PolygonTZM::new(line_string![], vec![]) }; ( exterior: [ $(( $($exterior_tag:tt : $exterior_val:expr),* $(,)? )),* @@ -258,7 +273,7 @@ macro_rules! polygon { ] $(,)? ) => { - $crate::Polygon::new( + $crate::PolygonTZM::new( $crate::line_string![ $($exterior_coord), * ], @@ -285,7 +300,7 @@ macro_rules! polygon { $($coord:expr),* $(,)? ) => { - $crate::Polygon::new( + $crate::PolygonTZM::new( $crate::line_string![$($coord,)*], vec![], ) diff --git a/geo-types/src/multi_line_string.rs b/geo-types/src/multi_line_string.rs index fbb54ae7a4..35a4c6a2ce 100644 --- a/geo-types/src/multi_line_string.rs +++ b/geo-types/src/multi_line_string.rs @@ -1,4 +1,4 @@ -use crate::{CoordNum, LineString}; +use crate::{CoordNum, LineStringTZM, Measure, NoValue, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -33,11 +33,16 @@ use std::iter::FromIterator; /// of a closed `MultiLineString` is always empty. #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct MultiLineString(pub Vec>); +pub struct MultiLineStringTZM(pub Vec>); -impl MultiLineString { +pub type MultiLineString = MultiLineStringTZM; +pub type MultiLineStringM = MultiLineStringTZM; +pub type MultiLineStringZ = MultiLineStringTZM; +pub type MultiLineStringZM = MultiLineStringTZM; + +impl MultiLineStringTZM { /// Instantiate Self from the raw content value - pub fn new(value: Vec>) -> Self { + pub fn new(value: Vec>) -> Self { Self(value) } @@ -63,55 +68,59 @@ impl MultiLineString { /// ``` pub fn is_closed(&self) -> bool { // Note: Unlike JTS et al, we consider an empty MultiLineString as closed. - self.iter().all(LineString::is_closed) + self.iter().all(LineStringTZM::is_closed) } } -impl>> From for MultiLineString { +impl>> From + for MultiLineStringTZM +{ fn from(ls: ILS) -> Self { Self(vec![ls.into()]) } } -impl>> FromIterator for MultiLineString { +impl>> FromIterator + for MultiLineStringTZM +{ fn from_iter>(iter: I) -> Self { Self(iter.into_iter().map(|ls| ls.into()).collect()) } } -impl IntoIterator for MultiLineString { - type Item = LineString; - type IntoIter = ::std::vec::IntoIter>; +impl IntoIterator for MultiLineStringTZM { + type Item = LineStringTZM; + type IntoIter = ::std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a MultiLineString { - type Item = &'a LineString; - type IntoIter = ::std::slice::Iter<'a, LineString>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a MultiLineStringTZM { + type Item = &'a LineStringTZM; + type IntoIter = ::std::slice::Iter<'a, LineStringTZM>; fn into_iter(self) -> Self::IntoIter { (&self.0).iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a mut MultiLineString { - type Item = &'a mut LineString; - type IntoIter = ::std::slice::IterMut<'a, LineString>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a mut MultiLineStringTZM { + type Item = &'a mut LineStringTZM; + type IntoIter = ::std::slice::IterMut<'a, LineStringTZM>; fn into_iter(self) -> Self::IntoIter { (&mut self.0).iter_mut() } } -impl MultiLineString { - pub fn iter(&self) -> impl Iterator> { +impl MultiLineStringTZM { + pub fn iter(&self) -> impl Iterator> { self.0.iter() } - pub fn iter_mut(&mut self) -> impl Iterator> { + pub fn iter_mut(&mut self) -> impl Iterator> { self.0.iter_mut() } } @@ -195,7 +204,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::line_string; + use crate::{line_string, LineString}; #[test] fn test_iter() { diff --git a/geo-types/src/multi_point.rs b/geo-types/src/multi_point.rs index 6a7acfdbe2..73164ddc67 100644 --- a/geo-types/src/multi_point.rs +++ b/geo-types/src/multi_point.rs @@ -1,4 +1,4 @@ -use crate::{CoordNum, Point}; +use crate::{CoordNum, Measure, NoValue, PointTZM, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -30,9 +30,16 @@ use std::iter::FromIterator; /// ``` #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct MultiPoint(pub Vec>); +pub struct MultiPointTZM(pub Vec>); -impl>> From for MultiPoint { +pub type MultiPoint = MultiPointTZM; +pub type MultiPointM = MultiPointTZM; +pub type MultiPointZ = MultiPointTZM; +pub type MultiPointZM = MultiPointTZM; + +impl>> From + for MultiPointTZM +{ /// Convert a single `Point` (or something which can be converted to a `Point`) into a /// one-member `MultiPoint` fn from(x: IP) -> Self { @@ -40,7 +47,9 @@ impl>> From for MultiPoint { } } -impl>> From> for MultiPoint { +impl>> From> + for MultiPointTZM +{ /// Convert a `Vec` of `Points` (or `Vec` of things which can be converted to a `Point`) into a /// `MultiPoint`. fn from(v: Vec) -> Self { @@ -48,7 +57,9 @@ impl>> From> for MultiPoint { } } -impl>> FromIterator for MultiPoint { +impl>> FromIterator + for MultiPointTZM +{ /// Collect the results of a `Point` iterator into a `MultiPoint` fn from_iter>(iter: I) -> Self { Self(iter.into_iter().map(|p| p.into()).collect()) @@ -56,43 +67,43 @@ impl>> FromIterator for MultiPoint { } /// Iterate over the `Point`s in this `MultiPoint`. -impl IntoIterator for MultiPoint { - type Item = Point; - type IntoIter = ::std::vec::IntoIter>; +impl IntoIterator for MultiPointTZM { + type Item = PointTZM; + type IntoIter = ::std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a MultiPoint { - type Item = &'a Point; - type IntoIter = ::std::slice::Iter<'a, Point>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a MultiPointTZM { + type Item = &'a PointTZM; + type IntoIter = ::std::slice::Iter<'a, PointTZM>; fn into_iter(self) -> Self::IntoIter { (&self.0).iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPoint { - type Item = &'a mut Point; - type IntoIter = ::std::slice::IterMut<'a, Point>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a mut MultiPointTZM { + type Item = &'a mut PointTZM; + type IntoIter = ::std::slice::IterMut<'a, PointTZM>; fn into_iter(self) -> Self::IntoIter { (&mut self.0).iter_mut() } } -impl MultiPoint { - pub fn new(value: Vec>) -> Self { +impl MultiPointTZM { + pub fn new(value: Vec>) -> Self { Self(value) } - pub fn iter(&self) -> impl Iterator> { + pub fn iter(&self) -> impl Iterator> { self.0.iter() } - pub fn iter_mut(&mut self) -> impl Iterator> { + pub fn iter_mut(&mut self) -> impl Iterator> { self.0.iter_mut() } } diff --git a/geo-types/src/multi_polygon.rs b/geo-types/src/multi_polygon.rs index 881d250dd4..5f5215c736 100644 --- a/geo-types/src/multi_polygon.rs +++ b/geo-types/src/multi_polygon.rs @@ -1,4 +1,4 @@ -use crate::{CoordNum, Polygon}; +use crate::{CoordNum, Measure, NoValue, PolygonTZM, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -27,64 +27,75 @@ use std::iter::FromIterator; /// predicates that operate on it. #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct MultiPolygon(pub Vec>); +pub struct MultiPolygonTZM(pub Vec>); -impl>> From for MultiPolygon { +pub type MultiPolygon = MultiPolygonTZM; +pub type MultiPolygonM = MultiPolygonTZM; +pub type MultiPolygonZ = MultiPolygonTZM; +pub type MultiPolygonZM = MultiPolygonTZM; + +impl>> From + for MultiPolygonTZM +{ fn from(x: IP) -> Self { Self(vec![x.into()]) } } -impl>> From> for MultiPolygon { +impl>> From> + for MultiPolygonTZM +{ fn from(x: Vec) -> Self { Self(x.into_iter().map(|p| p.into()).collect()) } } -impl>> FromIterator for MultiPolygon { +impl>> FromIterator + for MultiPolygonTZM +{ fn from_iter>(iter: I) -> Self { Self(iter.into_iter().map(|p| p.into()).collect()) } } -impl IntoIterator for MultiPolygon { - type Item = Polygon; - type IntoIter = ::std::vec::IntoIter>; +impl IntoIterator for MultiPolygonTZM { + type Item = PolygonTZM; + type IntoIter = ::std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a MultiPolygon { - type Item = &'a Polygon; - type IntoIter = ::std::slice::Iter<'a, Polygon>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a MultiPolygonTZM { + type Item = &'a PolygonTZM; + type IntoIter = ::std::slice::Iter<'a, PolygonTZM>; fn into_iter(self) -> Self::IntoIter { (&self.0).iter() } } -impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPolygon { - type Item = &'a mut Polygon; - type IntoIter = ::std::slice::IterMut<'a, Polygon>; +impl<'a, T: CoordNum, Z: ZCoord, M: Measure> IntoIterator for &'a mut MultiPolygonTZM { + type Item = &'a mut PolygonTZM; + type IntoIter = ::std::slice::IterMut<'a, PolygonTZM>; fn into_iter(self) -> Self::IntoIter { (&mut self.0).iter_mut() } } -impl MultiPolygon { +impl MultiPolygonTZM { /// Instantiate Self from the raw content value - pub fn new(value: Vec>) -> Self { + pub fn new(value: Vec>) -> Self { Self(value) } - pub fn iter(&self) -> impl Iterator> { + pub fn iter(&self) -> impl Iterator> { self.0.iter() } - pub fn iter_mut(&mut self) -> impl Iterator> { + pub fn iter_mut(&mut self) -> impl Iterator> { self.0.iter_mut() } } diff --git a/geo-types/src/novalue.rs b/geo-types/src/novalue.rs new file mode 100644 index 0000000000..b3e4db1835 --- /dev/null +++ b/geo-types/src/novalue.rs @@ -0,0 +1,95 @@ +#[cfg(any(feature = "approx", test))] +use approx::AbsDiffEq; +use num_traits::{One, Zero}; +use std::fmt::Debug; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; + +#[derive(Eq, PartialEq, PartialOrd, Clone, Copy, Debug, Hash, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct NoValue; + +impl Add for NoValue { + type Output = Self; + + fn add(self, _: Self) -> Self::Output { + NoValue::default() + } +} + +impl Div for NoValue { + type Output = Self; + + fn div(self, _: T) -> Self::Output { + NoValue::default() + } +} + +impl Mul for NoValue { + type Output = Self; + + fn mul(self, _: T) -> Self::Output { + NoValue::default() + } +} + +impl Neg for NoValue { + type Output = Self; + + fn neg(self) -> Self::Output { + NoValue::default() + } +} + +impl Rem for NoValue { + type Output = Self; + + fn rem(self, _: T) -> Self::Output { + NoValue::default() + } +} + +impl Sub for NoValue { + type Output = Self; + + fn sub(self, _: Self) -> Self::Output { + NoValue::default() + } +} + +/// This hack allows mathematical operations that result in noop due to above ops +impl Zero for NoValue { + fn zero() -> Self { + NoValue::default() + } + + fn is_zero(&self) -> bool { + true + } +} + +/// This hack allows mathematical operations that result in noop due to above ops +impl One for NoValue { + fn one() -> Self { + NoValue::default() + } +} + +#[cfg(any(feature = "approx", test))] +impl AbsDiffEq for NoValue { + type Epsilon = Self; + + fn default_epsilon() -> Self::Epsilon { + NoValue::default() + } + + fn abs_diff_eq(&self, _: &Self, _: Self::Epsilon) -> bool { + true + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for NoValue { + fn arbitrary(_: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Ok(NoValue::default()) + } +} diff --git a/geo-types/src/point.rs b/geo-types/src/point.rs index cb704d2a92..ca083464a7 100644 --- a/geo-types/src/point.rs +++ b/geo-types/src/point.rs @@ -1,4 +1,4 @@ -use crate::{point, CoordFloat, CoordNum, Coordinate}; +use crate::{point, CoordFloat, CoordNum, CoordTZM, Measure, NoValue, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -28,11 +28,16 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi /// ``` #[derive(Eq, PartialEq, Clone, Copy, Debug, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Point(pub Coordinate); +pub struct PointTZM(pub CoordTZM); -impl From> for Point { - fn from(x: Coordinate) -> Self { - Point(x) +pub type Point = PointTZM; +pub type PointM = PointTZM; +pub type PointZ = PointTZM; +pub type PointZM = PointTZM; + +impl From> for PointTZM { + fn from(x: CoordTZM) -> Self { + Self(x) } } @@ -76,7 +81,9 @@ impl Point { pub fn new(x: T, y: T) -> Self { point! { x: x, y: y } } +} +impl PointTZM { /// Returns the x/horizontal component of the point. /// /// # Examples @@ -157,71 +164,69 @@ impl Point { pub fn x_y(self) -> (T, T) { (self.0.x, self.0.y) } - /// Returns the longitude/horizontal component of the point. + + /// Returns the z component of the point. /// /// # Examples /// /// ``` - /// use geo_types::Point; + /// use geo_types::point; /// - /// let p = Point::new(1.234, 2.345); + /// let p = point! { x: 1.234, y: 2.345, z: 3.456 }; /// - /// assert_eq!(p.x(), 1.234); + /// assert_eq!(p.z(), 3.456); /// ``` - #[deprecated = "use `Point::x` instead, it's less ambiguous"] - pub fn lng(self) -> T { - self.x() + pub fn z(self) -> Z { + self.0.z } - /// Sets the longitude/horizontal component of the point. + /// Sets the z component of the point. /// /// # Examples /// /// ``` - /// use geo_types::Point; + /// use geo_types::point; /// - /// let mut p = Point::new(1.234, 2.345); - /// #[allow(deprecated)] - /// p.set_lng(9.876); + /// let mut p = point! { x: 1.234, y: 2.345, z: 3.456 }; /// - /// assert_eq!(p.x(), 9.876); + /// p.set_z(9.876); + /// assert_eq!(p.z(), 9.876); /// ``` - #[deprecated = "use `Point::set_x` instead, it's less ambiguous"] - pub fn set_lng(&mut self, lng: T) -> &mut Self { - self.set_x(lng) + pub fn set_z(&mut self, z: Z) -> &mut Self { + self.0.z = z; + self } - /// Returns the latitude/vertical component of the point. + /// Returns the m/measure component of the point. /// /// # Examples /// /// ``` - /// use geo_types::Point; + /// use geo_types::point; /// - /// let p = Point::new(1.234, 2.345); + /// let p = point! { x: 1.234, y: 2.345, z: 3.456, m: 100 }; /// - /// assert_eq!(p.y(), 2.345); + /// assert_eq!(p.m(), 100); /// ``` - #[deprecated = "use `Point::y` instead, it's less ambiguous"] - pub fn lat(self) -> T { - self.y() + pub fn m(self) -> M { + self.0.m } - /// Sets the latitude/vertical component of the point. + + /// Sets the m/measure component of the point. /// /// # Examples /// /// ``` - /// use geo_types::Point; + /// use geo_types::point; /// - /// let mut p = Point::new(1.234, 2.345); - /// #[allow(deprecated)] - /// p.set_lat(9.876); + /// let mut p = point! { x: 1.234, y: 2.345, z: 3.456, m: 100 }; /// - /// assert_eq!(p.y(), 9.876); + /// p.set_m(100); + /// assert_eq!(p.m(), 100); /// ``` - #[deprecated = "use `Point::set_y` instead, it's less ambiguous"] - pub fn set_lat(&mut self, lat: T) -> &mut Self { - self.set_y(lat) + pub fn set_m(&mut self, m: M) -> &mut Self { + self.0.m = m; + self } } @@ -609,9 +614,36 @@ where #[cfg(test)] mod test { use super::*; - + #[cfg(any(feature = "approx", test))] use approx::AbsDiffEq; + #[test] + fn test_point() { + let p: Point<_> = point! { x: 1.0, y: 2.0 }; + assert_relative_eq!(p.x(), 1.0); + assert_relative_eq!(p.y(), 2.0); + assert_eq!(p.z(), NoValue); + assert_eq!(p.m(), NoValue); + + let p: PointZ<_> = point! { x: 1.0, y: 2.0, z: 3.0 }; + assert_relative_eq!(p.x(), 1.0); + assert_relative_eq!(p.y(), 2.0); + assert_relative_eq!(p.z(), 3.0); + assert_eq!(p.m(), NoValue); + + let p: PointM<_, _> = point! { x: 1.0, y: 2.0, m: 4_u8 }; + assert_relative_eq!(p.x(), 1.0); + assert_relative_eq!(p.y(), 2.0); + assert_eq!(p.z(), NoValue); + assert_eq!(p.m(), 4_u8); + + let p: PointZM<_, _> = point! { x: 1_i32, y: 2_i32, z: 3_i32, m: 4.0_f64 }; + assert_eq!(p.x(), 1); + assert_eq!(p.y(), 2); + assert_eq!(p.z(), 3); + assert_relative_eq!(p.m(), 4.0); + } + #[test] fn test_abs_diff_eq() { let delta = 1e-6; diff --git a/geo-types/src/polygon.rs b/geo-types/src/polygon.rs index e450a4034b..8a8cfff00e 100644 --- a/geo-types/src/polygon.rs +++ b/geo-types/src/polygon.rs @@ -1,5 +1,4 @@ -use crate::{CoordFloat, CoordNum, LineString, Point, Rect, Triangle}; -use num_traits::{Float, Signed}; +use crate::{CoordNum, LineStringTZM, Measure, NoValue, Rect, TriangleTZM, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -66,12 +65,17 @@ use approx::{AbsDiffEq, RelativeEq}; /// [`LineString`]: line_string/struct.LineString.html #[derive(Eq, PartialEq, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Polygon { - exterior: LineString, - interiors: Vec>, +pub struct PolygonTZM { + exterior: LineStringTZM, + interiors: Vec>, } -impl Polygon { +pub type Polygon = PolygonTZM; +pub type PolygonM = PolygonTZM; +pub type PolygonZ = PolygonTZM; +pub type PolygonZM = PolygonTZM; + +impl PolygonTZM { /// Create a new `Polygon` with the provided exterior `LineString` ring and /// interior `LineString` rings. /// @@ -122,7 +126,10 @@ impl Polygon { /// &LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.),]) /// ); /// ``` - pub fn new(mut exterior: LineString, mut interiors: Vec>) -> Self { + pub fn new( + mut exterior: LineStringTZM, + mut interiors: Vec>, + ) -> Self { exterior.close(); for interior in &mut interiors { interior.close(); @@ -168,7 +175,8 @@ impl Polygon { /// ])] /// ); /// ``` - pub fn into_inner(self) -> (LineString, Vec>) { + #[allow(clippy::type_complexity)] + pub fn into_inner(self) -> (LineStringTZM, Vec>) { (self.exterior, self.interiors) } @@ -185,7 +193,7 @@ impl Polygon { /// /// assert_eq!(polygon.exterior(), &exterior); /// ``` - pub fn exterior(&self) -> &LineString { + pub fn exterior(&self) -> &LineStringTZM { &self.exterior } @@ -238,7 +246,7 @@ impl Polygon { /// [will be closed]: #linestring-closing-operation pub fn exterior_mut(&mut self, f: F) where - F: FnOnce(&mut LineString), + F: FnOnce(&mut LineStringTZM), { f(&mut self.exterior); self.exterior.close(); @@ -265,7 +273,7 @@ impl Polygon { /// /// assert_eq!(interiors, polygon.interiors()); /// ``` - pub fn interiors(&self) -> &[LineString] { + pub fn interiors(&self) -> &[LineStringTZM] { &self.interiors } @@ -340,7 +348,7 @@ impl Polygon { /// [will be closed]: #linestring-closing-operation pub fn interiors_mut(&mut self, f: F) where - F: FnOnce(&mut [LineString]), + F: FnOnce(&mut [LineStringTZM]), { f(&mut self.interiors); for interior in &mut self.interiors { @@ -378,67 +386,11 @@ impl Polygon { /// ``` /// /// [will be closed]: #linestring-closing-operation - pub fn interiors_push(&mut self, new_interior: impl Into>) { + pub fn interiors_push(&mut self, new_interior: impl Into>) { let mut new_interior = new_interior.into(); new_interior.close(); self.interiors.push(new_interior); } - - /// Wrap-around previous-vertex - fn previous_vertex(&self, current_vertex: usize) -> usize - where - T: Float, - { - (current_vertex + (self.exterior.0.len() - 1) - 1) % (self.exterior.0.len() - 1) - } -} - -// used to check the sign of a vec of floats -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum ListSign { - Empty, - Positive, - Negative, - Mixed, -} - -impl Polygon { - /// Determine whether a Polygon is convex - // For each consecutive pair of edges of the polygon (each triplet of points), - // compute the z-component of the cross product of the vectors defined by the - // edges pointing towards the points in increasing order. - // Take the cross product of these vectors - // The polygon is convex if the z-components of the cross products are either - // all positive or all negative. Otherwise, the polygon is non-convex. - // see: http://stackoverflow.com/a/1881201/416626 - #[deprecated( - since = "0.6.1", - note = "Please use `geo::is_convex` on `poly.exterior()` instead" - )] - pub fn is_convex(&self) -> bool { - let convex = self - .exterior - .0 - .iter() - .enumerate() - .map(|(idx, _)| { - let prev_1 = self.previous_vertex(idx); - let prev_2 = self.previous_vertex(prev_1); - Point::from(self.exterior[prev_2]).cross_prod( - Point::from(self.exterior[prev_1]), - Point::from(self.exterior[idx]), - ) - }) - // accumulate and check cross-product result signs in a single pass - // positive implies ccw convexity, negative implies cw convexity - // anything else implies non-convexity - .fold(ListSign::Empty, |acc, n| match (acc, n.is_positive()) { - (ListSign::Empty, true) | (ListSign::Positive, true) => ListSign::Positive, - (ListSign::Empty, false) | (ListSign::Negative, false) => ListSign::Negative, - _ => ListSign::Mixed, - }); - convex != ListSign::Mixed - } } impl From> for Polygon { @@ -457,9 +409,9 @@ impl From> for Polygon { } } -impl From> for Polygon { - fn from(t: Triangle) -> Self { - Polygon::new(vec![t.0, t.1, t.2, t.0].into(), Vec::new()) +impl From> for PolygonTZM { + fn from(t: TriangleTZM) -> Self { + Self::new(vec![t.0, t.1, t.2, t.0].into(), Vec::new()) } } diff --git a/geo-types/src/private_utils.rs b/geo-types/src/private_utils.rs index a70e68e1c7..db831095fa 100644 --- a/geo-types/src/private_utils.rs +++ b/geo-types/src/private_utils.rs @@ -3,45 +3,55 @@ // hidden module is public so the geo crate can reuse these algorithms to // prevent duplication. These functions are _not_ meant for public consumption. -use crate::{CoordFloat, CoordNum, Coordinate, Line, LineString, Point, Rect}; +use crate::{ + CoordFloat, CoordNum, CoordTZM, Coordinate, Line, LineM, LineString, LineStringTZM, LineTZM, + Measure, Point, RectTZM, ZCoord, +}; -pub fn line_string_bounding_rect(line_string: &LineString) -> Option> -where - T: CoordNum, -{ +pub fn line_string_bounding_rect( + line_string: &LineStringTZM, +) -> Option> { get_bounding_rect(line_string.coords().cloned()) } -pub fn line_bounding_rect(line: Line) -> Rect -where - T: CoordNum, -{ - Rect::new(line.start, line.end) +pub fn line_bounding_rect( + line: LineTZM, +) -> RectTZM { + RectTZM::new(line.start, line.end) } -pub fn get_bounding_rect(collection: I) -> Option> +pub fn get_bounding_rect(collection: I) -> Option> where T: CoordNum, - I: IntoIterator>, + Z: ZCoord, + M: Measure, + I: IntoIterator>, { let mut iter = collection.into_iter(); if let Some(pnt) = iter.next() { let mut xrange = (pnt.x, pnt.x); let mut yrange = (pnt.y, pnt.y); + let mut zrange = (pnt.z, pnt.z); + let mut mrange = (pnt.m, pnt.m); for pnt in iter { - let (px, py) = pnt.x_y(); - xrange = get_min_max(px, xrange.0, xrange.1); - yrange = get_min_max(py, yrange.0, yrange.1); + xrange = get_min_max(pnt.x, xrange.0, xrange.1); + yrange = get_min_max(pnt.y, yrange.0, yrange.1); + zrange = get_min_max(pnt.z, zrange.0, zrange.1); + mrange = get_min_max(pnt.m, mrange.0, mrange.1); } - return Some(Rect::new( + return Some(RectTZM::new( coord! { x: xrange.0, y: yrange.0, + z: zrange.0, + m: mrange.0, }, coord! { x: xrange.1, y: yrange.1, + z: zrange.1, + m: mrange.1, }, )); } @@ -83,10 +93,7 @@ where s.abs() * dx.hypot(dy) } -pub fn line_euclidean_length(line: Line) -> T -where - T: CoordFloat, -{ +pub fn line_euclidean_length(line: LineM) -> T { line.dx().hypot(line.dy()) } diff --git a/geo-types/src/rect.rs b/geo-types/src/rect.rs index 2c7e0bc526..f9f185853d 100644 --- a/geo-types/src/rect.rs +++ b/geo-types/src/rect.rs @@ -1,7 +1,8 @@ -use crate::{coord, polygon, CoordFloat, CoordNum, Coordinate, Line, Polygon}; +use crate::{coord, polygon, CoordNum, CoordTZM, Line, Measure, NoValue, Polygon, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; +use num_traits::{NumOps, One}; /// An _axis-aligned_ bounded 2D rectangle whose area is /// defined by minimum and maximum `Coordinate`s. @@ -39,12 +40,17 @@ use approx::{AbsDiffEq, RelativeEq}; /// ``` #[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Rect { - min: Coordinate, - max: Coordinate, +pub struct RectTZM { + min: CoordTZM, + max: CoordTZM, } -impl Rect { +pub type Rect = RectTZM; +pub type RectM = RectTZM; +pub type RectZ = RectTZM; +pub type RectZM = RectTZM; + +impl RectTZM { /// Creates a new rectangle from two corner coordinates. /// /// # Examples @@ -61,7 +67,7 @@ impl Rect { /// ``` pub fn new(c1: C, c2: C) -> Self where - C: Into>, + C: Into>, { let c1 = c1.into(); let c2 = c2.into(); @@ -75,24 +81,22 @@ impl Rect { } else { (c2.y, c1.y) }; + let (min_z, max_z) = if c1.z < c2.z { + (c1.z, c2.z) + } else { + (c2.z, c1.z) + }; + let (min_m, max_m) = if c1.m < c2.m { + (c1.m, c2.m) + } else { + (c2.m, c1.m) + }; Self { - min: coord! { x: min_x, y: min_y }, - max: coord! { x: max_x, y: max_y }, + min: coord! { x: min_x, y: min_y, z: min_z, m: min_m }, + max: coord! { x: max_x, y: max_y, z: max_z, m: max_m }, } } - #[deprecated( - since = "0.6.2", - note = "Use `Rect::new` instead, since `Rect::try_new` will never Error" - )] - #[allow(deprecated)] - pub fn try_new(c1: C, c2: C) -> Result, InvalidRectCoordinatesError> - where - C: Into>, - { - Ok(Rect::new(c1, c2)) - } - /// Returns the minimum `Coordinate` of the `Rect`. /// /// # Examples @@ -107,7 +111,7 @@ impl Rect { /// /// assert_eq!(rect.min(), coord! { x: 5., y: 5. }); /// ``` - pub fn min(self) -> Coordinate { + pub fn min(self) -> CoordTZM { self.min } @@ -116,10 +120,7 @@ impl Rect { /// # Panics /// /// Panics if `min`’s x/y is greater than the maximum coordinate’s x/y. - pub fn set_min(&mut self, min: C) - where - C: Into>, - { + pub fn set_min>>(&mut self, min: C) { self.min = min.into(); self.assert_valid_bounds(); } @@ -138,7 +139,7 @@ impl Rect { /// /// assert_eq!(rect.max(), coord! { x: 15., y: 15. }); /// ``` - pub fn max(self) -> Coordinate { + pub fn max(self) -> CoordTZM { self.max } @@ -147,10 +148,7 @@ impl Rect { /// # Panics /// /// Panics if `max`’s x/y is less than the minimum coordinate’s x/y. - pub fn set_max(&mut self, max: C) - where - C: Into>, - { + pub fn set_max>>(&mut self, max: C) { self.max = max.into(); self.assert_valid_bounds(); } @@ -280,26 +278,50 @@ impl Rect { } } -impl Rect { +impl RectTZM +where + T: CoordNum, + Z: ZCoord + One + NumOps, + M: Measure + One + NumOps, +{ /// Returns the center `Coordinate` of the `Rect`. /// /// # Examples /// /// ```rust - /// use geo_types::{coord, Rect}; + /// use geo_types::{coord, Rect, RectZ, RectM, RectZM}; /// /// let rect = Rect::new( /// coord! { x: 5., y: 5. }, /// coord! { x: 15., y: 15. }, /// ); - /// /// assert_eq!(rect.center(), coord! { x: 10., y: 10. }); + /// + /// let rect = RectZ::new( + /// coord! { x: 1., y: 2., z: 3. }, + /// coord! { x: 3., y: 4., z: 5. }, + /// ); + /// assert_eq!(rect.center(), coord! { x: 2., y: 3., z: 4. }); + /// + /// let rect = RectM::new( + /// coord! { x: 1., y: 2., m: 4. }, + /// coord! { x: 3., y: 4., m: 6. }, + /// ); + /// assert_eq!(rect.center(), coord! { x: 2., y: 3., m: 5. }); + /// + /// let rect = RectZM::new( + /// coord! { x: 1., y: 2., z: 3., m: 4. }, + /// coord! { x: 3., y: 4., z: 5., m: 6. }, + /// ); + /// assert_eq!(rect.center(), coord! { x: 2., y: 3., z: 4., m: 5. }); /// ``` - pub fn center(self) -> Coordinate { + pub fn center(self) -> CoordTZM { let two = T::one() + T::one(); coord! { x: (self.max.x + self.min.x) / two, y: (self.max.y + self.min.y) / two, + z: (self.max.z + self.min.z) / (Z::one() + Z::one()), + m: (self.max.m + self.min.m) / (M::one() + M::one()), } } } @@ -388,27 +410,9 @@ where } } -#[deprecated( - since = "0.6.2", - note = "Use `Rect::new` instead, since `Rect::try_new` will never Error" -)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct InvalidRectCoordinatesError; - -#[allow(deprecated)] -impl std::error::Error for InvalidRectCoordinatesError {} - -#[allow(deprecated)] -impl std::fmt::Display for InvalidRectCoordinatesError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", RECT_INVALID_BOUNDS_ERROR) - } -} - #[cfg(test)] mod test { - use super::*; - use crate::coord; + use crate::{coord, Coordinate, Rect}; #[test] fn rect() { diff --git a/geo-types/src/triangle.rs b/geo-types/src/triangle.rs index 7cd54da0d1..1b98358fd7 100644 --- a/geo-types/src/triangle.rs +++ b/geo-types/src/triangle.rs @@ -1,4 +1,4 @@ -use crate::{polygon, CoordNum, Coordinate, Line, Polygon}; +use crate::{polygon, CoordNum, CoordTZM, LineTZM, Measure, NoValue, PolygonTZM, ZCoord}; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; @@ -9,23 +9,32 @@ use approx::{AbsDiffEq, RelativeEq}; /// vertices must not be collinear and they must be distinct. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Triangle(pub Coordinate, pub Coordinate, pub Coordinate); +pub struct TriangleTZM( + pub CoordTZM, + pub CoordTZM, + pub CoordTZM, +); -impl Triangle { +pub type Triangle = TriangleTZM; +pub type TriangleM = TriangleTZM; +pub type TriangleZ = TriangleTZM; +pub type TriangleZM = TriangleTZM; + +impl TriangleTZM { /// Instantiate Self from the raw content value - pub fn new(v1: Coordinate, v2: Coordinate, v3: Coordinate) -> Self { + pub fn new(v1: CoordTZM, v2: CoordTZM, v3: CoordTZM) -> Self { Self(v1, v2, v3) } - pub fn to_array(&self) -> [Coordinate; 3] { + pub fn to_array(&self) -> [CoordTZM; 3] { [self.0, self.1, self.2] } - pub fn to_lines(&self) -> [Line; 3] { + pub fn to_lines(&self) -> [LineTZM; 3] { [ - Line::new(self.0, self.1), - Line::new(self.1, self.2), - Line::new(self.2, self.0), + LineTZM::new(self.0, self.1), + LineTZM::new(self.1, self.2), + LineTZM::new(self.2, self.0), ] } @@ -52,12 +61,14 @@ impl Triangle { /// ], /// ); /// ``` - pub fn to_polygon(self) -> Polygon { + pub fn to_polygon(self) -> PolygonTZM { polygon![self.0, self.1, self.2, self.0] } } -impl> + Copy, T: CoordNum> From<[IC; 3]> for Triangle { +impl> + Copy, T: CoordNum, Z: ZCoord, M: Measure> From<[IC; 3]> + for TriangleTZM +{ fn from(array: [IC; 3]) -> Self { Self(array[0].into(), array[1].into(), array[2].into()) } diff --git a/geo/Cargo.toml b/geo/Cargo.toml index 800d161167..1cfa3f64fa 100644 --- a/geo/Cargo.toml +++ b/geo/Cargo.toml @@ -17,7 +17,7 @@ proj-network = ["use-proj", "proj/network"] use-serde = ["serde", "geo-types/serde"] [dependencies] -geo-types = { version = "0.7.3", features = ["approx", "use-rstar"] } +geo-types = { version = "0.7.4", features = ["approx", "use-rstar"] } geographiclib-rs = "0.2" log = "0.4.11" num-traits = "0.2" diff --git a/geo/fuzz/Cargo.toml b/geo/fuzz/Cargo.toml index fc1ce9524c..6a5290b4c1 100644 --- a/geo/fuzz/Cargo.toml +++ b/geo/fuzz/Cargo.toml @@ -16,7 +16,8 @@ path = ".." [dependencies.geo-types] features = ["arbitrary"] -path = "../../geo-types" +# Uncomment after geo-types 0.8+ is published with TZM support +# path = "../../geo-types" # Prevent this from interfering with workspaces [workspace] @@ -30,4 +31,5 @@ doc = false [patch.crates-io] geo = { path = ".." } -geo-types = { path = "../../geo-types" } +# Uncomment after geo-types 0.8+ is published with TZM support +# geo-types = { path = "../../geo-types" }