diff --git a/geo/Cargo.toml b/geo/Cargo.toml index cf5dfc626a..6873e6b5c2 100644 --- a/geo/Cargo.toml +++ b/geo/Cargo.toml @@ -32,6 +32,7 @@ robust = "1.1.0" rstar = "0.12.0" serde = { version = "1.0", optional = true, features = ["derive"] } i_overlay = { version = "2.0.0, < 2.1.0", default-features = false } +geo-traits = ">=0.3.0" [dev-dependencies] approx = ">= 0.4.0, < 0.6.0" diff --git a/geo/src/algorithm/kernels/mod.rs b/geo/src/algorithm/kernels/mod.rs index 814c45752b..2828a7224c 100644 --- a/geo/src/algorithm/kernels/mod.rs +++ b/geo/src/algorithm/kernels/mod.rs @@ -1,7 +1,8 @@ use num_traits::Zero; use std::cmp::Ordering; -use crate::{coord, Coord, CoordNum}; +use crate::CoordNum; +use geo_traits::CoordTrait; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Orientation { @@ -24,11 +25,14 @@ impl Orientation { /// Kernel trait to provide predicates to operate on /// different scalar types. -pub trait Kernel { +pub trait Kernel +where + T::T: CoordNum, +{ /// Gives the orientation of 3 2-dimensional points: /// ccw, cw or collinear (None) - fn orient2d(p: Coord, q: Coord, r: Coord) -> Orientation { - let res = (q.x - p.x) * (r.y - q.y) - (q.y - p.y) * (r.x - q.x); + fn orient2d(p: T, q: T, r: T) -> Orientation { + let res = (q.x() - p.x()) * (r.y() - q.y()) - (q.y() - p.y()) * (r.x() - q.x()); if res > Zero::zero() { Orientation::CounterClockwise } else if res < Zero::zero() { @@ -38,21 +42,23 @@ pub trait Kernel { } } - fn square_euclidean_distance(p: Coord, q: Coord) -> T { - (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y) + fn square_euclidean_distance(p: T, q: T) -> T::T { + (p.x() - q.x()) * (p.x() - q.x()) + (p.y() - q.y()) * (p.y() - q.y()) } /// Compute the sign of the dot product of `u` and `v` using /// robust predicates. The output is `CounterClockwise` if /// the sign is positive, `Clockwise` if negative, and /// `Collinear` if zero. - fn dot_product_sign(u: Coord, v: Coord) -> Orientation { - let zero = Coord::zero(); - let vdash = coord! { - x: T::zero() - v.y, - y: v.x, - }; - Self::orient2d(zero, u, vdash) + fn dot_product_sign(u: T, v: T) -> Orientation { + let dot_product = u.x() * v.x() + u.y() * v.y(); + if dot_product > T::T::zero() { + Orientation::CounterClockwise + } else if dot_product < T::T::zero() { + Orientation::Clockwise + } else { + Orientation::Collinear + } } } diff --git a/geo/src/algorithm/kernels/robust.rs b/geo/src/algorithm/kernels/robust.rs index b41df55ab3..f965afea8d 100644 --- a/geo/src/algorithm/kernels/robust.rs +++ b/geo/src/algorithm/kernels/robust.rs @@ -1,5 +1,5 @@ use super::{CoordNum, Kernel, Orientation}; -use crate::Coord; +use geo_traits::CoordTrait; use num_traits::{Float, NumCast}; @@ -11,25 +11,26 @@ use num_traits::{Float, NumCast}; #[derive(Default, Debug)] pub struct RobustKernel; -impl Kernel for RobustKernel +impl

Kernel

for RobustKernel where - T: CoordNum + Float, + P: CoordTrait, + P::T: CoordNum + Float, { - fn orient2d(p: Coord, q: Coord, r: Coord) -> Orientation { + fn orient2d(p: P, q: P, r: P) -> Orientation { use robust::{orient2d, Coord}; let orientation = orient2d( Coord { - x: ::from(p.x).unwrap(), - y: ::from(p.y).unwrap(), + x: ::from(p.x()).unwrap(), + y: ::from(p.y()).unwrap(), }, Coord { - x: ::from(q.x).unwrap(), - y: ::from(q.y).unwrap(), + x: ::from(q.x()).unwrap(), + y: ::from(q.y()).unwrap(), }, Coord { - x: ::from(r.x).unwrap(), - y: ::from(r.y).unwrap(), + x: ::from(r.x()).unwrap(), + y: ::from(r.y()).unwrap(), }, ); diff --git a/geo/src/algorithm/kernels/simple.rs b/geo/src/algorithm/kernels/simple.rs index 9bb75ed82c..c054b6df8b 100644 --- a/geo/src/algorithm/kernels/simple.rs +++ b/geo/src/algorithm/kernels/simple.rs @@ -1,5 +1,6 @@ use super::Kernel; use crate::CoordNum; +use geo_traits::CoordTrait; /// Simple kernel provides the direct implementation of the /// predicates. These are meant to be used with exact @@ -7,4 +8,9 @@ use crate::CoordNum; #[derive(Default, Debug)] pub struct SimpleKernel; -impl Kernel for SimpleKernel {} +impl Kernel for SimpleKernel +where + T: CoordTrait, + T::T: CoordNum, +{ +} diff --git a/geo/src/algorithm/old_sweep/line_or_point.rs b/geo/src/algorithm/old_sweep/line_or_point.rs index 594b907cb9..0c8b3ac2e8 100644 --- a/geo/src/algorithm/old_sweep/line_or_point.rs +++ b/geo/src/algorithm/old_sweep/line_or_point.rs @@ -333,7 +333,10 @@ mod tests { use geo_types::{Coord, LineString}; use wkt::ToWkt; - use crate::{GeoFloat, GeoNum, Kernel}; + use crate::{ + kernels::{RobustKernel, SimpleKernel}, + GeoFloat, GeoNum, Kernel, + }; use super::LineOrPoint; @@ -385,13 +388,7 @@ mod tests { eprintln!("l1: {}", l87.to_wkt()); eprintln!("lo: {}", lo.to_wkt()); - eprintln!( - "pred: {:?}", - ::Ker::orient2d(pt_8, pt_7, pt_17) - ); - eprintln!( - "pred: {:?}", - ::Ker::orient2d(pt_8, pt_14, pt_16) - ); + eprintln!("pred: {:?}", SimpleKernel::orient2d(pt_8, pt_7, pt_17)); + eprintln!("pred: {:?}", RobustKernel::orient2d(pt_8, pt_14, pt_16)); } } diff --git a/geo/src/algorithm/winding_order.rs b/geo/src/algorithm/winding_order.rs index 8f85fe69a3..f065a4e87e 100644 --- a/geo/src/algorithm/winding_order.rs +++ b/geo/src/algorithm/winding_order.rs @@ -1,7 +1,7 @@ use super::kernels::*; use crate::coords_iter::CoordsIter; use crate::utils::EitherIter; -use crate::{CoordNum, GeoFloat, GeoNum, LineString, Point}; +use crate::{Coord, CoordNum, GeoFloat, GeoNum, LineString, Point}; use geo_types::{PointsIter, Triangle}; use std::iter::Rev; @@ -117,8 +117,8 @@ pub trait Winding { impl Winding for LineString where - T: GeoNum, - K: Kernel, + T: GeoNum> = K>, + K: Kernel>, { type Scalar = T; diff --git a/geo/src/lib.rs b/geo/src/lib.rs index 4f8447ee65..1fa3cd1fdf 100644 --- a/geo/src/lib.rs +++ b/geo/src/lib.rs @@ -255,6 +255,7 @@ use std::cmp::Ordering; pub use crate::algorithm::sweep::Intersections; pub use crate::relate::PreparedGeometry; +use geo_traits::CoordTrait; pub use geo_types::{coord, line_string, point, polygon, wkt, CoordFloat, CoordNum}; pub mod geometry; @@ -345,7 +346,7 @@ impl GeoFloat for T where /// A trait for methods which work for both integers **and** floating point pub trait GeoNum: CoordNum { - type Ker: Kernel; + type Ker>: Kernel; /// Return the ordering between self and other. /// @@ -361,7 +362,7 @@ pub trait GeoNum: CoordNum { macro_rules! impl_geo_num_for_float { ($t: ident) => { impl GeoNum for $t { - type Ker = RobustKernel; + type Ker> = RobustKernel; fn total_cmp(&self, other: &Self) -> Ordering { self.total_cmp(other) } @@ -371,7 +372,7 @@ macro_rules! impl_geo_num_for_float { macro_rules! impl_geo_num_for_int { ($t: ident) => { impl GeoNum for $t { - type Ker = SimpleKernel; + type Ker> = SimpleKernel; fn total_cmp(&self, other: &Self) -> Ordering { self.cmp(other) }