diff --git a/geo/src/algorithm/affine_ops.rs b/geo/src/algorithm/affine_ops.rs index c228c4210..eb2ecbfb0 100644 --- a/geo/src/algorithm/affine_ops.rs +++ b/geo/src/algorithm/affine_ops.rs @@ -1,4 +1,7 @@ +use crate::num_traits::{One, Zero}; +use crate::traits::CoordTrait; use crate::{CoordFloat, CoordNum, Coordinate, MapCoords, MapCoordsInPlace}; + use std::fmt; /// Apply an [`AffineTransform`] like [`scale`](AffineTransform::scale), @@ -35,21 +38,27 @@ use std::fmt; /// (x: -0.5688687, y: 5.5688687) /// ], max_relative = 1.0); /// ``` -pub trait AffineOps { +pub trait AffineOps { + type Coord: CoordTrait; + /// Apply `transform` immutably, outputting a new geometry. #[must_use] - fn affine_transform(&self, transform: &AffineTransform) -> Self; + fn affine_transform(&self, transform: &AffineTransform) -> Self; /// Apply `transform` to mutate `self`. - fn affine_transform_mut(&mut self, transform: &AffineTransform); + fn affine_transform_mut(&mut self, transform: &AffineTransform); } -impl + MapCoords> AffineOps for M { - fn affine_transform(&self, transform: &AffineTransform) -> Self { +impl + MapCoords> + AffineOps for M +{ + type Coord = C; + + fn affine_transform(&self, transform: &AffineTransform) -> Self { self.map_coords(|c| transform.apply(c)) } - fn affine_transform_mut(&mut self, transform: &AffineTransform) { + fn affine_transform_mut(&mut self, transform: &AffineTransform) { self.map_coords_in_place(|c| transform.apply(c)) } } @@ -111,58 +120,61 @@ impl + MapCoords> Affin /// ], max_relative = 1.0); /// ``` #[derive(Copy, Clone, PartialEq, Eq)] -pub struct AffineTransform([[T; 3]; 3]); +pub struct AffineTransform> { + matrix: [[C::Scalar; 3]; 3], +} -impl Default for AffineTransform { +impl Default for AffineTransform { fn default() -> Self { // identity matrix Self::identity() } } -impl AffineTransform { +impl AffineTransform { /// Create a new affine transformation by composing two `AffineTransform`s. /// /// This is a **cumulative** operation; the new transform is *added* to the existing transform. #[must_use] pub fn compose(&self, other: &Self) -> Self { // lol - Self([ + let matrix = [ [ - (self.0[0][0] * other.0[0][0]) - + (self.0[0][1] * other.0[1][0]) - + (self.0[0][2] * other.0[2][0]), - (self.0[0][0] * other.0[0][1]) - + (self.0[0][1] * other.0[1][1]) - + (self.0[0][2] * other.0[2][1]), - (self.0[0][0] * other.0[0][2]) - + (self.0[0][1] * other.0[1][2]) - + (self.0[0][2] * other.0[2][2]), + (self.matrix[0][0] * other.matrix[0][0]) + + (self.matrix[0][1] * other.matrix[1][0]) + + (self.matrix[0][2] * other.matrix[2][0]), + (self.matrix[0][0] * other.matrix[0][1]) + + (self.matrix[0][1] * other.matrix[1][1]) + + (self.matrix[0][2] * other.matrix[2][1]), + (self.matrix[0][0] * other.matrix[0][2]) + + (self.matrix[0][1] * other.matrix[1][2]) + + (self.matrix[0][2] * other.matrix[2][2]), ], [ - (self.0[1][0] * other.0[0][0]) - + (self.0[1][1] * other.0[1][0]) - + (self.0[1][2] * other.0[2][0]), - (self.0[1][0] * other.0[0][1]) - + (self.0[1][1] * other.0[1][1]) - + (self.0[1][2] * other.0[2][1]), - (self.0[1][0] * other.0[0][2]) - + (self.0[1][1] * other.0[1][2]) - + (self.0[1][2] * other.0[2][2]), + (self.matrix[1][0] * other.matrix[0][0]) + + (self.matrix[1][1] * other.matrix[1][0]) + + (self.matrix[1][2] * other.matrix[2][0]), + (self.matrix[1][0] * other.matrix[0][1]) + + (self.matrix[1][1] * other.matrix[1][1]) + + (self.matrix[1][2] * other.matrix[2][1]), + (self.matrix[1][0] * other.matrix[0][2]) + + (self.matrix[1][1] * other.matrix[1][2]) + + (self.matrix[1][2] * other.matrix[2][2]), ], [ // this section isn't technically necessary since the last row is invariant: [0, 0, 1] - (self.0[2][0] * other.0[0][0]) - + (self.0[2][1] * other.0[1][0]) - + (self.0[2][2] * other.0[2][0]), - (self.0[2][0] * other.0[0][1]) - + (self.0[2][1] * other.0[1][1]) - + (self.0[2][2] * other.0[2][1]), - (self.0[2][0] * other.0[0][2]) - + (self.0[2][1] * other.0[1][2]) - + (self.0[2][2] * other.0[2][2]), + (self.matrix[2][0] * other.matrix[0][0]) + + (self.matrix[2][1] * other.matrix[1][0]) + + (self.matrix[2][2] * other.matrix[2][0]), + (self.matrix[2][0] * other.matrix[0][1]) + + (self.matrix[2][1] * other.matrix[1][1]) + + (self.matrix[2][2] * other.matrix[2][1]), + (self.matrix[2][0] * other.matrix[0][2]) + + (self.matrix[2][1] * other.matrix[1][2]) + + (self.matrix[2][2] * other.matrix[2][2]), ], - ]) + ]; + Self { matrix } } /// Create the identity matrix /// @@ -174,12 +186,12 @@ impl AffineTransform { /// ``` pub fn identity() -> Self { Self::new( - T::one(), - T::zero(), - T::zero(), - T::zero(), - T::one(), - T::zero(), + C::Scalar::one(), + C::Scalar::zero(), + C::Scalar::zero(), + C::Scalar::zero(), + C::Scalar::one(), + C::Scalar::zero(), ) } @@ -217,11 +229,22 @@ impl AffineTransform { /// xoff = origin.x - (origin.x * xfact) /// yoff = origin.y - (origin.y * yfact) /// ``` - pub fn scale(xfact: T, yfact: T, origin: impl Into>) -> Self { + pub fn scale( + xfact: C::Scalar, + yfact: C::Scalar, + origin: impl Into>, + ) -> Self { let (x0, y0) = origin.into().x_y(); let xoff = x0 - (x0 * xfact); let yoff = y0 - (y0 * yfact); - Self::new(xfact, T::zero(), xoff, T::zero(), yfact, yoff) + Self::new( + xfact, + C::Scalar::zero(), + xoff, + C::Scalar::zero(), + yfact, + yoff, + ) } /// **Add** an affine transform for scaling, scaled by factors along the `x` and `y` dimensions. @@ -230,8 +253,13 @@ impl AffineTransform { /// Negative scale factors will mirror or reflect coordinates. /// This is a **cumulative** operation; the new transform is *added* to the existing transform. #[must_use] - pub fn scaled(mut self, xfact: T, yfact: T, origin: impl Into>) -> Self { - self.0 = self.compose(&Self::scale(xfact, yfact, origin)).0; + pub fn scaled( + mut self, + xfact: C::Scalar, + yfact: C::Scalar, + origin: impl Into>, + ) -> Self { + self.matrix = self.compose(&Self::scale(xfact, yfact, origin)).matrix; self } @@ -243,25 +271,32 @@ impl AffineTransform { /// [0, 1, yoff], /// [0, 0, 1]] /// ``` - pub fn translate(xoff: T, yoff: T) -> Self { - Self::new(T::one(), T::zero(), xoff, T::zero(), T::one(), yoff) + pub fn translate(xoff: C::Scalar, yoff: C::Scalar) -> Self { + Self::new( + C::Scalar::one(), + C::Scalar::zero(), + xoff, + C::Scalar::zero(), + C::Scalar::one(), + yoff, + ) } /// **Add** an affine transform for translation, shifted by offsets along the `x` and `y` dimensions /// /// This is a **cumulative** operation; the new transform is *added* to the existing transform. #[must_use] - pub fn translated(mut self, xoff: T, yoff: T) -> Self { - self.0 = self.compose(&Self::translate(xoff, yoff)).0; + pub fn translated(mut self, xoff: C::Scalar, yoff: C::Scalar) -> Self { + self.matrix = self.compose(&Self::translate(xoff, yoff)).matrix; self } /// Apply the current transform to a coordinate - pub fn apply(&self, coord: Coordinate) -> Coordinate { - Coordinate { - x: (self.0[0][0] * coord.x + self.0[0][1] * coord.y + self.0[0][2]), - y: (self.0[1][0] * coord.x + self.0[1][1] * coord.y + self.0[1][2]), - } + pub fn apply(&self, coord: C) -> C { + C::from_xy( + self.matrix[0][0] * coord.x() + self.matrix[0][1] * coord.y() + self.matrix[0][2], + self.matrix[1][0] * coord.x() + self.matrix[1][1] * coord.y() + self.matrix[1][2], + ) } /// Create a new custom transform matrix @@ -272,37 +307,49 @@ impl AffineTransform { /// [d, e, yoff], /// [0, 0, 1]] <-- not part of the input arguments /// ``` - pub fn new(a: T, b: T, xoff: T, d: T, e: T, yoff: T) -> Self { - Self([[a, b, xoff], [d, e, yoff], [T::zero(), T::zero(), T::one()]]) + pub fn new( + a: C::Scalar, + b: C::Scalar, + xoff: C::Scalar, + d: C::Scalar, + e: C::Scalar, + yoff: C::Scalar, + ) -> Self { + let matrix = [ + [a, b, xoff], + [d, e, yoff], + [C::Scalar::zero(), C::Scalar::zero(), C::Scalar::one()], + ]; + Self { matrix } } } -impl fmt::Debug for AffineTransform { +impl fmt::Debug for AffineTransform> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AffineTransform") - .field("a", &self.0[0][0]) - .field("b", &self.0[0][1]) - .field("xoff", &self.0[1][2]) - .field("d", &self.0[1][0]) - .field("e", &self.0[1][1]) - .field("yoff", &self.0[1][2]) + .field("a", &self.matrix[0][0]) + .field("b", &self.matrix[0][1]) + .field("xoff", &self.matrix[1][2]) + .field("d", &self.matrix[1][0]) + .field("e", &self.matrix[1][1]) + .field("yoff", &self.matrix[1][2]) .finish() } } -impl From<[T; 6]> for AffineTransform { +impl From<[T; 6]> for AffineTransform> { fn from(arr: [T; 6]) -> Self { Self::new(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]) } } -impl From<(T, T, T, T, T, T)> for AffineTransform { +impl From<(T, T, T, T, T, T)> for AffineTransform> { fn from(tup: (T, T, T, T, T, T)) -> Self { Self::new(tup.0, tup.1, tup.2, tup.3, tup.4, tup.5) } } -impl AffineTransform { +impl> AffineTransform { /// **Create** an affine transform for rotation, using an arbitrary point as its centre. /// /// Note that this operation is only available for geometries with floating point coordinates. @@ -335,7 +382,7 @@ impl AffineTransform { /// This is a **cumulative** operation; the new transform is *added* to the existing transform. #[must_use] pub fn rotated(mut self, angle: U, origin: impl Into>) -> Self { - self.0 = self.compose(&Self::rotate(angle, origin)).0; + self.matrix = self.compose(&Self::rotate(angle, origin)).matrix; self } @@ -382,7 +429,7 @@ impl AffineTransform { /// This is a **cumulative** operation; the new transform is *added* to the existing transform. #[must_use] pub fn skewed(mut self, xs: U, ys: U, origin: impl Into>) -> Self { - self.0 = self.compose(&Self::skew(xs, ys, origin)).0; + self.matrix = self.compose(&Self::skew(xs, ys, origin)).matrix; self } } @@ -398,21 +445,21 @@ mod tests { // [0, 0, 1]] #[test] fn matrix_multiply() { - let a = AffineTransform::new(1, 2, 5, 3, 4, 6); + let a = AffineTransform::>::new(1, 2, 5, 3, 4, 6); let b = AffineTransform::new(7, 8, 11, 9, 10, 12); let composed = a.compose(&b); - assert_eq!(composed.0[0][0], 25); - assert_eq!(composed.0[0][1], 28); - assert_eq!(composed.0[0][2], 40); - assert_eq!(composed.0[1][0], 57); - assert_eq!(composed.0[1][1], 64); - assert_eq!(composed.0[1][2], 87); + assert_eq!(composed.matrix[0][0], 25); + assert_eq!(composed.matrix[0][1], 28); + assert_eq!(composed.matrix[0][2], 40); + assert_eq!(composed.matrix[1][0], 57); + assert_eq!(composed.matrix[1][1], 64); + assert_eq!(composed.matrix[1][2], 87); } #[test] fn test_transform_composition() { let p0 = Point::new(0.0f64, 0.0); // scale once - let mut scale_a = AffineTransform::default().scaled(2.0, 2.0, p0); + let mut scale_a = AffineTransform::>::default().scaled(2.0, 2.0, p0); // rotate scale_a = scale_a.rotated(45.0, p0); // rotate back @@ -420,11 +467,11 @@ mod tests { // scale up again, doubling scale_a = scale_a.scaled(2.0, 2.0, p0); // scaled once - let scale_b = AffineTransform::default().scaled(2.0, 2.0, p0); + let scale_b = AffineTransform::>::default().scaled(2.0, 2.0, p0); // scaled once, but equal to 2 + 2 - let scale_c = AffineTransform::default().scaled(4.0, 4.0, p0); - assert_ne!(&scale_a.0, &scale_b.0); - assert_eq!(&scale_a.0, &scale_c.0); + let scale_c = AffineTransform::>::default().scaled(4.0, 4.0, p0); + assert_ne!(&scale_a.matrix, &scale_b.matrix); + assert_eq!(&scale_a.matrix, &scale_c.matrix); } #[test] diff --git a/geo/src/algorithm/convert.rs b/geo/src/algorithm/convert.rs index 1d8eb7de5..0015add1f 100644 --- a/geo/src/algorithm/convert.rs +++ b/geo/src/algorithm/convert.rs @@ -23,10 +23,10 @@ pub trait Convert { } impl Convert for G where - G: MapCoords, + G: MapCoords, InCoord = Coordinate>, U: From, { - type Output = >::Output; + type Output = >>::Output; fn convert(&self) -> Self::Output { self.map_coords(|Coordinate { x, y }| Coordinate { @@ -59,10 +59,10 @@ pub trait TryConvert { } impl TryConvert for G where - G: MapCoords, + G: MapCoords, InCoord = Coordinate>, U: TryFrom, { - type Output = Result<>::Output, >::Error>; + type Output = Result<>>::Output, >::Error>; fn try_convert(&self) -> Self::Output { self.try_map_coords(|Coordinate { x, y }| { diff --git a/geo/src/algorithm/map_coords.rs b/geo/src/algorithm/map_coords.rs index 5e8ec4ad0..63a70249f 100644 --- a/geo/src/algorithm/map_coords.rs +++ b/geo/src/algorithm/map_coords.rs @@ -27,11 +27,13 @@ pub use modern::*; mod modern { pub(crate) use crate::geometry::*; + use crate::traits::{CoordTrait, GeometryTrait}; pub(crate) use crate::CoordNum; /// Map a function over all the coordinates in an object, returning a new one - pub trait MapCoords { - type Output; + pub trait MapCoords { + type InCoord: CoordTrait; + type Output: GeometryTrait; /// Apply a function to all the coordinates in a geometric object, returning a new object. /// @@ -70,10 +72,7 @@ mod modern { /// /// If you want *only* to convert between numeric types (i32 -> f64) without further /// transformation, consider using [`Convert`](crate::Convert). - fn map_coords(&self, func: impl Fn(Coordinate) -> Coordinate + Copy) -> Self::Output - where - T: CoordNum, - NT: CoordNum; + fn map_coords(&self, func: impl Fn(Self::InCoord) -> OutCoord + Copy) -> Self::Output; /// Map a fallible function over all the coordinates in a geometry, returning a Result /// @@ -120,14 +119,13 @@ mod modern { /// ``` fn try_map_coords( &self, - func: impl Fn(Coordinate) -> Result, E> + Copy, - ) -> Result - where - T: CoordNum, - NT: CoordNum; + func: impl Fn(Self::InCoord) -> Result + Copy, + ) -> Result; } - pub trait MapCoordsInPlace { + pub trait MapCoordsInPlace { + type Coord: CoordTrait; + /// Apply a function to all the coordinates in a geometric object, in place /// /// # Examples @@ -142,9 +140,7 @@ mod modern { /// /// assert_relative_eq!(p, Point::new(1010., 40.), epsilon = 1e-6); /// ``` - fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) - where - T: CoordNum; + fn map_coords_in_place(&mut self, func: impl Fn(Self::Coord) -> Self::Coord + Copy); /// Map a fallible function over all the coordinates in a geometry, in place, returning a `Result`. /// @@ -174,17 +170,16 @@ mod modern { /// ``` fn try_map_coords_in_place( &mut self, - func: impl Fn(Coordinate) -> Result, E>, - ) -> Result<(), E> - where - T: CoordNum; + func: impl Fn(Self::Coord) -> Result, + ) -> Result<(), E>; } //-----------------------// // Point implementations // //-----------------------// - impl MapCoords for Point { + impl MapCoords> for Point { + type InCoord = Coordinate; type Output = Point; fn map_coords( @@ -202,7 +197,9 @@ mod modern { } } - impl MapCoordsInPlace for Point { + impl MapCoordsInPlace for Point { + type Coord = Coordinate; + fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate) { self.0 = func(self.0); } @@ -220,7 +217,8 @@ mod modern { // Line implementations // //----------------------// - impl MapCoords for Line { + impl MapCoords> for Line { + type InCoord = Coordinate; type Output = Line; fn map_coords( @@ -244,7 +242,9 @@ mod modern { } } - impl MapCoordsInPlace for Line { + impl MapCoordsInPlace for Line { + type Coord = Coordinate; + fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate) { self.start = func(self.start); self.end = func(self.end); @@ -265,7 +265,8 @@ mod modern { // LineString implementations // //----------------------------// - impl MapCoords for LineString { + impl MapCoords> for LineString { + type InCoord = Coordinate; type Output = LineString; fn map_coords( @@ -291,7 +292,8 @@ mod modern { } } - impl MapCoordsInPlace for LineString { + impl MapCoordsInPlace for LineString { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate) { for p in &mut self.0 { *p = func(*p); @@ -313,7 +315,8 @@ mod modern { // Polygon implementations // //-------------------------// - impl MapCoords for Polygon { + impl MapCoords> for Polygon { + type InCoord = Coordinate; type Output = Polygon; fn map_coords( @@ -343,7 +346,8 @@ mod modern { } } - impl MapCoordsInPlace for Polygon { + impl MapCoordsInPlace for Polygon { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { self.exterior_mut(|line_string| { line_string.map_coords_in_place(func); @@ -387,7 +391,8 @@ mod modern { // MultiPoint implementations // //----------------------------// - impl MapCoords for MultiPoint { + impl MapCoords> for MultiPoint { + type InCoord = Coordinate; type Output = MultiPoint; fn map_coords( @@ -410,7 +415,8 @@ mod modern { } } - impl MapCoordsInPlace for MultiPoint { + impl MapCoordsInPlace for MultiPoint { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { for p in &mut self.0 { p.map_coords_in_place(func); @@ -432,7 +438,8 @@ mod modern { // MultiLineString implementations // //---------------------------------// - impl MapCoords for MultiLineString { + impl MapCoords> for MultiLineString { + type InCoord = Coordinate; type Output = MultiLineString; fn map_coords( @@ -455,7 +462,8 @@ mod modern { } } - impl MapCoordsInPlace for MultiLineString { + impl MapCoordsInPlace for MultiLineString { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { for p in &mut self.0 { p.map_coords_in_place(func); @@ -477,7 +485,8 @@ mod modern { // MultiPolygon implementations // //------------------------------// - impl MapCoords for MultiPolygon { + impl MapCoords> for MultiPolygon { + type InCoord = Coordinate; type Output = MultiPolygon; fn map_coords( @@ -500,7 +509,8 @@ mod modern { } } - impl MapCoordsInPlace for MultiPolygon { + impl MapCoordsInPlace for MultiPolygon { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { for p in &mut self.0 { p.map_coords_in_place(func); @@ -522,7 +532,8 @@ mod modern { // Geometry implementations // //--------------------------// - impl MapCoords for Geometry { + impl MapCoords> for Geometry { + type InCoord = Coordinate; type Output = Geometry; fn map_coords( @@ -570,7 +581,8 @@ mod modern { } } - impl MapCoordsInPlace for Geometry { + impl MapCoordsInPlace for Geometry { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { match *self { Geometry::Point(ref mut x) => x.map_coords_in_place(func), @@ -609,7 +621,8 @@ mod modern { // GeometryCollection implementations // //------------------------------------// - impl MapCoords for GeometryCollection { + impl MapCoords> for GeometryCollection { + type InCoord = Coordinate; type Output = GeometryCollection; fn map_coords( @@ -632,7 +645,8 @@ mod modern { } } - impl MapCoordsInPlace for GeometryCollection { + impl MapCoordsInPlace for GeometryCollection { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate + Copy) { for p in &mut self.0 { p.map_coords_in_place(func); @@ -654,7 +668,8 @@ mod modern { // Rect implementations // //----------------------// - impl MapCoords for Rect { + impl MapCoords> for Rect { + type InCoord = Coordinate; type Output = Rect; fn map_coords( @@ -672,7 +687,8 @@ mod modern { } } - impl MapCoordsInPlace for Rect { + impl MapCoordsInPlace for Rect { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate) { let mut new_rect = Rect::new(func(self.min()), func(self.max())); ::std::mem::swap(self, &mut new_rect); @@ -692,7 +708,8 @@ mod modern { // Triangle implementations // //--------------------------// - impl MapCoords for Triangle { + impl MapCoords> for Triangle { + type InCoord = Coordinate; type Output = Triangle; fn map_coords( @@ -710,7 +727,8 @@ mod modern { } } - impl MapCoordsInPlace for Triangle { + impl MapCoordsInPlace for Triangle { + type Coord = Coordinate; fn map_coords_in_place(&mut self, func: impl Fn(Coordinate) -> Coordinate) { let mut new_triangle = Triangle::new(func(self.0), func(self.1), func(self.2)); @@ -843,7 +861,7 @@ pub(crate) mod deprecated { since = "0.21.0", note = "use `MapCoordsInPlace::map_coords_in_place` instead which takes a `Coordinate` instead of an (x,y) tuple" )] - pub trait MapCoordsInplace: MapCoordsInPlace { + pub trait MapCoordsInplace: MapCoordsInPlace { /// Apply a function to all the coordinates in a geometric object, in place /// /// # Examples diff --git a/geo/src/algorithm/rotate.rs b/geo/src/algorithm/rotate.rs index cea2b432b..a9ec5fc05 100644 --- a/geo/src/algorithm/rotate.rs +++ b/geo/src/algorithm/rotate.rs @@ -1,5 +1,6 @@ use crate::algorithm::{AffineOps, AffineTransform, BoundingRect, Centroid}; use crate::geometry::*; +use crate::traits::CoordTrait; use crate::CoordFloat; /// Rotate a geometry around a point by an angle, in degrees. @@ -109,12 +110,13 @@ where } } -impl Rotate for G +impl Rotate for G where T: CoordFloat, + C: CoordTrait, IP: Into>>, IR: Into>>, - G: Clone + Centroid + BoundingRect + AffineOps, + G: Clone + Centroid + BoundingRect + AffineOps, { fn rotate_around_centroid(&self, degrees: T) -> Self { let point = match self.centroid().into() { diff --git a/geo/src/algorithm/scale.rs b/geo/src/algorithm/scale.rs index a840e64a8..f4d34e398 100644 --- a/geo/src/algorithm/scale.rs +++ b/geo/src/algorithm/scale.rs @@ -1,3 +1,4 @@ +use crate::traits::CoordTrait; use crate::{AffineOps, AffineTransform, BoundingRect, CoordFloat, CoordNum, Coordinate, Rect}; /// An affine transformation which scales a geometry up or down by a factor. @@ -94,11 +95,12 @@ pub trait Scale { ); } -impl Scale for G +impl Scale for G where T: CoordFloat, + C: CoordTrait, IR: Into>>, - G: Clone + AffineOps + BoundingRect, + G: Clone + AffineOps + BoundingRect, { fn scale(&self, scale_factor: T) -> Self { self.scale_xy(scale_factor, scale_factor) diff --git a/geo/src/algorithm/skew.rs b/geo/src/algorithm/skew.rs index 14a787183..e6341b1db 100644 --- a/geo/src/algorithm/skew.rs +++ b/geo/src/algorithm/skew.rs @@ -1,3 +1,4 @@ +use crate::traits::CoordTrait; use crate::{AffineOps, AffineTransform, BoundingRect, CoordFloat, CoordNum, Coordinate, Rect}; /// An affine transformation which skews a geometry, sheared by angles along x and y dimensions. @@ -121,11 +122,12 @@ pub trait Skew { ); } -impl Skew for G +impl Skew for G where T: CoordFloat, + C: CoordTrait, IR: Into>>, - G: Clone + AffineOps + BoundingRect, + G: Clone + AffineOps + BoundingRect, { fn skew(&self, degrees: T) -> Self { self.skew_xy(degrees, degrees) diff --git a/geo/src/algorithm/translate.rs b/geo/src/algorithm/translate.rs index c3a3f0350..c2e2fb38c 100644 --- a/geo/src/algorithm/translate.rs +++ b/geo/src/algorithm/translate.rs @@ -1,3 +1,4 @@ +use crate::traits::CoordTrait; use crate::{AffineOps, AffineTransform, CoordNum}; pub trait Translate { @@ -46,10 +47,11 @@ pub trait Translate { fn translate_inplace(&mut self, x_offset: T, y_offset: T); } -impl Translate for G +impl Translate for G where T: CoordNum, - G: AffineOps, + C: CoordTrait, + G: AffineOps, { fn translate(&self, x_offset: T, y_offset: T) -> Self { let transform = AffineTransform::translate(x_offset, y_offset); diff --git a/geo/src/lib.rs b/geo/src/lib.rs index 28663cc90..a3364653a 100644 --- a/geo/src/lib.rs +++ b/geo/src/lib.rs @@ -202,8 +202,10 @@ pub use geometry::*; /// This module includes all the functions of geometric calculations pub mod algorithm; mod geometry_cow; +pub mod traits; mod types; mod utils; + pub(crate) use geometry_cow::GeometryCow; #[cfg(test)] diff --git a/geo/src/traits.rs b/geo/src/traits.rs new file mode 100644 index 000000000..0c24dad2c --- /dev/null +++ b/geo/src/traits.rs @@ -0,0 +1,80 @@ +use crate::geometry::*; +use crate::CoordNum; + +pub trait GeometryTrait: PartialEq { + type Coord: CoordTrait; +} + +impl GeometryTrait for Point { + type Coord = Coordinate; +} +impl GeometryTrait for Line { + type Coord = Coordinate; +} +impl GeometryTrait for LineString { + type Coord = Coordinate; +} +impl GeometryTrait for Polygon { + type Coord = Coordinate; +} +impl GeometryTrait for MultiPoint { + type Coord = Coordinate; +} +impl GeometryTrait for MultiLineString { + type Coord = Coordinate; +} +impl GeometryTrait for MultiPolygon { + type Coord = Coordinate; +} +impl GeometryTrait for Rect { + type Coord = Coordinate; +} +impl GeometryTrait for Triangle { + type Coord = Coordinate; +} +impl GeometryTrait for GeometryCollection { + type Coord = Coordinate; +} +impl GeometryTrait for Geometry { + type Coord = Coordinate; +} + +pub trait CoordTrait: PartialEq { + type Scalar: CoordNum; + + fn x(&self) -> Self::Scalar; + fn y(&self) -> Self::Scalar; + fn x_mut(&mut self) -> &mut Self::Scalar; + fn y_mut(&mut self) -> &mut Self::Scalar; + + fn xy(&self) -> (Self::Scalar, Self::Scalar); + fn from_xy(x: Self::Scalar, y: Self::Scalar) -> Self; +} + +impl CoordTrait for Coordinate { + type Scalar = T; + + fn x(&self) -> T { + self.x + } + + fn y(&self) -> T { + self.y + } + + fn x_mut(&mut self) -> &mut T { + &mut self.x + } + + fn y_mut(&mut self) -> &mut T { + &mut self.y + } + + fn xy(&self) -> (T, T) { + self.x_y() + } + + fn from_xy(x: T, y: T) -> Self { + Self { x, y } + } +}