From 04c96e938d91dbd3258de6b8da32d45d4e7e0792 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 10:26:58 -0500 Subject: [PATCH 01/34] Add traits for each geometry type. https://github.com/georust/rust-geo/issues/67 --- src/traits.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/traits.rs b/src/traits.rs index 79e538462..e229fe287 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -6,3 +6,49 @@ pub trait ToGeo { fn to_geo(&self) -> Geometry; } + +pub trait Point { + fn x(&self) -> f64; + fn y(&self) -> f64; + fn opt_z(&self) -> Option { + None + } + fn opt_m(&self) -> Option { + None + } +} + +pub trait LineString<'a> { + type ItemType: 'a + Point; + type Iter: Iterator; + + fn points(&'a self) -> Self::Iter; +} + +pub trait Polygon<'a> { + type ItemType: 'a + LineString<'a>; + type Iter: Iterator; + + fn rings(&'a self) -> Self::Iter; +} + +pub trait MultiPoint<'a> { + type ItemType: 'a + Point; + type Iter: Iterator; + + fn points(&'a self) -> Self::Iter; +} + +pub trait MultiLineString<'a> { + type ItemType: 'a + LineString<'a>; + type Iter: Iterator; + + fn lines(&'a self) -> Self::Iter; +} + +pub trait MultiPolygon<'a> { + type ItemType: 'a + Polygon<'a>; + type Iter: Iterator; + + fn polygons(&'a self) -> Self::Iter; +} From 7e7731f1291698407a052658eb64d5313504fc32 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 10:34:29 -0500 Subject: [PATCH 02/34] Rename traits to differentiate for now. --- src/lib.rs | 2 +- src/traits.rs | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 14a2882d5..2e138e368 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ extern crate num_traits; -pub use traits::ToGeo; +pub use traits::*; pub use types::*; pub use algorithm::*; diff --git a/src/traits.rs b/src/traits.rs index e229fe287..1dfc4469b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -7,7 +7,9 @@ pub trait ToGeo fn to_geo(&self) -> Geometry; } -pub trait Point { +// FIXME: find good names for these traits, don't use XyzTrait naming scheme + +pub trait PointTrait { fn x(&self) -> f64; fn y(&self) -> f64; fn opt_z(&self) -> Option { @@ -18,36 +20,36 @@ pub trait Point { } } -pub trait LineString<'a> { - type ItemType: 'a + Point; +pub trait LineStringTrait<'a> { + type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait Polygon<'a> { - type ItemType: 'a + LineString<'a>; +pub trait PolygonTrait<'a> { + type ItemType: 'a + LineStringTrait<'a>; type Iter: Iterator; fn rings(&'a self) -> Self::Iter; } -pub trait MultiPoint<'a> { - type ItemType: 'a + Point; +pub trait MultiPointTrait<'a> { + type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait MultiLineString<'a> { - type ItemType: 'a + LineString<'a>; +pub trait MultiLineStringTrait<'a> { + type ItemType: 'a + LineStringTrait<'a>; type Iter: Iterator; fn lines(&'a self) -> Self::Iter; } -pub trait MultiPolygon<'a> { - type ItemType: 'a + Polygon<'a>; +pub trait MultiPolygonTrait<'a> { + type ItemType: 'a + PolygonTrait<'a>; type Iter: Iterator; fn polygons(&'a self) -> Self::Iter; From 2e00a1a083b4a4d705783964616323850b50e4b1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 10:35:32 -0500 Subject: [PATCH 03/34] Beginning of an area implementation. --- src/algorithm/area.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index cf0ba2b98..4e0871488 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,5 +1,6 @@ use num_traits::Float; use types::{LineString, Polygon, MultiPolygon, Bbox}; +use ::PolygonTrait; /// Calculation of the area. @@ -57,6 +58,15 @@ impl Area for Bbox } } +impl<'a, T, G> Area for G + where G: PolygonTrait<'a>, + T: Float, +{ + fn area(&self) -> T { + unimplemented!() + } +} + #[cfg(test)] mod test { use num_traits::Float; From a1771882737aaa3dd6dfc58b63511f8ae3935d7e Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 10:57:47 -0500 Subject: [PATCH 04/34] Make traits float-generic, not based on f64. --- src/traits.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 1dfc4469b..6b8470d48 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -9,9 +9,9 @@ pub trait ToGeo // FIXME: find good names for these traits, don't use XyzTrait naming scheme -pub trait PointTrait { - fn x(&self) -> f64; - fn y(&self) -> f64; +pub trait PointTrait { + fn x(&self) -> T; + fn y(&self) -> T; fn opt_z(&self) -> Option { None } @@ -20,36 +20,36 @@ pub trait PointTrait { } } -pub trait LineStringTrait<'a> { - type ItemType: 'a + PointTrait; +pub trait LineStringTrait<'a, T: Float> { + type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait PolygonTrait<'a> { - type ItemType: 'a + LineStringTrait<'a>; +pub trait PolygonTrait<'a, T: Float> { + type ItemType: 'a + LineStringTrait<'a, T>; type Iter: Iterator; fn rings(&'a self) -> Self::Iter; } -pub trait MultiPointTrait<'a> { - type ItemType: 'a + PointTrait; +pub trait MultiPointTrait<'a, T: Float> { + type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait MultiLineStringTrait<'a> { - type ItemType: 'a + LineStringTrait<'a>; +pub trait MultiLineStringTrait<'a, T: Float> { + type ItemType: 'a + LineStringTrait<'a, T>; type Iter: Iterator; fn lines(&'a self) -> Self::Iter; } -pub trait MultiPolygonTrait<'a> { - type ItemType: 'a + PolygonTrait<'a>; +pub trait MultiPolygonTrait<'a, T: Float> { + type ItemType: 'a + PolygonTrait<'a, T>; type Iter: Iterator; fn polygons(&'a self) -> Self::Iter; From 4099e9840ed80b225e817a8ff62a54d95fca345c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 11:04:55 -0500 Subject: [PATCH 05/34] Remove opt_foo for now --- src/traits.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 6b8470d48..8480b7775 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -12,12 +12,6 @@ pub trait ToGeo pub trait PointTrait { fn x(&self) -> T; fn y(&self) -> T; - fn opt_z(&self) -> Option { - None - } - fn opt_m(&self) -> Option { - None - } } pub trait LineStringTrait<'a, T: Float> { From e35f97772bfba9d1919a8fb6f1f73593a2ec4742 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 11:10:51 -0500 Subject: [PATCH 06/34] Remove lifetimes on geometry trait types --- src/traits.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 8480b7775..2f3c600fb 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -14,37 +14,37 @@ pub trait PointTrait { fn y(&self) -> T; } -pub trait LineStringTrait<'a, T: Float> { - type ItemType: 'a + PointTrait; - type Iter: Iterator; +pub trait LineStringTrait { + type ItemType: PointTrait; + type Iter: Iterator; - fn points(&'a self) -> Self::Iter; + fn points(&self) -> Self::Iter; } -pub trait PolygonTrait<'a, T: Float> { - type ItemType: 'a + LineStringTrait<'a, T>; - type Iter: Iterator; +pub trait PolygonTrait { + type ItemType: LineStringTrait; + type Iter: Iterator; - fn rings(&'a self) -> Self::Iter; + fn rings(&self) -> Self::Iter; } -pub trait MultiPointTrait<'a, T: Float> { - type ItemType: 'a + PointTrait; - type Iter: Iterator; +pub trait MultiPointTrait { + type ItemType: PointTrait; + type Iter: Iterator; - fn points(&'a self) -> Self::Iter; + fn points(&self) -> Self::Iter; } -pub trait MultiLineStringTrait<'a, T: Float> { - type ItemType: 'a + LineStringTrait<'a, T>; - type Iter: Iterator; +pub trait MultiLineStringTrait { + type ItemType: LineStringTrait; + type Iter: Iterator; - fn lines(&'a self) -> Self::Iter; + fn lines(&self) -> Self::Iter; } -pub trait MultiPolygonTrait<'a, T: Float> { - type ItemType: 'a + PolygonTrait<'a, T>; - type Iter: Iterator; +pub trait MultiPolygonTrait { + type ItemType: PolygonTrait; + type Iter: Iterator; - fn polygons(&'a self) -> Self::Iter; + fn polygons(&self) -> Self::Iter; } From cf76f43522b7b0f14b72dddd4029183e64c2eeee Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 15:35:32 -0500 Subject: [PATCH 07/34] sorta kinda implement area operation generically --- src/algorithm/area.rs | 62 ++++++++++++++++---------------- src/types.rs | 82 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 32 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 4e0871488..79a96666d 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,6 +1,5 @@ use num_traits::Float; -use types::{LineString, Polygon, MultiPolygon, Bbox}; -use ::PolygonTrait; +use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; /// Calculation of the area. @@ -21,51 +20,46 @@ pub trait Area where T: Float fn area(&self) -> T; } -fn get_linestring_area(linestring: &LineString) -> T where T: Float { - if linestring.0.is_empty() || linestring.0.len() == 1 { - return T::zero(); - } +fn get_linestring_area(linestring: &G) -> T + where T: Float, G: LineStringTrait +{ + let mut points = linestring.points(); + let mut p1 = match points.next() { + Some(p) => p, + None => return T::zero(), + }; let mut tmp = T::zero(); - for ps in linestring.0.windows(2) { - tmp = tmp + (ps[0].x() * ps[1].y() - ps[1].x() * ps[0].y()); + for p2 in points { + tmp = tmp + (p1.x() * p2.y() - p2.x() * p1.y()); + p1 = p2; } tmp / (T::one() + T::one()) } - -impl Area for Polygon - where T: Float -{ - fn area(&self) -> T { - self.interiors.iter().fold(get_linestring_area(&self.exterior), - |total, next| total - get_linestring_area(next)) - } -} - -impl Area for MultiPolygon - where T: Float -{ - fn area(&self) -> T { - self.0.iter().fold(T::zero(), |total, next| total + next.area()) - } -} - -impl Area for Bbox - where T: Float +impl Area for G + where G: PolygonTrait, + T: Float, { fn area(&self) -> T { - (self.xmax - self.xmin) * (self.ymax - self.ymin) + let mut rings = self.rings(); + let outer_ring = rings.next().expect("no outer ring in polygon"); + let outer_ring_area = get_linestring_area(&outer_ring); + rings.fold(outer_ring_area, |acc, ring| { + acc - get_linestring_area(&ring) + }) } } -impl<'a, T, G> Area for G - where G: PolygonTrait<'a>, +/* +impl Area for G + where G: MultiPolygonTrait, T: Float, { fn area(&self) -> T { - unimplemented!() + self.polygons().map(|n| n.area()).sum() } } +*/ #[cfg(test)] mod test { @@ -73,6 +67,7 @@ mod test { use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; use algorithm::area::Area; use test_helpers::within_epsilon; + use ::{PolygonTrait, LineStringTrait, PointTrait}; // Area of the polygon #[test] fn area_empty_polygon_test() { @@ -106,6 +101,8 @@ mod test { let poly = Polygon::new(outer, vec![inner0, inner1]); assert!(within_epsilon(poly.area(), 98., Float::epsilon())); } + + /* #[test] fn area_multipolygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); @@ -122,4 +119,5 @@ mod test { assert_eq!(mpoly.area(), 102.); assert!(within_epsilon(mpoly.area(), 102., Float::epsilon())); } + */ } diff --git a/src/types.rs b/src/types.rs index 597ad5f98..e369f2d39 100644 --- a/src/types.rs +++ b/src/types.rs @@ -25,6 +25,27 @@ pub struct Bbox pub ymax: T, } +impl Bbox { + fn to_line_string(&self) -> LineString { + LineString(vec![ + Point(Coordinate { x: self.xmin, y: self.ymax }), + Point(Coordinate { x: self.xmax, y: self.ymax }), + Point(Coordinate { x: self.xmax, y: self.ymin }), + Point(Coordinate { x: self.xmin, y: self.ymin }), + ]) + } +} + +impl ::PolygonTrait for Bbox { + type ItemType = LineString; + type Iter = ::std::iter::Once>; + + fn rings(&self) -> Self::Iter { + // TODO: no clones please! + ::std::iter::once(self.to_line_string()) + } +} + #[derive(PartialEq, Clone, Copy, Debug)] pub struct Point (pub Coordinate) where T: Float; @@ -231,6 +252,16 @@ impl Sub for Point } } +impl ::PointTrait for Point { + fn x(&self) -> T { + self.x() + } + + fn y(&self) -> T { + self.y() + } +} + impl Add for Bbox where T: Float + ToPrimitive { @@ -289,12 +320,42 @@ impl AddAssign for Bbox #[derive(PartialEq, Clone, Debug)] pub struct MultiPoint(pub Vec>) where T: Float; +impl ::MultiPointTrait for MultiPoint { + type ItemType = Point; + type Iter = ::std::vec::IntoIter>; + + fn points(&self) -> Self::Iter { + // TODO: no clones please! + self.0.iter().map(|n| n.clone()).collect::>().into_iter() + } +} + #[derive(PartialEq, Clone, Debug)] pub struct LineString(pub Vec>) where T: Float; +impl ::LineStringTrait for LineString { + type ItemType = Point; + type Iter = ::std::vec::IntoIter>; + + fn points(&self) -> Self::Iter { + // TODO: no clones please! + self.0.iter().map(|n| n.clone()).collect::>().into_iter() + } +} + #[derive(PartialEq, Clone, Debug)] pub struct MultiLineString(pub Vec>) where T: Float; +impl ::MultiLineStringTrait for MultiLineString { + type ItemType = LineString; + type Iter = ::std::vec::IntoIter>; + + fn lines(&self) -> Self::Iter { + // TODO: no clones please! + self.0.iter().map(|n| n.clone()).collect::>().into_iter() + } +} + #[derive(PartialEq, Clone, Debug)] pub struct Polygon where T: Float @@ -324,9 +385,30 @@ impl Polygon } } +impl ::PolygonTrait for Polygon { + type ItemType = LineString; + type Iter = ::std::iter::Once>; + + fn rings(&self) -> Self::Iter { + // TODO: no clones please! + // TODO: add in interiors + ::std::iter::once(self.exterior.clone()) + } +} + #[derive(PartialEq, Clone, Debug)] pub struct MultiPolygon(pub Vec>) where T: Float; +impl ::MultiPolygonTrait for MultiPolygon { + type ItemType = Polygon; + type Iter = ::std::vec::IntoIter>; + + fn polygons(&self) -> Self::Iter { + // TODO: no clones please! + self.0.iter().map(|n| n.clone()).collect::>().into_iter() + } +} + #[derive(PartialEq, Clone, Debug)] pub struct GeometryCollection(pub Vec>) where T: Float; From 0564d17c871bfc0f34d219fd701beead52504d6d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 15:56:14 -0500 Subject: [PATCH 08/34] incorporate interiors --- src/types.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/types.rs b/src/types.rs index e369f2d39..c7ec66923 100644 --- a/src/types.rs +++ b/src/types.rs @@ -387,12 +387,13 @@ impl Polygon impl ::PolygonTrait for Polygon { type ItemType = LineString; - type Iter = ::std::iter::Once>; + type Iter = ::std::vec::IntoIter>; fn rings(&self) -> Self::Iter { // TODO: no clones please! - // TODO: add in interiors - ::std::iter::once(self.exterior.clone()) + let mut rings = vec![self.exterior.clone()]; + rings.extend(self.interiors.clone().into_iter()); + rings.into_iter() } } From 4c860ed3ab13ade1a7f117f7a4bb478d1c77ee4b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 16:07:44 -0500 Subject: [PATCH 09/34] aint nobody got time for bboxes --- src/algorithm/area.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 79a96666d..16ca3e594 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -87,11 +87,15 @@ mod test { let poly = Polygon::new(linestring, Vec::new()); assert!(within_epsilon(poly.area(), 30., Float::epsilon())); } + + /* #[test] fn bbox_test() { let bbox = Bbox {xmin: 10., xmax: 20., ymin: 30., ymax: 40.}; assert!(within_epsilon(bbox.area(), 100., Float::epsilon())); } + */ + #[test] fn area_polygon_inner_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); From 05dda09c0d0802491b25eb5f49f71b51000fdab8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 17:59:34 -0500 Subject: [PATCH 10/34] fewer clones, redesign traits --- src/algorithm/area.rs | 23 +++++++------- src/traits.rs | 40 ++++++++++++------------- src/types.rs | 70 ++++++++++++++----------------------------- 3 files changed, 54 insertions(+), 79 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 16ca3e594..00caa3522 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -3,7 +3,7 @@ use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; /// Calculation of the area. -pub trait Area where T: Float +pub trait Area<'a, T> where T: Float { /// Area of polygon. /// See: https://en.wikipedia.org/wiki/Polygon @@ -17,11 +17,12 @@ pub trait Area where T: Float /// let poly = Polygon::new(linestring, v); /// assert_eq!(poly.area(), 30.); /// ``` - fn area(&self) -> T; + fn area(&'a self) -> T; } -fn get_linestring_area(linestring: &G) -> T - where T: Float, G: LineStringTrait +fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T + where T: 'a + Float, + G: 'a + LineStringTrait<'a, T> { let mut points = linestring.points(); let mut p1 = match points.next() { @@ -36,16 +37,16 @@ fn get_linestring_area(linestring: &G) -> T tmp / (T::one() + T::one()) } -impl Area for G - where G: PolygonTrait, - T: Float, +impl<'a, T, G> Area<'a, T> for G + where G: 'a + PolygonTrait<'a, T>, + T: 'a + Float, { - fn area(&self) -> T { + fn area(&'a self) -> T { let mut rings = self.rings(); let outer_ring = rings.next().expect("no outer ring in polygon"); - let outer_ring_area = get_linestring_area(&outer_ring); - rings.fold(outer_ring_area, |acc, ring| { - acc - get_linestring_area(&ring) + let outer_ring_area = get_linestring_area(outer_ring); + rings.fold(outer_ring_area, |acc, inner_ring| { + acc - get_linestring_area(inner_ring) }) } } diff --git a/src/traits.rs b/src/traits.rs index 2f3c600fb..fd8229b9c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -14,37 +14,37 @@ pub trait PointTrait { fn y(&self) -> T; } -pub trait LineStringTrait { - type ItemType: PointTrait; - type Iter: Iterator; +pub trait LineStringTrait<'a, T: Float> { + type ItemType: 'a + PointTrait; + type Iter: Iterator; - fn points(&self) -> Self::Iter; + fn points(&'a self) -> Self::Iter; } -pub trait PolygonTrait { - type ItemType: LineStringTrait; - type Iter: Iterator; +pub trait PolygonTrait<'a, T: Float> { + type ItemType: 'a + LineStringTrait<'a, T>; + type Iter: 'a + Iterator; - fn rings(&self) -> Self::Iter; + fn rings(&'a self) -> Self::Iter; } -pub trait MultiPointTrait { - type ItemType: PointTrait; - type Iter: Iterator; +pub trait MultiPointTrait<'a, T: Float> { + type ItemType: 'a + PointTrait; + type Iter: Iterator; - fn points(&self) -> Self::Iter; + fn points(&'a self) -> Self::Iter; } -pub trait MultiLineStringTrait { - type ItemType: LineStringTrait; - type Iter: Iterator; +pub trait MultiLineStringTrait<'a, T: Float> { + type ItemType: 'a + LineStringTrait<'a, T>; + type Iter: Iterator; - fn lines(&self) -> Self::Iter; + fn lines(&'a self) -> Self::Iter; } -pub trait MultiPolygonTrait { - type ItemType: PolygonTrait; - type Iter: Iterator; +pub trait MultiPolygonTrait<'a, T: Float> { + type ItemType: 'a + PolygonTrait<'a, T>; + type Iter: Iterator; - fn polygons(&self) -> Self::Iter; + fn polygons(&'a self) -> Self::Iter; } diff --git a/src/types.rs b/src/types.rs index c7ec66923..d36366963 100644 --- a/src/types.rs +++ b/src/types.rs @@ -25,27 +25,6 @@ pub struct Bbox pub ymax: T, } -impl Bbox { - fn to_line_string(&self) -> LineString { - LineString(vec![ - Point(Coordinate { x: self.xmin, y: self.ymax }), - Point(Coordinate { x: self.xmax, y: self.ymax }), - Point(Coordinate { x: self.xmax, y: self.ymin }), - Point(Coordinate { x: self.xmin, y: self.ymin }), - ]) - } -} - -impl ::PolygonTrait for Bbox { - type ItemType = LineString; - type Iter = ::std::iter::Once>; - - fn rings(&self) -> Self::Iter { - // TODO: no clones please! - ::std::iter::once(self.to_line_string()) - } -} - #[derive(PartialEq, Clone, Copy, Debug)] pub struct Point (pub Coordinate) where T: Float; @@ -320,39 +299,36 @@ impl AddAssign for Bbox #[derive(PartialEq, Clone, Debug)] pub struct MultiPoint(pub Vec>) where T: Float; -impl ::MultiPointTrait for MultiPoint { +impl<'a, T: 'a + Float> ::MultiPointTrait<'a, T> for MultiPoint { type ItemType = Point; - type Iter = ::std::vec::IntoIter>; + type Iter = Box + 'a>; - fn points(&self) -> Self::Iter { - // TODO: no clones please! - self.0.iter().map(|n| n.clone()).collect::>().into_iter() + fn points(&'a self) -> Self::Iter { + Box::new(self.0.iter()) } } #[derive(PartialEq, Clone, Debug)] pub struct LineString(pub Vec>) where T: Float; -impl ::LineStringTrait for LineString { +impl<'a, T: 'a + Float> ::LineStringTrait<'a, T> for LineString { type ItemType = Point; - type Iter = ::std::vec::IntoIter>; + type Iter = Box + 'a>; - fn points(&self) -> Self::Iter { - // TODO: no clones please! - self.0.iter().map(|n| n.clone()).collect::>().into_iter() + fn points(&'a self) -> Self::Iter { + Box::new(self.0.iter()) } } #[derive(PartialEq, Clone, Debug)] pub struct MultiLineString(pub Vec>) where T: Float; -impl ::MultiLineStringTrait for MultiLineString { +impl<'a, T: 'a + Float> ::MultiLineStringTrait<'a, T> for MultiLineString { type ItemType = LineString; - type Iter = ::std::vec::IntoIter>; + type Iter = Box + 'a>; - fn lines(&self) -> Self::Iter { - // TODO: no clones please! - self.0.iter().map(|n| n.clone()).collect::>().into_iter() + fn lines(&'a self) -> Self::Iter { + Box::new(self.0.iter()) } } @@ -385,28 +361,26 @@ impl Polygon } } -impl ::PolygonTrait for Polygon { +impl<'a, T: 'a + Float> ::PolygonTrait<'a, T> for Polygon { type ItemType = LineString; - type Iter = ::std::vec::IntoIter>; + type Iter = Box + 'a>; - fn rings(&self) -> Self::Iter { - // TODO: no clones please! - let mut rings = vec![self.exterior.clone()]; - rings.extend(self.interiors.clone().into_iter()); - rings.into_iter() + fn rings(&'a self) -> Self::Iter { + let iter = ::std::iter::once(&self.exterior) + .chain(self.interiors.iter()); + Box::new(iter) } } #[derive(PartialEq, Clone, Debug)] pub struct MultiPolygon(pub Vec>) where T: Float; -impl ::MultiPolygonTrait for MultiPolygon { +impl<'a, T: 'a + Float> ::MultiPolygonTrait<'a, T> for MultiPolygon { type ItemType = Polygon; - type Iter = ::std::vec::IntoIter>; + type Iter = Box + 'a>; - fn polygons(&self) -> Self::Iter { - // TODO: no clones please! - self.0.iter().map(|n| n.clone()).collect::>().into_iter() + fn polygons(&'a self) -> Self::Iter { + Box::new(self.0.iter()) } } From 196b8c4b91c7bf1ac65b86ef182738895a61eca1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 18:20:47 -0500 Subject: [PATCH 11/34] move area algorithm as method --- src/algorithm/area.rs | 31 +++++++++---------------------- src/algorithm/centroid.rs | 2 +- src/traits.rs | 24 +++++++++++++++++++----- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 00caa3522..b72f927a1 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -37,30 +37,17 @@ fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T tmp / (T::one() + T::one()) } -impl<'a, T, G> Area<'a, T> for G - where G: 'a + PolygonTrait<'a, T>, - T: 'a + Float, -{ - fn area(&'a self) -> T { - let mut rings = self.rings(); - let outer_ring = rings.next().expect("no outer ring in polygon"); - let outer_ring_area = get_linestring_area(outer_ring); - rings.fold(outer_ring_area, |acc, inner_ring| { - acc - get_linestring_area(inner_ring) - }) - } -} - -/* -impl Area for G - where G: MultiPolygonTrait, - T: Float, +pub fn polygon<'a, G, T>(polygon: &'a G) -> T + where T: 'a + Float, + G: 'a + PolygonTrait<'a, T> + ?Sized { - fn area(&self) -> T { - self.polygons().map(|n| n.area()).sum() - } + let mut rings = polygon.rings(); + let outer_ring = rings.next().expect("no outer ring in polygon"); + let outer_ring_area = get_linestring_area(outer_ring); + rings.fold(outer_ring_area, |acc, inner_ring| { + acc - get_linestring_area(inner_ring) + }) } -*/ #[cfg(test)] mod test { diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index aff651a4a..0bb992c3c 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,7 +1,7 @@ use num_traits::{Float, FromPrimitive}; use types::{Point, LineString, Polygon, MultiPolygon, Bbox}; -use algorithm::area::Area; +use traits::PolygonTrait; use algorithm::distance::Distance; /// Calculation of the centroid. diff --git a/src/traits.rs b/src/traits.rs index fd8229b9c..47308f176 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -14,35 +14,49 @@ pub trait PointTrait { fn y(&self) -> T; } -pub trait LineStringTrait<'a, T: Float> { +pub trait LineStringTrait<'a, T> + where T: 'a + Float +{ type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait PolygonTrait<'a, T: Float> { +pub trait PolygonTrait<'a, T> + where T: 'a + Float, +{ type ItemType: 'a + LineStringTrait<'a, T>; type Iter: 'a + Iterator; fn rings(&'a self) -> Self::Iter; + + fn area(&'a self) -> T { + ::algorithm::area::polygon(self) + } } -pub trait MultiPointTrait<'a, T: Float> { +pub trait MultiPointTrait<'a, T> + where T: 'a + Float, +{ type ItemType: 'a + PointTrait; type Iter: Iterator; fn points(&'a self) -> Self::Iter; } -pub trait MultiLineStringTrait<'a, T: Float> { +pub trait MultiLineStringTrait<'a, T> + where T: 'a + Float, +{ type ItemType: 'a + LineStringTrait<'a, T>; type Iter: Iterator; fn lines(&'a self) -> Self::Iter; } -pub trait MultiPolygonTrait<'a, T: Float> { +pub trait MultiPolygonTrait<'a, T> + where T: 'a + Float, +{ type ItemType: 'a + PolygonTrait<'a, T>; type Iter: Iterator; From add85185e3185cd18a47255f646daab0685a26a8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 18:54:01 -0500 Subject: [PATCH 12/34] unused imports --- src/algorithm/area.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index b72f927a1..6af32ad9a 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -53,9 +53,8 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> T mod test { use num_traits::Float; use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; - use algorithm::area::Area; use test_helpers::within_epsilon; - use ::{PolygonTrait, LineStringTrait, PointTrait}; + use ::PolygonTrait; // Area of the polygon #[test] fn area_empty_polygon_test() { From a46853b4fe41f8e5b72057a88b31a13b72928125 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 18:55:32 -0500 Subject: [PATCH 13/34] remove area trait --- src/algorithm/area.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 6af32ad9a..b6aa17901 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,25 +1,6 @@ use num_traits::Float; use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; -/// Calculation of the area. - -pub trait Area<'a, T> where T: Float -{ - /// Area of polygon. - /// See: https://en.wikipedia.org/wiki/Polygon - /// - /// ``` - /// use geo::{Coordinate, Point, LineString, Polygon}; - /// use geo::algorithm::area::Area; - /// let p = |x, y| Point(Coordinate { x: x, y: y }); - /// let v = Vec::new(); - /// let linestring = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]); - /// let poly = Polygon::new(linestring, v); - /// assert_eq!(poly.area(), 30.); - /// ``` - fn area(&'a self) -> T; -} - fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T where T: 'a + Float, G: 'a + LineStringTrait<'a, T> From 1440816a8bea3c10c0b78ca474a99cc80f72b02c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 15 Jan 2017 19:04:51 -0500 Subject: [PATCH 14/34] implement area for multipolygon --- src/algorithm/area.rs | 23 ++++++++++------------- src/traits.rs | 4 ++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index b6aa17901..3ec10b10c 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -30,13 +30,20 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> T }) } +pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T + where T: 'a + Float, + G: 'a + MultiPolygonTrait<'a, T> + ?Sized +{ + multi_polygon.polygons().map(polygon).fold(T::zero(), |acc, n| acc + n) +} + #[cfg(test)] mod test { use num_traits::Float; - use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; + use types::{Coordinate, Point, LineString, Polygon, MultiPolygon}; use test_helpers::within_epsilon; - use ::PolygonTrait; - // Area of the polygon + use ::{PolygonTrait, MultiPolygonTrait}; + #[test] fn area_empty_polygon_test() { let poly = Polygon::::new(LineString(Vec::new()), Vec::new()); @@ -56,14 +63,6 @@ mod test { assert!(within_epsilon(poly.area(), 30., Float::epsilon())); } - /* - #[test] - fn bbox_test() { - let bbox = Bbox {xmin: 10., xmax: 20., ymin: 30., ymax: 40.}; - assert!(within_epsilon(bbox.area(), 100., Float::epsilon())); - } - */ - #[test] fn area_polygon_inner_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); @@ -74,7 +73,6 @@ mod test { assert!(within_epsilon(poly.area(), 98., Float::epsilon())); } - /* #[test] fn area_multipolygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); @@ -91,5 +89,4 @@ mod test { assert_eq!(mpoly.area(), 102.); assert!(within_epsilon(mpoly.area(), 102., Float::epsilon())); } - */ } diff --git a/src/traits.rs b/src/traits.rs index 47308f176..fb54d377b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -61,4 +61,8 @@ pub trait MultiPolygonTrait<'a, T> type Iter: Iterator; fn polygons(&'a self) -> Self::Iter; + + fn area(&'a self) -> T { + ::algorithm::area::multi_polygon(self) + } } From 3ee7fd3213a5f0f020f86d4372b9e843ecf6c51f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 15:39:19 -0500 Subject: [PATCH 15/34] implement centroid for polygon --- src/algorithm/area.rs | 9 +++--- src/algorithm/boundingbox.rs | 16 +++++----- src/algorithm/centroid.rs | 59 +++++++++++++++++------------------- src/algorithm/contains.rs | 14 ++++----- src/algorithm/distance.rs | 16 +++++----- src/algorithm/intersects.rs | 12 ++++---- src/algorithm/length.rs | 4 +-- src/algorithm/simplify.rs | 8 ++--- src/algorithm/simplifyvw.rs | 18 +++++------ src/traits.rs | 21 ++++++++----- src/types.rs | 51 +++++++++++++++++-------------- 11 files changed, 119 insertions(+), 109 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 3ec10b10c..755a8ae53 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,8 +1,8 @@ -use num_traits::Float; +use num_traits::{Float, FromPrimitive}; use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T - where T: 'a + Float, + where T: 'a + Float + ::num::FromPrimitive, G: 'a + LineStringTrait<'a, T> { let mut points = linestring.points(); @@ -18,8 +18,9 @@ fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T tmp / (T::one() + T::one()) } +// FIXME: remove FromPrimitive pub fn polygon<'a, G, T>(polygon: &'a G) -> T - where T: 'a + Float, + where T: 'a + Float + FromPrimitive, G: 'a + PolygonTrait<'a, T> + ?Sized { let mut rings = polygon.rings(); @@ -31,7 +32,7 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> T } pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T - where T: 'a + Float, + where T: 'a + Float + ::num::FromPrimitive, G: 'a + MultiPolygonTrait<'a, T> + ?Sized { multi_polygon.polygons().map(polygon).fold(T::zero(), |acc, n| acc + n) diff --git a/src/algorithm/boundingbox.rs b/src/algorithm/boundingbox.rs index 2b0d86d9b..738a6f076 100644 --- a/src/algorithm/boundingbox.rs +++ b/src/algorithm/boundingbox.rs @@ -4,7 +4,7 @@ use types::{Bbox, Point, MultiPoint, LineString, MultiLineString, Polygon, Multi /// Calculation of the bounding box of a geometry. -pub trait BoundingBox { +pub trait BoundingBox { /// Return a Bounding Box of a geometry /// /// ``` @@ -29,13 +29,13 @@ pub trait BoundingBox { fn get_min_max(p: T, min: T, max: T) -> (T, T) - where T: Float + where T: Float + ::num::FromPrimitive { if p > max {(min, p)} else if p < min {(p, max)} else {(min, max)} } fn get_bbox<'a, I, T>(collection: I) -> Option> - where T: 'a + Float, + where T: 'a + Float + ::num::FromPrimitive, I: 'a + IntoIterator> { let mut iter = collection.into_iter(); @@ -55,7 +55,7 @@ fn get_bbox<'a, I, T>(collection: I) -> Option> impl BoundingBox for MultiPoint - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Return the BoundingBox for a MultiPoint @@ -66,7 +66,7 @@ impl BoundingBox for MultiPoint } impl BoundingBox for LineString - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Return the BoundingBox for a LineString @@ -77,7 +77,7 @@ impl BoundingBox for LineString } impl BoundingBox for MultiLineString - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Return the BoundingBox for a MultiLineString @@ -88,7 +88,7 @@ impl BoundingBox for MultiLineString } impl BoundingBox for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Return the BoundingBox for a Polygon @@ -100,7 +100,7 @@ impl BoundingBox for Polygon } impl BoundingBox for MultiPolygon - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Return the BoundingBox for a MultiPolygon diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 0bb992c3c..6316a8f7c 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,11 +1,11 @@ use num_traits::{Float, FromPrimitive}; -use types::{Point, LineString, Polygon, MultiPolygon, Bbox}; -use traits::PolygonTrait; +use types::{Point, LineString, MultiPolygon, Bbox}; +use traits::{PolygonTrait, LineStringTrait, PointTrait}; use algorithm::distance::Distance; /// Calculation of the centroid. -pub trait Centroid { +pub trait Centroid { /// Calculation the centroid, see: https://en.wikipedia.org/wiki/Centroid /// /// ``` @@ -24,7 +24,7 @@ pub trait Centroid { } impl Centroid for LineString - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Centroid on a LineString is the mean of the middle of the segment @@ -54,34 +54,30 @@ impl Centroid for LineString } } -impl Centroid for Polygon - where T: Float + FromPrimitive +pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> + where T: 'a + Float + FromPrimitive, + G: 'a + PolygonTrait<'a, T> + ?Sized { - /// - /// Centroid on a Polygon. - /// See: https://en.wikipedia.org/wiki/Centroid - /// - fn centroid(&self) -> Option> { - // TODO: consideration of inner polygons; - let linestring = &self.exterior; - let vect = &linestring.0; - if vect.is_empty() { - return None; - } - if vect.len() == 1 { - Some(Point::new(vect[0].x(), vect[0].y())) - } else { - let area = self.area(); - let mut sum_x = T::zero(); - let mut sum_y = T::zero(); - for ps in vect.windows(2) { - let tmp = ps[0].x() * ps[1].y() - ps[1].x() * ps[0].y(); - sum_x = sum_x + ((ps[1].x() + ps[0].x()) * tmp); - sum_y = sum_y + ((ps[1].y() + ps[0].y()) * tmp); - } - let six = T::from_i32(6).unwrap(); - Some(Point::new(sum_x / (six * area), sum_y / (six * area))) + // TODO: consideration of inner polygons; + let mut rings = polygon.rings(); + // TODO: remove `collect` + let vect = rings.next().expect("no outer ring").points().collect::>(); + if vect.is_empty() { + return None; + } + if vect.len() == 1 { + Some(Point::new(vect[0].x(), vect[0].y())) + } else { + let area = polygon.area(); + let mut sum_x = T::zero(); + let mut sum_y = T::zero(); + for ps in vect.windows(2) { + let tmp = ps[0].x() * ps[1].y() - ps[1].x() * ps[0].y(); + sum_x = sum_x + ((ps[1].x() + ps[0].x()) * tmp); + sum_y = sum_y + ((ps[1].y() + ps[0].y()) * tmp); } + let six = T::from_i32(6).unwrap(); + Some(Point::new(sum_x / (six * area), sum_y / (six * area))) } } @@ -110,7 +106,7 @@ impl Centroid for MultiPolygon } impl Centroid for Bbox - where T: Float + where T: Float + ::num::FromPrimitive { /// /// Centroid on a Bbox. @@ -124,6 +120,7 @@ impl Centroid for Bbox #[cfg(test)] mod test { use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; + use traits::PolygonTrait; use algorithm::centroid::Centroid; use algorithm::distance::Distance; /// Tests: Centroid of LineString diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 952fdaf3d..5c22e9030 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -33,7 +33,7 @@ pub trait Contains { } impl Contains> for Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive + ::num::FromPrimitive { fn contains(&self, p: &Point) -> bool { self.distance(p).to_f32().unwrap() < COORD_PRECISION @@ -41,7 +41,7 @@ impl Contains> for Point } impl Contains> for LineString - where T: Float + where T: Float + ::num::FromPrimitive { fn contains(&self, p: &Point) -> bool { let vect = &self.0; @@ -78,7 +78,7 @@ enum PositionPoint { } fn get_position(p: &Point, linestring: &LineString) -> PositionPoint - where T: Float + where T: Float + ::num::FromPrimitive { // See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // http://geospatialpython.com/search @@ -120,7 +120,7 @@ fn get_position(p: &Point, linestring: &LineString) -> PositionPoint } impl Contains> for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { fn contains(&self, p: &Point) -> bool { match get_position(p, &self.exterior) { @@ -132,7 +132,7 @@ impl Contains> for Polygon } impl Contains> for MultiPolygon - where T: Float + where T: Float + ::num::FromPrimitive { fn contains(&self, p: &Point) -> bool { self.0.iter().any(|poly| poly.contains(p)) @@ -140,7 +140,7 @@ impl Contains> for MultiPolygon } impl Contains> for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { fn contains(&self, linestring: &LineString) -> bool { // All points of LineString must be in the polygon ? @@ -153,7 +153,7 @@ impl Contains> for Polygon } impl Contains> for Bbox - where T: Float + where T: Float + ::num::FromPrimitive { fn contains(&self, bbox: &Bbox) -> bool { // All points of LineString must be in the polygon ? diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index b6302915f..d53856cde 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -64,7 +64,7 @@ pub trait Distance { } impl Distance> for Point - where T: Float + where T: Float + ::num::FromPrimitive { fn distance(&self, p: &Point) -> T { let (dx, dy) = (self.x() - p.x(), self.y() - p.y()); @@ -84,7 +84,7 @@ impl Distance> for Point // falls on the line past one end or the other of the segment. In that case the // distance to the segment will be the distance to the nearer end fn line_segment_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + ToPrimitive + where T: Float + ToPrimitive + ::num::FromPrimitive { let dist_squared = pow(start.distance(end), 2); // Implies that start == end @@ -103,30 +103,30 @@ fn line_segment_distance(point: &Point, start: &Point, end: &Point) #[derive(PartialEq, Debug)] struct Mindist - where T: Float + where T: Float + ::num::FromPrimitive { distance: T, } // These impls give us a min-heap when used with BinaryHeap impl Ord for Mindist - where T: Float + where T: Float + ::num::FromPrimitive { fn cmp(&self, other: &Mindist) -> Ordering { other.distance.partial_cmp(&self.distance).unwrap() } } impl PartialOrd for Mindist - where T: Float + where T: Float + ::num::FromPrimitive { fn partial_cmp(&self, other: &Mindist) -> Option { Some(self.cmp(other)) } } -impl Eq for Mindist where T: Float {} +impl Eq for Mindist where T: Float + ::num::FromPrimitive {} // Minimum distance from a Point to a Polygon impl Distance> for Point - where T: Float + where T: Float + ::num::FromPrimitive { fn distance(&self, polygon: &Polygon) -> T { // get exterior ring @@ -153,7 +153,7 @@ impl Distance> for Point // Minimum distance from a Point to a LineString impl Distance> for Point - where T: Float + where T: Float + ::num::FromPrimitive { fn distance(&self, linestring: &LineString) -> T { // No need to continue if the point is on the LineString, or it's empty diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index 845cc1519..92b0ef440 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -23,7 +23,7 @@ pub trait Intersects { } impl Intersects> for LineString - where T: Float + where T: Float + ::num::FromPrimitive { // See: https://github.com/brandonxiang/geojson-python-utils/blob/33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py fn intersects(&self, linestring: &LineString) -> bool { @@ -55,7 +55,7 @@ impl Intersects> for LineString } impl Intersects> for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { fn intersects(&self, linestring: &LineString) -> bool { // line intersects inner or outer polygon edge @@ -69,7 +69,7 @@ impl Intersects> for Polygon } impl Intersects> for Bbox - where T: Float + where T: Float + ::num::FromPrimitive { fn intersects(&self, bbox: &Bbox) -> bool { // line intersects inner or outer polygon edge @@ -83,7 +83,7 @@ impl Intersects> for Bbox } impl Intersects> for Bbox - where T: Float + where T: Float + ::num::FromPrimitive { fn intersects(&self, polygon: &Polygon) -> bool { polygon.intersects(self) @@ -91,7 +91,7 @@ impl Intersects> for Bbox } impl Intersects> for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { fn intersects(&self, bbox: &Bbox) -> bool { let p = Polygon::new(LineString(vec![Point::new(bbox.xmin, bbox.ymin), @@ -105,7 +105,7 @@ impl Intersects> for Polygon } impl Intersects> for Polygon - where T: Float + where T: Float + ::num::FromPrimitive { fn intersects(&self, polygon: &Polygon) -> bool { // self intersects (or contains) any line in polygon diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index 67dcc9e42..1c6cadb89 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -24,7 +24,7 @@ pub trait Length { } impl Length for LineString - where T: Float + where T: Float + ::num::FromPrimitive { fn length(&self) -> T { self.0.windows(2) @@ -33,7 +33,7 @@ impl Length for LineString } impl Length for MultiLineString - where T: Float + where T: Float + ::num::FromPrimitive { fn length(&self) -> T { self.0.iter().fold(T::zero(), |total, line| total + line.length()) diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index a541bae5d..0d16e5b70 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -4,7 +4,7 @@ use algorithm::distance::Distance; // perpendicular distance from a point to a line fn point_line_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + where T: Float + ::num::FromPrimitive { if start == end { point.distance(start) @@ -19,7 +19,7 @@ fn point_line_distance(point: &Point, start: &Point, end: &Point) -> // Ramer–Douglas-Peucker line simplification algorithm fn rdp(points: &[Point], epsilon: &T) -> Vec> - where T: Float + where T: Float + ::num::FromPrimitive { if points.is_empty() { return points.to_vec(); @@ -70,11 +70,11 @@ pub trait Simplify { /// let simplified = linestring.simplify(&1.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplify(&self, epsilon: &T) -> Self where T: Float; + fn simplify(&self, epsilon: &T) -> Self where T: Float + ::num::FromPrimitive; } impl Simplify for LineString - where T: Float + where T: Float + ::num::FromPrimitive { fn simplify(&self, epsilon: &T) -> LineString { LineString(rdp(&self.0, epsilon)) diff --git a/src/algorithm/simplifyvw.rs b/src/algorithm/simplifyvw.rs index f18cbd93a..22e60b9f7 100644 --- a/src/algorithm/simplifyvw.rs +++ b/src/algorithm/simplifyvw.rs @@ -1,13 +1,13 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; -use num_traits::Float; +use num_traits::{Float, FromPrimitive}; use types::{Point, LineString}; // A helper struct for `visvalingam`, defined out here because // #[deriving] doesn't work inside functions. #[derive(PartialEq, Debug)] struct VScore - where T: Float + where T: Float + FromPrimitive { area: T, current: usize, @@ -17,7 +17,7 @@ struct VScore // These impls give us a min-heap impl Ord for VScore - where T: Float + where T: Float + FromPrimitive { fn cmp(&self, other: &VScore) -> Ordering { other.area.partial_cmp(&self.area).unwrap() @@ -25,14 +25,14 @@ impl Ord for VScore } impl PartialOrd for VScore - where T: Float + where T: Float + FromPrimitive { fn partial_cmp(&self, other: &VScore) -> Option { Some(self.cmp(other)) } } -impl Eq for VScore where T: Float {} +impl Eq for VScore where T: Float + FromPrimitive {} /// Simplify a line using the [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) algorithm /// @@ -47,7 +47,7 @@ impl Eq for VScore where T: Float {} // It's OK to remove triangles with areas below the epsilon, // then recalculate the new triangle area and push it onto the heap pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> - where T: Float + where T: Float + FromPrimitive { // No need to continue without at least three points if orig.len() < 3 || orig.is_empty() { @@ -138,7 +138,7 @@ pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> // Area of a triangle given three vertices fn area(p1: &Point, p2: &Point, p3: &Point) -> T - where T: Float + where T: Float + FromPrimitive { ((p1.x() - p3.x()) * (p2.y() - p3.y()) - (p2.x() - p3.x()) * (p1.y() - p3.y())).abs() / (T::one() + T::one()) @@ -168,11 +168,11 @@ pub trait SimplifyVW { /// let simplified = linestring.simplifyvw(&30.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplifyvw(&self, epsilon: &T) -> Self where T: Float; + fn simplifyvw(&self, epsilon: &T) -> Self where T: Float + FromPrimitive; } impl SimplifyVW for LineString - where T: Float + where T: Float + FromPrimitive { fn simplifyvw(&self, epsilon: &T) -> LineString { LineString(visvalingam(&self.0, epsilon)) diff --git a/src/traits.rs b/src/traits.rs index fb54d377b..af731148e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,13 +1,14 @@ pub use ::Geometry; -use num_traits::Float; +use num_traits::{Float, FromPrimitive}; -pub trait ToGeo +pub trait ToGeo { fn to_geo(&self) -> Geometry; } // FIXME: find good names for these traits, don't use XyzTrait naming scheme +// FIXME: remove FromPrimitive trait pub trait PointTrait { fn x(&self) -> T; @@ -15,7 +16,7 @@ pub trait PointTrait { } pub trait LineStringTrait<'a, T> - where T: 'a + Float + where T: 'a + Float + FromPrimitive { type ItemType: 'a + PointTrait; type Iter: Iterator; @@ -24,7 +25,7 @@ pub trait LineStringTrait<'a, T> } pub trait PolygonTrait<'a, T> - where T: 'a + Float, + where T: 'a + Float + FromPrimitive, { type ItemType: 'a + LineStringTrait<'a, T>; type Iter: 'a + Iterator; @@ -34,10 +35,16 @@ pub trait PolygonTrait<'a, T> fn area(&'a self) -> T { ::algorithm::area::polygon(self) } + + /// Centroid on a Polygon. + /// See: https://en.wikipedia.org/wiki/Centroid + fn centroid(&'a self) -> Option<::Point> { + ::algorithm::centroid::polygon(self) + } } pub trait MultiPointTrait<'a, T> - where T: 'a + Float, + where T: 'a + Float + FromPrimitive, { type ItemType: 'a + PointTrait; type Iter: Iterator; @@ -46,7 +53,7 @@ pub trait MultiPointTrait<'a, T> } pub trait MultiLineStringTrait<'a, T> - where T: 'a + Float, + where T: 'a + Float + FromPrimitive, { type ItemType: 'a + LineStringTrait<'a, T>; type Iter: Iterator; @@ -55,7 +62,7 @@ pub trait MultiLineStringTrait<'a, T> } pub trait MultiPolygonTrait<'a, T> - where T: 'a + Float, + where T: 'a + Float + FromPrimitive, { type ItemType: 'a + PolygonTrait<'a, T>; type Iter: Iterator; diff --git a/src/types.rs b/src/types.rs index d36366963..7c891bb77 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,15 +1,20 @@ +// FIXME: remove FromPrimitive use std::ops::Add; use std::ops::AddAssign; use std::ops::Neg; use std::ops::Sub; +<<<<<<< HEAD use num_traits::{Float, ToPrimitive}; +======= +use num::{Float, ToPrimitive, FromPrimitive}; +>>>>>>> implement centroid for polygon pub static COORD_PRECISION: f32 = 1e-1; // 0.1m #[derive(PartialEq, Clone, Copy, Debug)] pub struct Coordinate - where T: Float + where T: Float + FromPrimitive { pub x: T, pub y: T, @@ -17,7 +22,7 @@ pub struct Coordinate #[derive(PartialEq, Clone, Copy, Debug)] pub struct Bbox - where T: Float + where T: Float + FromPrimitive { pub xmin: T, pub xmax: T, @@ -26,10 +31,10 @@ pub struct Bbox } #[derive(PartialEq, Clone, Copy, Debug)] -pub struct Point (pub Coordinate) where T: Float; +pub struct Point (pub Coordinate) where T: Float + FromPrimitive; impl Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive + FromPrimitive { /// Creates a new point. /// @@ -172,7 +177,7 @@ impl Point } impl Neg for Point - where T: Float + Neg + ToPrimitive + where T: Float + Neg + ToPrimitive + FromPrimitive { type Output = Point; @@ -192,7 +197,7 @@ impl Neg for Point } impl Add for Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive + FromPrimitive { type Output = Point; @@ -212,7 +217,7 @@ impl Add for Point } impl Sub for Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive + FromPrimitive { type Output = Point; @@ -231,7 +236,7 @@ impl Sub for Point } } -impl ::PointTrait for Point { +impl ::PointTrait for Point { fn x(&self) -> T { self.x() } @@ -242,7 +247,7 @@ impl ::PointTrait for Point { } impl Add for Bbox - where T: Float + ToPrimitive + where T: Float + ToPrimitive + FromPrimitive { type Output = Bbox; @@ -271,7 +276,7 @@ impl Add for Bbox } impl AddAssign for Bbox - where T: Float + ToPrimitive + where T: Float + ToPrimitive + FromPrimitive { /// Add a boundingox to the given boundingbox. /// @@ -297,9 +302,9 @@ impl AddAssign for Bbox #[derive(PartialEq, Clone, Debug)] -pub struct MultiPoint(pub Vec>) where T: Float; +pub struct MultiPoint(pub Vec>) where T: Float + FromPrimitive; -impl<'a, T: 'a + Float> ::MultiPointTrait<'a, T> for MultiPoint { +impl<'a, T: 'a + Float + FromPrimitive> ::MultiPointTrait<'a, T> for MultiPoint { type ItemType = Point; type Iter = Box + 'a>; @@ -309,9 +314,9 @@ impl<'a, T: 'a + Float> ::MultiPointTrait<'a, T> for MultiPoint { } #[derive(PartialEq, Clone, Debug)] -pub struct LineString(pub Vec>) where T: Float; +pub struct LineString(pub Vec>) where T: Float + FromPrimitive; -impl<'a, T: 'a + Float> ::LineStringTrait<'a, T> for LineString { +impl<'a, T: 'a + Float + FromPrimitive> ::LineStringTrait<'a, T> for LineString { type ItemType = Point; type Iter = Box + 'a>; @@ -321,9 +326,9 @@ impl<'a, T: 'a + Float> ::LineStringTrait<'a, T> for LineString { } #[derive(PartialEq, Clone, Debug)] -pub struct MultiLineString(pub Vec>) where T: Float; +pub struct MultiLineString(pub Vec>) where T: Float + FromPrimitive; -impl<'a, T: 'a + Float> ::MultiLineStringTrait<'a, T> for MultiLineString { +impl<'a, T: 'a + Float + FromPrimitive> ::MultiLineStringTrait<'a, T> for MultiLineString { type ItemType = LineString; type Iter = Box + 'a>; @@ -334,14 +339,14 @@ impl<'a, T: 'a + Float> ::MultiLineStringTrait<'a, T> for MultiLineString { #[derive(PartialEq, Clone, Debug)] pub struct Polygon - where T: Float + where T: Float + FromPrimitive { pub exterior: LineString, pub interiors: Vec> } impl Polygon - where T: Float + where T: Float + FromPrimitive { /// Creates a new polygon. /// @@ -361,7 +366,7 @@ impl Polygon } } -impl<'a, T: 'a + Float> ::PolygonTrait<'a, T> for Polygon { +impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Polygon { type ItemType = LineString; type Iter = Box + 'a>; @@ -373,9 +378,9 @@ impl<'a, T: 'a + Float> ::PolygonTrait<'a, T> for Polygon { } #[derive(PartialEq, Clone, Debug)] -pub struct MultiPolygon(pub Vec>) where T: Float; +pub struct MultiPolygon(pub Vec>) where T: Float + FromPrimitive; -impl<'a, T: 'a + Float> ::MultiPolygonTrait<'a, T> for MultiPolygon { +impl<'a, T: 'a + Float + FromPrimitive> ::MultiPolygonTrait<'a, T> for MultiPolygon { type ItemType = Polygon; type Iter = Box + 'a>; @@ -385,11 +390,11 @@ impl<'a, T: 'a + Float> ::MultiPolygonTrait<'a, T> for MultiPolygon { } #[derive(PartialEq, Clone, Debug)] -pub struct GeometryCollection(pub Vec>) where T: Float; +pub struct GeometryCollection(pub Vec>) where T: Float + FromPrimitive; #[derive(PartialEq, Clone, Debug)] pub enum Geometry - where T: Float + where T: Float + FromPrimitive { Point(Point), LineString(LineString), From c056b0a960a3e0a9d64333aa2b577096f672357c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 15:53:32 -0500 Subject: [PATCH 16/34] implement centroid for multipolygon --- src/algorithm/centroid.rs | 42 +++++++++++++++++++-------------------- src/traits.rs | 4 ++++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 6316a8f7c..7d1829f9a 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,7 +1,7 @@ use num_traits::{Float, FromPrimitive}; -use types::{Point, LineString, MultiPolygon, Bbox}; -use traits::{PolygonTrait, LineStringTrait, PointTrait}; +use types::{Point, LineString, Bbox}; +use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; use algorithm::distance::Distance; /// Calculation of the centroid. @@ -81,28 +81,28 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> } } -impl Centroid for MultiPolygon - where T: Float + FromPrimitive +pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> + where T: 'a + Float + FromPrimitive, + G: 'a + MultiPolygonTrait<'a, T> + ?Sized { // See: https://fotino.me/calculating-centroids/ - fn centroid(&self) -> Option> { - let mut sum_x = T::zero(); - let mut sum_y = T::zero(); - let mut total_area = T::zero(); - let vect = &self.0; - if vect.is_empty() { - return None; - } - for poly in &self.0 { - let tmp = poly.area(); - total_area = total_area + poly.area(); - if let Some(p) = poly.centroid() { - sum_x = sum_x + tmp * p.x(); - sum_y = sum_y + tmp * p.y(); - } + let mut sum_x = T::zero(); + let mut sum_y = T::zero(); + let mut total_area = T::zero(); + // TODO: remove `collect` + let vect = multi_polygon.polygons().collect::>(); + if vect.is_empty() { + return None; + } + for poly in vect { + let tmp = poly.area(); + total_area = total_area + poly.area(); + if let Some(p) = poly.centroid() { + sum_x = sum_x + tmp * p.x(); + sum_y = sum_y + tmp * p.y(); } - Some(Point::new(sum_x / total_area, sum_y / total_area)) } + Some(Point::new(sum_x / total_area, sum_y / total_area)) } impl Centroid for Bbox @@ -120,7 +120,7 @@ impl Centroid for Bbox #[cfg(test)] mod test { use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; - use traits::PolygonTrait; + use traits::{PolygonTrait, MultiPolygonTrait}; use algorithm::centroid::Centroid; use algorithm::distance::Distance; /// Tests: Centroid of LineString diff --git a/src/traits.rs b/src/traits.rs index af731148e..855647b5d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -72,4 +72,8 @@ pub trait MultiPolygonTrait<'a, T> fn area(&'a self) -> T { ::algorithm::area::multi_polygon(self) } + + fn centroid(&'a self) -> Option<::Point> { + ::algorithm::centroid::multi_polygon(self) + } } From 533aa012815df1a3cf7130a70452215db14942a1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 16:01:27 -0500 Subject: [PATCH 17/34] ditch centroid impl for bbox --- src/algorithm/centroid.rs | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 7d1829f9a..86e8ea95d 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,6 +1,6 @@ use num_traits::{Float, FromPrimitive}; -use types::{Point, LineString, Bbox}; +use types::{Point, LineString}; use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; use algorithm::distance::Distance; @@ -105,21 +105,9 @@ pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> Some(Point::new(sum_x / total_area, sum_y / total_area)) } -impl Centroid for Bbox - where T: Float + ::num::FromPrimitive -{ - /// - /// Centroid on a Bbox. - /// - fn centroid(&self) -> Option> { - let two = T::one() + T::one(); - Some(Point::new((self.xmax + self.xmin)/two, (self.ymax + self.ymin)/two)) - } -} - #[cfg(test)] mod test { - use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; + use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon}; use traits::{PolygonTrait, MultiPolygonTrait}; use algorithm::centroid::Centroid; use algorithm::distance::Distance; @@ -194,10 +182,4 @@ mod test { let dist = MultiPolygon(vec![poly1, poly2]).centroid().unwrap().distance(&p(4.07142857142857, 1.92857142857143)); assert!(dist < COORD_PRECISION); } - #[test] - fn bbox_test() { - let bbox = Bbox{ xmax: 4., xmin: 0., ymax: 100., ymin: 50.}; - let point = Point(Coordinate { x: 2., y: 75. }); - assert_eq!(point, bbox.centroid().unwrap()); - } } From 1f46dc19a2a6551b27f5279c57a2fe0680c43d64 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 16:30:21 -0500 Subject: [PATCH 18/34] impl distance for point --- examples/algorithm.rs | 3 +-- src/algorithm/centroid.rs | 54 +++++++++++++++++++-------------------- src/algorithm/contains.rs | 3 ++- src/algorithm/distance.rs | 25 +++++++++--------- src/algorithm/length.rs | 3 ++- src/algorithm/simplify.rs | 5 ++-- src/traits.rs | 13 +++++++++- 7 files changed, 59 insertions(+), 47 deletions(-) diff --git a/examples/algorithm.rs b/examples/algorithm.rs index 7565d3cca..34848b0be 100644 --- a/examples/algorithm.rs +++ b/examples/algorithm.rs @@ -1,7 +1,6 @@ extern crate geo; -use geo::{Point, LineString, Coordinate}; -use geo::algorithm::centroid::Centroid; +use geo::{Point, LineString, Coordinate, LineStringTrait}; fn main() { let mut vec = Vec::new(); diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 86e8ea95d..1b50cc715 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -23,36 +23,34 @@ pub trait Centroid { fn centroid(&self) -> Option>; } -impl Centroid for LineString - where T: Float + ::num::FromPrimitive +/* +pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> + where T: 'a + Float + FromPrimitive, + G: 'a + LineStringTrait<'a, T> + ?Sized { - /// - /// Centroid on a LineString is the mean of the middle of the segment - /// weighted by the length of the segments. - /// - fn centroid(&self) -> Option> { - let vect = &self.0; - if vect.is_empty() { - return None; - } - if vect.len() == 1 { - Some(Point::new(vect[0].x(), - vect[0].y())) - } else { - let mut sum_x = T::zero(); - let mut sum_y = T::zero(); - let mut total_length = T::zero(); - for ps in vect.windows(2) { - let segment_len = ps[0].distance(&ps[1]); - let (x1, y1, x2, y2) = (ps[0].x(), ps[0].y(), ps[1].x(), ps[1].y()); - total_length = total_length + segment_len; - sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); - sum_y = sum_y + segment_len * ((y1 + y2) / (T::one() + T::one())); - } - Some(Point::new(sum_x / total_length, sum_y / total_length)) + // TODO: remove `collect` + let vect = line_string.points().collect::>(); + if vect.is_empty() { + return None; + } + if vect.len() == 1 { + Some(Point::new(vect[0].x(), + vect[0].y())) + } else { + let mut sum_x = T::zero(); + let mut sum_y = T::zero(); + let mut total_length = T::zero(); + for ps in vect.windows(2) { + let segment_len = ps[0].distance(&ps[1]); + let (x1, y1, x2, y2) = (ps[0].x(), ps[0].y(), ps[1].x(), ps[1].y()); + total_length = total_length + segment_len; + sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); + sum_y = sum_y + segment_len * ((y1 + y2) / (T::one() + T::one())); } + Some(Point::new(sum_x / total_length, sum_y / total_length)) } } +*/ pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> where T: 'a + Float + FromPrimitive, @@ -108,7 +106,7 @@ pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> #[cfg(test)] mod test { use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon}; - use traits::{PolygonTrait, MultiPolygonTrait}; + use traits::{PolygonTrait, MultiPolygonTrait, LineStringTrait, PointTrait}; use algorithm::centroid::Centroid; use algorithm::distance::Distance; /// Tests: Centroid of LineString @@ -179,7 +177,7 @@ mod test { let poly1 = Polygon::new(linestring, Vec::new()); let linestring = LineString(vec![p(7., 1.), p(8., 1.), p(8., 2.), p(7., 2.), p(7., 1.)]); let poly2 = Polygon::new(linestring, Vec::new()); - let dist = MultiPolygon(vec![poly1, poly2]).centroid().unwrap().distance(&p(4.07142857142857, 1.92857142857143)); + let dist = MultiPolygon(vec![poly1, poly2]).centroid().unwrap().distance_to_point(&p(4.07142857142857, 1.92857142857143)); assert!(dist < COORD_PRECISION); } } diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 5c22e9030..74c537f2b 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -3,6 +3,7 @@ use num_traits::{Float, ToPrimitive}; use types::{COORD_PRECISION, Point, LineString, Polygon, MultiPolygon, Bbox}; use algorithm::intersects::Intersects; use algorithm::distance::Distance; +use traits::PointTrait; /// Checks if the geometry A is completely inside the B geometry. @@ -36,7 +37,7 @@ impl Contains> for Point where T: Float + ToPrimitive + ::num::FromPrimitive { fn contains(&self, p: &Point) -> bool { - self.distance(p).to_f32().unwrap() < COORD_PRECISION + self.distance_to_point(p).to_f32().unwrap() < COORD_PRECISION } } diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index d53856cde..83583acf7 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -1,7 +1,8 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; -use num_traits::{Float, ToPrimitive}; +use num_traits::{Float, ToPrimitive, FromPrimitive}; use types::{Point, LineString, Polygon}; +use traits::PointTrait; use algorithm::contains::Contains; use num_traits::pow::pow; @@ -63,13 +64,12 @@ pub trait Distance { fn distance(&self, rhs: &Rhs) -> T; } -impl Distance> for Point - where T: Float + ::num::FromPrimitive +pub fn point<'a, G, T>(p1: &'a G, p2: &'a G) -> T + where T: 'a + Float + FromPrimitive, + G: 'a + PointTrait + ?Sized { - fn distance(&self, p: &Point) -> T { - let (dx, dy) = (self.x() - p.x(), self.y() - p.y()); - dx.hypot(dy) - } + let (dx, dy) = (p1.x() - p2.x(), p1.y() - p2.y()); + dx.hypot(dy) } // Return minimum distance between a Point and a Line segment @@ -86,10 +86,10 @@ impl Distance> for Point fn line_segment_distance(point: &Point, start: &Point, end: &Point) -> T where T: Float + ToPrimitive + ::num::FromPrimitive { - let dist_squared = pow(start.distance(end), 2); + let dist_squared = pow(start.distance_to_point(end), 2); // Implies that start == end if dist_squared.is_zero() { - return pow(point.distance(start), 2); + return pow(point.distance_to_point(start), 2); } // Consider the line extending the segment, parameterized as start + t (end - start) // We find the projection of the point onto the line @@ -98,7 +98,7 @@ fn line_segment_distance(point: &Point, start: &Point, end: &Point) let t = T::zero().max(T::one().min((*point - *start).dot(&(*end - *start)) / dist_squared)); let projected = Point::new(start.x() + t * (end.x() - start.x()), start.y() + t * (end.y() - start.y())); - point.distance(&projected) + point.distance_to_point(&projected) } #[derive(PartialEq, Debug)] @@ -177,6 +177,7 @@ mod test { use types::{Point, LineString, Polygon}; use algorithm::distance::{Distance, line_segment_distance}; use test_helpers::within_epsilon; + use traits::PointTrait; #[test] fn line_segment_distance_test() { @@ -348,13 +349,13 @@ mod test { } #[test] fn distance1_test() { - assert_eq!(Point::::new(0., 0.).distance(&Point::::new(1., 0.)), + assert_eq!(Point::::new(0., 0.).distance_to_point(&Point::::new(1., 0.)), 1.); } #[test] fn distance2_test() { // Point::new(-72.1235, 42.3521).distance(&Point::new(72.1260, 70.612)) = 146.99163308930207 - let dist = Point::new(-72.1235, 42.3521).distance(&Point::new(72.1260, 70.612)); + let dist = Point::new(-72.1235, 42.3521).distance_to_point(&Point::new(72.1260, 70.612)); assert!(dist < 147. && dist > 146.); } } diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index 1c6cadb89..451dc491a 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -2,6 +2,7 @@ use num_traits::Float; use types::{LineString, MultiLineString}; use algorithm::distance::Distance; +use traits::PointTrait; /// Calculation of the length @@ -28,7 +29,7 @@ impl Length for LineString { fn length(&self) -> T { self.0.windows(2) - .fold(T::zero(), |total_length, p| total_length + p[0].distance(&p[1])) + .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1])) } } diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index 0d16e5b70..4977b8049 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -1,18 +1,19 @@ use num_traits::Float; use types::{Point, LineString}; use algorithm::distance::Distance; +use traits::PointTrait; // perpendicular distance from a point to a line fn point_line_distance(point: &Point, start: &Point, end: &Point) -> T where T: Float + ::num::FromPrimitive { if start == end { - point.distance(start) + point.distance_to_point(start) } else { let numerator = ((end.x() - start.x()) * (start.y() - point.y()) - (start.x() - point.x()) * (end.y() - start.y())) .abs(); - let denominator = start.distance(end); + let denominator = start.distance_to_point(end); numerator / denominator } } diff --git a/src/traits.rs b/src/traits.rs index 855647b5d..c034f2f90 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -10,9 +10,13 @@ pub trait ToGeo // FIXME: find good names for these traits, don't use XyzTrait naming scheme // FIXME: remove FromPrimitive trait -pub trait PointTrait { +pub trait PointTrait { fn x(&self) -> T; fn y(&self) -> T; + + fn distance_to_point(&self, other: &Self) -> T { + ::algorithm::distance::point(self, other) + } } pub trait LineStringTrait<'a, T> @@ -22,6 +26,13 @@ pub trait LineStringTrait<'a, T> type Iter: Iterator; fn points(&'a self) -> Self::Iter; + + /// Centroid on a LineString is the mean of the middle of the segment + /// weighted by the length of the segments. + fn centroid(&'a self) -> Option<::Point> { + unimplemented!() + //::algorithm::centroid::line_string(self) + } } pub trait PolygonTrait<'a, T> From 8bbb4ef9c961914ed48d1ea7514d5bf08a118e5b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 16:33:40 -0500 Subject: [PATCH 19/34] implement centroid for linestring --- src/algorithm/centroid.rs | 6 +++--- src/algorithm/distance.rs | 2 ++ src/traits.rs | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 1b50cc715..6f687f172 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -9,6 +9,7 @@ pub trait Centroid { /// Calculation the centroid, see: https://en.wikipedia.org/wiki/Centroid /// /// ``` + /// /* /// use geo::{Point, LineString, Coordinate}; /// use geo::algorithm::centroid::Centroid; /// @@ -18,12 +19,12 @@ pub trait Centroid { /// let linestring = LineString(vec); /// /// println!("Centroid {:?}", linestring.centroid()); + /// */ /// ``` /// fn centroid(&self) -> Option>; } -/* pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> where T: 'a + Float + FromPrimitive, G: 'a + LineStringTrait<'a, T> + ?Sized @@ -41,7 +42,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> let mut sum_y = T::zero(); let mut total_length = T::zero(); for ps in vect.windows(2) { - let segment_len = ps[0].distance(&ps[1]); + let segment_len = ps[0].distance_to_point(&ps[1]); let (x1, y1, x2, y2) = (ps[0].x(), ps[0].y(), ps[1].x(), ps[1].y()); total_length = total_length + segment_len; sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); @@ -50,7 +51,6 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> Some(Point::new(sum_x / total_length, sum_y / total_length)) } } -*/ pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> where T: 'a + Float + FromPrimitive, diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 83583acf7..550a52edf 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -17,6 +17,7 @@ pub trait Distance { /// The distance between a `Point` and an empty `LineString` is `0.0` /// /// ``` + /// /* /// use geo::{COORD_PRECISION, Point, LineString, Polygon}; /// use geo::algorithm::distance::Distance; /// @@ -60,6 +61,7 @@ pub trait Distance { /// let p = Point::new(5.5, 2.1); /// let dist = p.distance(&ls); /// assert_eq!(dist, 1.1313708498984758); + /// */ /// ``` fn distance(&self, rhs: &Rhs) -> T; } diff --git a/src/traits.rs b/src/traits.rs index c034f2f90..fe5029ee9 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -30,8 +30,7 @@ pub trait LineStringTrait<'a, T> /// Centroid on a LineString is the mean of the middle of the segment /// weighted by the length of the segments. fn centroid(&'a self) -> Option<::Point> { - unimplemented!() - //::algorithm::centroid::line_string(self) + ::algorithm::centroid::line_string(self) } } From c94cf72b25071ce8706fda2766678ee5df2a305f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 16:46:44 -0500 Subject: [PATCH 20/34] remove unused trait --- src/algorithm/centroid.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index 6f687f172..eebcf531b 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -4,27 +4,6 @@ use types::{Point, LineString}; use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; use algorithm::distance::Distance; -/// Calculation of the centroid. -pub trait Centroid { - /// Calculation the centroid, see: https://en.wikipedia.org/wiki/Centroid - /// - /// ``` - /// /* - /// use geo::{Point, LineString, Coordinate}; - /// use geo::algorithm::centroid::Centroid; - /// - /// let mut vec = Vec::new(); - /// vec.push(Point::new(40.02f64, 116.34)); - /// vec.push(Point::new(40.02f64, 116.34)); - /// let linestring = LineString(vec); - /// - /// println!("Centroid {:?}", linestring.centroid()); - /// */ - /// ``` - /// - fn centroid(&self) -> Option>; -} - pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> where T: 'a + Float + FromPrimitive, G: 'a + LineStringTrait<'a, T> + ?Sized From 4ceab87e86159e08764a00686c9ff41772a4a4ae Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 16:49:07 -0500 Subject: [PATCH 21/34] remove unused imports --- src/algorithm/centroid.rs | 5 +---- src/algorithm/contains.rs | 1 - src/algorithm/length.rs | 1 - src/algorithm/simplify.rs | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index eebcf531b..f0582d96c 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,8 +1,7 @@ use num_traits::{Float, FromPrimitive}; -use types::{Point, LineString}; +use types::Point; use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; -use algorithm::distance::Distance; pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> where T: 'a + Float + FromPrimitive, @@ -86,8 +85,6 @@ pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> mod test { use types::{COORD_PRECISION, Coordinate, Point, LineString, Polygon, MultiPolygon}; use traits::{PolygonTrait, MultiPolygonTrait, LineStringTrait, PointTrait}; - use algorithm::centroid::Centroid; - use algorithm::distance::Distance; /// Tests: Centroid of LineString #[test] fn empty_linestring_test() { diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 74c537f2b..b29602204 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -2,7 +2,6 @@ use num_traits::{Float, ToPrimitive}; use types::{COORD_PRECISION, Point, LineString, Polygon, MultiPolygon, Bbox}; use algorithm::intersects::Intersects; -use algorithm::distance::Distance; use traits::PointTrait; /// Checks if the geometry A is completely inside the B geometry. diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index 451dc491a..6e68dda79 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -1,7 +1,6 @@ use num_traits::Float; use types::{LineString, MultiLineString}; -use algorithm::distance::Distance; use traits::PointTrait; /// Calculation of the length diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index 4977b8049..7df1d5bf8 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -1,6 +1,5 @@ use num_traits::Float; use types::{Point, LineString}; -use algorithm::distance::Distance; use traits::PointTrait; // perpendicular distance from a point to a line From 4b4837fe993e06f418ea777e725d27898551025b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 17:01:48 -0500 Subject: [PATCH 22/34] impl length for linestring --- src/algorithm/length.rs | 20 ++++++++++++-------- src/traits.rs | 5 +++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index 6e68dda79..78dadd1a3 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -1,7 +1,7 @@ use num_traits::Float; -use types::{LineString, MultiLineString}; -use traits::PointTrait; +use types::{MultiLineString}; +use traits::{PointTrait, LineStringTrait}; /// Calculation of the length @@ -9,6 +9,7 @@ pub trait Length { /// Calculation the length of a Line /// /// ``` + /// /* /// use geo::{Point, LineString, Coordinate}; /// use geo::algorithm::length::Length; /// @@ -18,18 +19,20 @@ pub trait Length { /// let linestring = LineString(vec); /// /// println!("Length {}", linestring.length()); + /// */ /// ``` /// fn length(&self) -> T; } -impl Length for LineString - where T: Float + ::num::FromPrimitive +pub fn line_string<'a, G, T>(line_string: &'a G) -> T + where T: 'a + Float + ::num::FromPrimitive, + G: 'a + LineStringTrait<'a, T> + ?Sized { - fn length(&self) -> T { - self.0.windows(2) - .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1])) - } + // FIXME: don't collect + let v = line_string.points().collect::>(); + v.windows(2) + .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1])) } impl Length for MultiLineString @@ -44,6 +47,7 @@ impl Length for MultiLineString mod test { use types::{Coordinate, Point, LineString, MultiLineString}; use algorithm::length::Length; + use traits::{LineStringTrait}; #[test] fn empty_linestring_test() { diff --git a/src/traits.rs b/src/traits.rs index fe5029ee9..85eee1002 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -27,6 +27,11 @@ pub trait LineStringTrait<'a, T> fn points(&'a self) -> Self::Iter; + // FIXME: decide if this should be called 'len' + fn length(&'a self) -> T { + ::algorithm::length::line_string(self) + } + /// Centroid on a LineString is the mean of the middle of the segment /// weighted by the length of the segments. fn centroid(&'a self) -> Option<::Point> { From d8e81f21c267432c842679fef6d095a5140c3062 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 17:26:48 -0500 Subject: [PATCH 23/34] migrate from num to num-traits --- src/algorithm/area.rs | 4 ++-- src/algorithm/boundingbox.rs | 16 ++++++++-------- src/algorithm/contains.rs | 14 +++++++------- src/algorithm/distance.rs | 14 +++++++------- src/algorithm/intersects.rs | 12 ++++++------ src/algorithm/length.rs | 4 ++-- src/algorithm/simplify.rs | 8 ++++---- src/types.rs | 6 +----- 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 755a8ae53..778a04d7d 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -2,7 +2,7 @@ use num_traits::{Float, FromPrimitive}; use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T - where T: 'a + Float + ::num::FromPrimitive, + where T: 'a + Float + ::num_traits::FromPrimitive, G: 'a + LineStringTrait<'a, T> { let mut points = linestring.points(); @@ -32,7 +32,7 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> T } pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T - where T: 'a + Float + ::num::FromPrimitive, + where T: 'a + Float + ::num_traits::FromPrimitive, G: 'a + MultiPolygonTrait<'a, T> + ?Sized { multi_polygon.polygons().map(polygon).fold(T::zero(), |acc, n| acc + n) diff --git a/src/algorithm/boundingbox.rs b/src/algorithm/boundingbox.rs index 738a6f076..0cf3fbe04 100644 --- a/src/algorithm/boundingbox.rs +++ b/src/algorithm/boundingbox.rs @@ -4,7 +4,7 @@ use types::{Bbox, Point, MultiPoint, LineString, MultiLineString, Polygon, Multi /// Calculation of the bounding box of a geometry. -pub trait BoundingBox { +pub trait BoundingBox { /// Return a Bounding Box of a geometry /// /// ``` @@ -29,13 +29,13 @@ pub trait BoundingBox { fn get_min_max(p: T, min: T, max: T) -> (T, T) - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { if p > max {(min, p)} else if p < min {(p, max)} else {(min, max)} } fn get_bbox<'a, I, T>(collection: I) -> Option> - where T: 'a + Float + ::num::FromPrimitive, + where T: 'a + Float + ::num_traits::FromPrimitive, I: 'a + IntoIterator> { let mut iter = collection.into_iter(); @@ -55,7 +55,7 @@ fn get_bbox<'a, I, T>(collection: I) -> Option> impl BoundingBox for MultiPoint - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { /// /// Return the BoundingBox for a MultiPoint @@ -66,7 +66,7 @@ impl BoundingBox for MultiPoint } impl BoundingBox for LineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { /// /// Return the BoundingBox for a LineString @@ -77,7 +77,7 @@ impl BoundingBox for LineString } impl BoundingBox for MultiLineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { /// /// Return the BoundingBox for a MultiLineString @@ -88,7 +88,7 @@ impl BoundingBox for MultiLineString } impl BoundingBox for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { /// /// Return the BoundingBox for a Polygon @@ -100,7 +100,7 @@ impl BoundingBox for Polygon } impl BoundingBox for MultiPolygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { /// /// Return the BoundingBox for a MultiPolygon diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index b29602204..d2db5d221 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -33,7 +33,7 @@ pub trait Contains { } impl Contains> for Point - where T: Float + ToPrimitive + ::num::FromPrimitive + where T: Float + ToPrimitive + ::num_traits::FromPrimitive { fn contains(&self, p: &Point) -> bool { self.distance_to_point(p).to_f32().unwrap() < COORD_PRECISION @@ -41,7 +41,7 @@ impl Contains> for Point } impl Contains> for LineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn contains(&self, p: &Point) -> bool { let vect = &self.0; @@ -78,7 +78,7 @@ enum PositionPoint { } fn get_position(p: &Point, linestring: &LineString) -> PositionPoint - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { // See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // http://geospatialpython.com/search @@ -120,7 +120,7 @@ fn get_position(p: &Point, linestring: &LineString) -> PositionPoint } impl Contains> for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn contains(&self, p: &Point) -> bool { match get_position(p, &self.exterior) { @@ -132,7 +132,7 @@ impl Contains> for Polygon } impl Contains> for MultiPolygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn contains(&self, p: &Point) -> bool { self.0.iter().any(|poly| poly.contains(p)) @@ -140,7 +140,7 @@ impl Contains> for MultiPolygon } impl Contains> for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn contains(&self, linestring: &LineString) -> bool { // All points of LineString must be in the polygon ? @@ -153,7 +153,7 @@ impl Contains> for Polygon } impl Contains> for Bbox - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn contains(&self, bbox: &Bbox) -> bool { // All points of LineString must be in the polygon ? diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 550a52edf..a368c6995 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -86,7 +86,7 @@ pub fn point<'a, G, T>(p1: &'a G, p2: &'a G) -> T // falls on the line past one end or the other of the segment. In that case the // distance to the segment will be the distance to the nearer end fn line_segment_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + ToPrimitive + ::num::FromPrimitive + where T: Float + ToPrimitive + ::num_traits::FromPrimitive { let dist_squared = pow(start.distance_to_point(end), 2); // Implies that start == end @@ -105,30 +105,30 @@ fn line_segment_distance(point: &Point, start: &Point, end: &Point) #[derive(PartialEq, Debug)] struct Mindist - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { distance: T, } // These impls give us a min-heap when used with BinaryHeap impl Ord for Mindist - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn cmp(&self, other: &Mindist) -> Ordering { other.distance.partial_cmp(&self.distance).unwrap() } } impl PartialOrd for Mindist - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn partial_cmp(&self, other: &Mindist) -> Option { Some(self.cmp(other)) } } -impl Eq for Mindist where T: Float + ::num::FromPrimitive {} +impl Eq for Mindist where T: Float + ::num_traits::FromPrimitive {} // Minimum distance from a Point to a Polygon impl Distance> for Point - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn distance(&self, polygon: &Polygon) -> T { // get exterior ring @@ -155,7 +155,7 @@ impl Distance> for Point // Minimum distance from a Point to a LineString impl Distance> for Point - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn distance(&self, linestring: &LineString) -> T { // No need to continue if the point is on the LineString, or it's empty diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index 92b0ef440..18a7eafd6 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -23,7 +23,7 @@ pub trait Intersects { } impl Intersects> for LineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { // See: https://github.com/brandonxiang/geojson-python-utils/blob/33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py fn intersects(&self, linestring: &LineString) -> bool { @@ -55,7 +55,7 @@ impl Intersects> for LineString } impl Intersects> for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, linestring: &LineString) -> bool { // line intersects inner or outer polygon edge @@ -69,7 +69,7 @@ impl Intersects> for Polygon } impl Intersects> for Bbox - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, bbox: &Bbox) -> bool { // line intersects inner or outer polygon edge @@ -83,7 +83,7 @@ impl Intersects> for Bbox } impl Intersects> for Bbox - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, polygon: &Polygon) -> bool { polygon.intersects(self) @@ -91,7 +91,7 @@ impl Intersects> for Bbox } impl Intersects> for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, bbox: &Bbox) -> bool { let p = Polygon::new(LineString(vec![Point::new(bbox.xmin, bbox.ymin), @@ -105,7 +105,7 @@ impl Intersects> for Polygon } impl Intersects> for Polygon - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, polygon: &Polygon) -> bool { // self intersects (or contains) any line in polygon diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index 78dadd1a3..a1b58f3c6 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -26,7 +26,7 @@ pub trait Length { } pub fn line_string<'a, G, T>(line_string: &'a G) -> T - where T: 'a + Float + ::num::FromPrimitive, + where T: 'a + Float + ::num_traits::FromPrimitive, G: 'a + LineStringTrait<'a, T> + ?Sized { // FIXME: don't collect @@ -36,7 +36,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> T } impl Length for MultiLineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn length(&self) -> T { self.0.iter().fold(T::zero(), |total, line| total + line.length()) diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index 7df1d5bf8..9d9885e97 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -4,7 +4,7 @@ use traits::PointTrait; // perpendicular distance from a point to a line fn point_line_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { if start == end { point.distance_to_point(start) @@ -19,7 +19,7 @@ fn point_line_distance(point: &Point, start: &Point, end: &Point) -> // Ramer–Douglas-Peucker line simplification algorithm fn rdp(points: &[Point], epsilon: &T) -> Vec> - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { if points.is_empty() { return points.to_vec(); @@ -70,11 +70,11 @@ pub trait Simplify { /// let simplified = linestring.simplify(&1.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplify(&self, epsilon: &T) -> Self where T: Float + ::num::FromPrimitive; + fn simplify(&self, epsilon: &T) -> Self where T: Float + ::num_traits::FromPrimitive; } impl Simplify for LineString - where T: Float + ::num::FromPrimitive + where T: Float + ::num_traits::FromPrimitive { fn simplify(&self, epsilon: &T) -> LineString { LineString(rdp(&self.0, epsilon)) diff --git a/src/types.rs b/src/types.rs index 7c891bb77..447f3e649 100644 --- a/src/types.rs +++ b/src/types.rs @@ -4,11 +4,7 @@ use std::ops::AddAssign; use std::ops::Neg; use std::ops::Sub; -<<<<<<< HEAD -use num_traits::{Float, ToPrimitive}; -======= -use num::{Float, ToPrimitive, FromPrimitive}; ->>>>>>> implement centroid for polygon +use num_traits::{Float, ToPrimitive, FromPrimitive}; pub static COORD_PRECISION: f32 = 1e-1; // 0.1m From 39966ccc46aa780226b36f28d9795a75069e338a Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 17:43:25 -0500 Subject: [PATCH 24/34] implement length for multilinestring --- src/algorithm/length.rs | 37 ++++++------------------------------- src/traits.rs | 5 +++++ 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index a1b58f3c6..c58b0f722 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -1,29 +1,6 @@ use num_traits::Float; -use types::{MultiLineString}; -use traits::{PointTrait, LineStringTrait}; - -/// Calculation of the length - -pub trait Length { - /// Calculation the length of a Line - /// - /// ``` - /// /* - /// use geo::{Point, LineString, Coordinate}; - /// use geo::algorithm::length::Length; - /// - /// let mut vec = Vec::new(); - /// vec.push(Point::new(40.02f64, 116.34)); - /// vec.push(Point::new(42.02f64, 116.34)); - /// let linestring = LineString(vec); - /// - /// println!("Length {}", linestring.length()); - /// */ - /// ``` - /// - fn length(&self) -> T; -} +use traits::{PointTrait, LineStringTrait, MultiLineStringTrait}; pub fn line_string<'a, G, T>(line_string: &'a G) -> T where T: 'a + Float + ::num_traits::FromPrimitive, @@ -35,19 +12,17 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> T .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1])) } -impl Length for MultiLineString - where T: Float + ::num_traits::FromPrimitive +pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T + where T: 'a + Float + ::num_traits::FromPrimitive, + G: 'a + MultiLineStringTrait<'a, T> + ?Sized { - fn length(&self) -> T { - self.0.iter().fold(T::zero(), |total, line| total + line.length()) - } + multi_line_string.lines().fold(T::zero(), |total, line| total + line.length()) } #[cfg(test)] mod test { use types::{Coordinate, Point, LineString, MultiLineString}; - use algorithm::length::Length; - use traits::{LineStringTrait}; + use traits::{LineStringTrait, MultiLineStringTrait}; #[test] fn empty_linestring_test() { diff --git a/src/traits.rs b/src/traits.rs index 85eee1002..a68dff98b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -74,6 +74,11 @@ pub trait MultiLineStringTrait<'a, T> type Iter: Iterator; fn lines(&'a self) -> Self::Iter; + + // FIXME: decide if this should be called 'len' + fn length(&'a self) -> T { + ::algorithm::length::multi_line_string(self) + } } pub trait MultiPolygonTrait<'a, T> From 72a6d85b9a1ac0106ddf57f2bb95f0ded2bbb514 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 17:58:12 -0500 Subject: [PATCH 25/34] point to point rename --- src/algorithm/distance.rs | 2 +- src/traits.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index a368c6995..787105970 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -66,7 +66,7 @@ pub trait Distance { fn distance(&self, rhs: &Rhs) -> T; } -pub fn point<'a, G, T>(p1: &'a G, p2: &'a G) -> T +pub fn point_to_point<'a, G, T>(p1: &'a G, p2: &'a G) -> T where T: 'a + Float + FromPrimitive, G: 'a + PointTrait + ?Sized { diff --git a/src/traits.rs b/src/traits.rs index a68dff98b..e03502290 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -15,7 +15,7 @@ pub trait PointTrait { fn y(&self) -> T; fn distance_to_point(&self, other: &Self) -> T { - ::algorithm::distance::point(self, other) + ::algorithm::distance::point_to_point(self, other) } } From e20e29c95d70a7e7e4c6ff3352b442c29c942410 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 18:42:46 -0500 Subject: [PATCH 26/34] implement contains for point and linestring --- src/algorithm/centroid.rs | 2 +- src/algorithm/contains.rs | 79 ++++++++++++++++++++++----------------- src/algorithm/distance.rs | 11 +++--- src/algorithm/length.rs | 2 +- src/traits.rs | 17 ++++++++- 5 files changed, 67 insertions(+), 44 deletions(-) diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index f0582d96c..c8c44f5d3 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -20,7 +20,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> let mut sum_y = T::zero(); let mut total_length = T::zero(); for ps in vect.windows(2) { - let segment_len = ps[0].distance_to_point(&ps[1]); + let segment_len = ps[0].distance_to_point(ps[1]); let (x1, y1, x2, y2) = (ps[0].x(), ps[0].y(), ps[1].x(), ps[1].y()); total_length = total_length + segment_len; sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index d2db5d221..ce43610ae 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -1,8 +1,8 @@ -use num_traits::{Float, ToPrimitive}; +use num_traits::{Float, FromPrimitive}; use types::{COORD_PRECISION, Point, LineString, Polygon, MultiPolygon, Bbox}; use algorithm::intersects::Intersects; -use traits::PointTrait; +use traits::{PointTrait, LineStringTrait}; /// Checks if the geometry A is completely inside the B geometry. @@ -10,6 +10,7 @@ pub trait Contains { /// Checks if the geometry A is completely inside the B geometry. /// /// ``` + /// /* /// use geo::{Coordinate, Point, LineString, Polygon}; /// use geo::algorithm::contains::Contains; /// @@ -26,50 +27,57 @@ pub trait Contains { /// /// //Point in Polygon /// assert!(poly.contains(&p(1., 1.))); + /// */ /// /// ``` /// fn contains(&self, rhs: &Rhs) -> bool; } -impl Contains> for Point - where T: Float + ToPrimitive + ::num_traits::FromPrimitive +pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bool + where T: 'a + Float + FromPrimitive, + P1: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized, { - fn contains(&self, p: &Point) -> bool { - self.distance_to_point(p).to_f32().unwrap() < COORD_PRECISION - } + point1.distance_to_point(point2).to_f32().unwrap() < COORD_PRECISION } -impl Contains> for LineString - where T: Float + ::num_traits::FromPrimitive +pub fn line_string_contains_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> bool + where T: 'a + Float + FromPrimitive, + L: 'a + LineStringTrait<'a, T> + ?Sized, + P: 'a + PointTrait + ?Sized, { - fn contains(&self, p: &Point) -> bool { - let vect = &self.0; - // LineString without points - if vect.is_empty() { - return false; - } - // LineString with one point equal p - if vect.len() == 1 { - return vect[0].contains(p); - } - // check if point is a vertex - if vect.contains(p) { + // FIXME: remove collect + let vect = line_string.points().collect::>(); + + // LineString without points + if vect.is_empty() { + return false; + } + // LineString with one point equal p + if vect.len() == 1 { + return vect[0].contains_point(point); + } + // check if point is a vertex + for p in &vect { + if p.has_same_coordinates_as_point(point) { return true; } - for ps in vect.windows(2) { - if ((ps[0].y() == ps[1].y()) && (ps[0].y() == p.y()) && - (p.x() > ps[0].x().min(ps[1].x())) && - (p.x() < ps[0].x().max(ps[1].x()))) || - ((ps[0].x() == ps[1].x()) && (ps[0].x() == p.x()) && - (p.y() > ps[0].y().min(ps[1].y())) && - (p.y() < ps[0].y().max(ps[1].y()))) { - return true; - } + } + + for ps in vect.windows(2) { + if ((ps[0].y() == ps[1].y()) && (ps[0].y() == point.y()) && + (point.x() > ps[0].x().min(ps[1].x())) && + (point.x() < ps[0].x().max(ps[1].x()))) || + ((ps[0].x() == ps[1].x()) && (ps[0].x() == point.x()) && + (point.y() > ps[0].y().min(ps[1].y())) && + (point.y() < ps[0].y().max(ps[1].y()))) { + return true; } - false } + false } + #[derive(PartialEq, Clone, Debug)] enum PositionPoint { OnBoundary, @@ -91,7 +99,7 @@ fn get_position(p: &Point, linestring: &LineString) -> PositionPoint return PositionPoint::Outside; } // Point is on linestring - if linestring.contains(p) { + if linestring.contains_point(p) { return PositionPoint::OnBoundary; } @@ -166,23 +174,24 @@ impl Contains> for Bbox mod test { use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; use algorithm::contains::Contains; + use traits::LineStringTrait; /// Tests: Point in LineString #[test] fn empty_linestring_test() { let linestring = LineString(Vec::new()); - assert!(!linestring.contains(&Point::new(2., 1.))); + assert!(!linestring.contains_point(&Point::new(2., 1.))); } #[test] fn linestring_point_is_vertex_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.)]); - assert!(linestring.contains(&p(2., 2.))); + assert!(linestring.contains_point(&p(2., 2.))); } #[test] fn linestring_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.)]); - assert!(linestring.contains(&p(1., 0.))); + assert!(linestring.contains_point(&p(1., 0.))); } /// Tests: Point in Polygon #[test] diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 787105970..f40754bab 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; use num_traits::{Float, ToPrimitive, FromPrimitive}; use types::{Point, LineString, Polygon}; -use traits::PointTrait; +use traits::{PointTrait, LineStringTrait}; use algorithm::contains::Contains; use num_traits::pow::pow; @@ -66,11 +66,12 @@ pub trait Distance { fn distance(&self, rhs: &Rhs) -> T; } -pub fn point_to_point<'a, G, T>(p1: &'a G, p2: &'a G) -> T +pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T where T: 'a + Float + FromPrimitive, - G: 'a + PointTrait + ?Sized + P1: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized, { - let (dx, dy) = (p1.x() - p2.x(), p1.y() - p2.y()); + let (dx, dy) = (point1.x() - point2.x(), point1.y() - point2.y()); dx.hypot(dy) } @@ -159,7 +160,7 @@ impl Distance> for Point { fn distance(&self, linestring: &LineString) -> T { // No need to continue if the point is on the LineString, or it's empty - if linestring.contains(self) || linestring.0.len() == 0 { + if linestring.contains_point(self) || linestring.0.len() == 0 { return T::zero(); } // minimum priority queue diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index c58b0f722..a1266e5b5 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -9,7 +9,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> T // FIXME: don't collect let v = line_string.points().collect::>(); v.windows(2) - .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1])) + .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(p[1])) } pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T diff --git a/src/traits.rs b/src/traits.rs index e03502290..a5e36210e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -10,13 +10,22 @@ pub trait ToGeo // FIXME: find good names for these traits, don't use XyzTrait naming scheme // FIXME: remove FromPrimitive trait -pub trait PointTrait { +pub trait PointTrait: Sized { fn x(&self) -> T; fn y(&self) -> T; - fn distance_to_point(&self, other: &Self) -> T { + // TODO: keep this? + fn has_same_coordinates_as_point>(&self, other: &P) -> bool { + self.x() == other.x() && self.y() == other.y() + } + + fn distance_to_point>(&self, other: &P) -> T { ::algorithm::distance::point_to_point(self, other) } + + fn contains_point>(&self, other: &P) -> bool { + ::algorithm::contains::point_contains_point(self, other) + } } pub trait LineStringTrait<'a, T> @@ -37,6 +46,10 @@ pub trait LineStringTrait<'a, T> fn centroid(&'a self) -> Option<::Point> { ::algorithm::centroid::line_string(self) } + + fn contains_point>(&'a self, other: &'a P) -> bool { + ::algorithm::contains::line_string_contains_point(self, other) + } } pub trait PolygonTrait<'a, T> From 6efd5df7e209fa77c0b645ff38b123dccfc3f53d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 22 Jan 2017 18:44:42 -0500 Subject: [PATCH 27/34] rename method --- src/algorithm/contains.rs | 2 +- src/traits.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index ce43610ae..7e1094e38 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -60,7 +60,7 @@ pub fn line_string_contains_point<'a, L, P, T>(line_string: &'a L, point: &'a P) } // check if point is a vertex for p in &vect { - if p.has_same_coordinates_as_point(point) { + if p.eq_coordinates(point) { return true; } } diff --git a/src/traits.rs b/src/traits.rs index a5e36210e..311f829ba 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -15,7 +15,7 @@ pub trait PointTrait: Sized { fn y(&self) -> T; // TODO: keep this? - fn has_same_coordinates_as_point>(&self, other: &P) -> bool { + fn eq_coordinates>(&self, other: &P) -> bool { self.x() == other.x() && self.y() == other.y() } From ed2b205a1f825afbe57276d1545c3206342c80c9 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 24 Jan 2017 23:04:35 -0500 Subject: [PATCH 28/34] impl contains and intersects --- src/algorithm/contains.rs | 148 +++++++++++++++++++----------------- src/algorithm/distance.rs | 5 +- src/algorithm/intersects.rs | 131 ++++++++++++++++--------------- src/traits.rs | 20 +++++ src/types.rs | 19 +++++ 5 files changed, 190 insertions(+), 133 deletions(-) diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 7e1094e38..c50890dc3 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -1,12 +1,11 @@ use num_traits::{Float, FromPrimitive}; -use types::{COORD_PRECISION, Point, LineString, Polygon, MultiPolygon, Bbox}; -use algorithm::intersects::Intersects; -use traits::{PointTrait, LineStringTrait}; +use types::COORD_PRECISION; +use traits::{PointTrait, LineStringTrait, PolygonTrait, MultiPolygonTrait}; /// Checks if the geometry A is completely inside the B geometry. -pub trait Contains { +trait Contains { /// Checks if the geometry A is completely inside the B geometry. /// /// ``` @@ -85,35 +84,39 @@ enum PositionPoint { Outside, } -fn get_position(p: &Point, linestring: &LineString) -> PositionPoint - where T: Float + ::num_traits::FromPrimitive +fn get_position<'a, P, L, T>(point: &'a P, line_string: &'a L) -> PositionPoint + where T: 'a + Float + FromPrimitive, + P: 'a + PointTrait + ?Sized, + L: 'a + LineStringTrait<'a, T> + ?Sized, { // See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // http://geospatialpython.com/search // ?updated-min=2011-01-01T00:00:00-06:00&updated-max=2012-01-01T00:00:00-06:00&max-results=19 // Return the position of the point relative to a linestring - let vect = &linestring.0; + // TODO: remove `collect` call here + let vect = line_string.points().collect::>(); + // LineString without points if vect.is_empty() { return PositionPoint::Outside; } // Point is on linestring - if linestring.contains_point(p) { + if line_string.contains_point(point) { return PositionPoint::OnBoundary; } let mut xints = T::zero(); let mut crossings = 0; for ps in vect.windows(2) { - if p.y() > ps[0].y().min(ps[1].y()) { - if p.y() <= ps[0].y().max(ps[1].y()) { - if p.x() <= ps[0].x().max(ps[1].x()) { + if point.y() > ps[0].y().min(ps[1].y()) { + if point.y() <= ps[0].y().max(ps[1].y()) { + if point.x() <= ps[0].x().max(ps[1].x()) { if ps[0].y() != ps[1].y() { - xints = (p.y() - ps[0].y()) * (ps[1].x() - ps[0].x()) / + xints = (point.y() - ps[0].y()) * (ps[1].x() - ps[0].x()) / (ps[1].y() - ps[0].y()) + ps[0].x(); } - if (ps[0].x() == ps[1].x()) || (p.x() <= xints) { + if (ps[0].x() == ps[1].x()) || (point.x() <= xints) { crossings += 1; } } @@ -127,39 +130,42 @@ fn get_position(p: &Point, linestring: &LineString) -> PositionPoint } } -impl Contains> for Polygon - where T: Float + ::num_traits::FromPrimitive +pub fn polygon_contains_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> bool + where T: 'a + Float + FromPrimitive, + P1: 'a + PolygonTrait<'a, T> + ?Sized, + P2: 'a + PointTrait + ?Sized, { - fn contains(&self, p: &Point) -> bool { - match get_position(p, &self.exterior) { - PositionPoint::OnBoundary => false, - PositionPoint::Outside => false, - _ => self.interiors.iter().all(|ls| get_position(p, ls) == PositionPoint::Outside), - } + let mut rings = polygon.rings(); + let exterior_ring = rings.next().expect("expected outer ring"); + match get_position(point, exterior_ring) { + PositionPoint::OnBoundary => false, + PositionPoint::Outside => false, + _ => rings.all(|ls| get_position(point, ls) == PositionPoint::Outside), } } -impl Contains> for MultiPolygon - where T: Float + ::num_traits::FromPrimitive +pub fn multi_polygon_contains_point<'a, M, P, T>(multi_polygon: &'a M, point: &'a P) -> bool + where T: 'a + Float + ::num_traits::FromPrimitive, + M: 'a + MultiPolygonTrait<'a, T> + ?Sized, + P: 'a + PointTrait + ?Sized, { - fn contains(&self, p: &Point) -> bool { - self.0.iter().any(|poly| poly.contains(p)) - } + multi_polygon.polygons().any(|poly| poly.contains_point(point)) } -impl Contains> for Polygon - where T: Float + ::num_traits::FromPrimitive +pub fn polygon_contains_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool + where T: 'a + Float + ::num_traits::FromPrimitive, + P: 'a + PolygonTrait<'a, T> + ?Sized, + L: 'a + LineStringTrait<'a, T> + Sized, { - fn contains(&self, linestring: &LineString) -> bool { - // All points of LineString must be in the polygon ? - if linestring.0.iter().all(|point| self.contains(point)) { - !self.intersects(linestring) - } else { - false - } + // All points of LineString must be in the polygon ? + if line_string.points().all(|point| polygon.contains_point(point)) { + !polygon.intersects_line_string(line_string) + } else { + false } } +/* impl Contains> for Bbox where T: Float + ::num_traits::FromPrimitive { @@ -168,13 +174,13 @@ impl Contains> for Bbox self.xmin <= bbox.xmin && self.xmax >= bbox.xmax && self.ymin <= bbox.ymin && self.ymax >= bbox.ymax } } +*/ #[cfg(test)] mod test { - use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox}; - use algorithm::contains::Contains; - use traits::LineStringTrait; + use types::{Coordinate, Point, LineString, Polygon, MultiPolygon}; + use traits::{LineStringTrait, PolygonTrait, MultiPolygonTrait}; /// Tests: Point in LineString #[test] fn empty_linestring_test() { @@ -198,45 +204,45 @@ mod test { fn empty_polygon_test() { let linestring = LineString(Vec::new()); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&Point::new(2., 1.))); + assert!(!poly.contains_point(&Point::new(2., 1.))); } #[test] fn polygon_with_one_point_test() { let linestring = LineString(vec![Point::new(2., 1.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&Point::new(3., 1.))); + assert!(!poly.contains_point(&Point::new(3., 1.))); } #[test] fn polygon_with_one_point_is_vertex_test() { let linestring = LineString(vec![Point::new(2., 1.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&Point::new(2., 1.))); + assert!(!poly.contains_point(&Point::new(2., 1.))); } #[test] fn polygon_with_point_on_boundary_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&p(1., 0.))); - assert!(!poly.contains(&p(2., 1.))); - assert!(!poly.contains(&p(1., 2.))); - assert!(!poly.contains(&p(0., 1.))); + assert!(!poly.contains_point(&p(1., 0.))); + assert!(!poly.contains_point(&p(2., 1.))); + assert!(!poly.contains_point(&p(1., 2.))); + assert!(!poly.contains_point(&p(0., 1.))); } #[test] fn point_in_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(poly.contains(&p(1., 1.))); + assert!(poly.contains_point(&p(1., 1.))); } #[test] fn point_out_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&p(2.1, 1.))); - assert!(!poly.contains(&p(1., 2.1))); - assert!(!poly.contains(&p(2.1, 2.1))); + assert!(!poly.contains_point(&p(2.1, 1.))); + assert!(!poly.contains_point(&p(1., 2.1))); + assert!(!poly.contains_point(&p(2.1, 2.1))); } #[test] fn point_polygon_with_inner_test() { @@ -248,16 +254,16 @@ mod test { p(0.0, 1.5), p(0.0, 0.0)]); let poly = Polygon::new(linestring, vec![inner_linestring]); - assert!(poly.contains(&p(0.25, 0.25))); - assert!(!poly.contains(&p(1., 1.))); - assert!(!poly.contains(&p(1.5, 1.5))); - assert!(!poly.contains(&p(1.5, 1.))); + assert!(poly.contains_point(&p(0.25, 0.25))); + assert!(!poly.contains_point(&p(1., 1.))); + assert!(!poly.contains_point(&p(1.5, 1.5))); + assert!(!poly.contains_point(&p(1.5, 1.))); } /// Tests: Point in MultiPolygon #[test] fn empty_multipolygon_test() { let multipoly = MultiPolygon(Vec::new()); - assert!(!multipoly.contains(&Point::new(2., 1.))); + assert!(!multipoly.contains_point(&Point::new(2., 1.))); } #[test] fn empty_multipolygon_two_polygons_test() { @@ -267,9 +273,9 @@ mod test { let poly2 = Polygon::new(LineString(vec![p(2., 0.), p(3., 0.), p(3., 1.), p(2., 1.), p(2., 0.)]), Vec::new()); let multipoly = MultiPolygon(vec![poly1, poly2]); - assert!(multipoly.contains(&Point::new(0.5, 0.5))); - assert!(multipoly.contains(&Point::new(2.5, 0.5))); - assert!(!multipoly.contains(&Point::new(1.5, 0.5))); + assert!(multipoly.contains_point(&Point::new(0.5, 0.5))); + assert!(multipoly.contains_point(&Point::new(2.5, 0.5))); + assert!(!multipoly.contains_point(&Point::new(1.5, 0.5))); } #[test] fn empty_multipolygon_two_polygons_and_inner_test() { @@ -280,10 +286,10 @@ mod test { Vec::new()); let multipoly = MultiPolygon(vec![poly1, poly2]); - assert!(multipoly.contains(&Point::new(3., 5.))); - assert!(multipoly.contains(&Point::new(12., 2.))); - assert!(!multipoly.contains(&Point::new(3., 2.))); - assert!(!multipoly.contains(&Point::new(7., 2.))); + assert!(multipoly.contains_point(&Point::new(3., 5.))); + assert!(multipoly.contains_point(&Point::new(12., 2.))); + assert!(!multipoly.contains_point(&Point::new(3., 2.))); + assert!(!multipoly.contains_point(&Point::new(7., 2.))); } /// Tests: LineString in Polygon #[test] @@ -291,18 +297,18 @@ mod test { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); let poly = Polygon::new(linestring.clone(), Vec::new()); - assert!(!poly.contains(&linestring.clone())); - assert!(!poly.contains(&LineString(vec![p(0., 0.), p(2., 0.)]))); - assert!(!poly.contains(&LineString(vec![p(2., 0.), p(2., 2.)]))); - assert!(!poly.contains(&LineString(vec![p(0., 2.), p(0., 0.)]))); + assert!(!poly.contains_line_string(&linestring.clone())); + assert!(!poly.contains_line_string(&LineString(vec![p(0., 0.), p(2., 0.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(2., 0.), p(2., 2.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(0., 2.), p(0., 0.)]))); } #[test] fn linestring_outside_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(!poly.contains(&LineString(vec![p(1., 1.), p(3., 0.)]))); - assert!(!poly.contains(&LineString(vec![p(3., 0.), p(5., 2.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(1., 1.), p(3., 0.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(3., 0.), p(5., 2.)]))); } #[test] fn linestring_in_inner_polygon_test() { @@ -310,10 +316,11 @@ mod test { let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])]); - assert!(!poly.contains(&LineString(vec![p(2., 2.), p(3., 3.)]))); - assert!(!poly.contains(&LineString(vec![p(2., 2.), p(2., 5.)]))); - assert!(!poly.contains(&LineString(vec![p(3., 0.5), p(3., 5.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(2., 2.), p(3., 3.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(2., 2.), p(2., 5.)]))); + assert!(!poly.contains_line_string(&LineString(vec![p(3., 0.5), p(3., 5.)]))); } + /* #[test] fn bbox_in_inner_bbox_test() { let bbox_xl = Bbox { xmin: -100., xmax: 100., ymin: -200., ymax: 200.}; @@ -321,4 +328,5 @@ mod test { assert_eq!(true, bbox_xl.contains(&bbox_sm)); assert_eq!(false, bbox_sm.contains(&bbox_xl)); } + */ } diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index f40754bab..fa8f45c64 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -2,8 +2,7 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; use num_traits::{Float, ToPrimitive, FromPrimitive}; use types::{Point, LineString, Polygon}; -use traits::{PointTrait, LineStringTrait}; -use algorithm::contains::Contains; +use traits::{PointTrait, LineStringTrait, PolygonTrait}; use num_traits::pow::pow; /// Returns the distance between two geometries. @@ -137,7 +136,7 @@ impl Distance> for Point // exterior ring as a LineString let ext_ring = &exterior.0; // No need to continue if the polygon contains the point, or is zero-length - if polygon.contains(self) || ext_ring.is_empty() { + if polygon.contains_point(self) || ext_ring.is_empty() { return T::zero(); } // minimum priority queue diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index 18a7eafd6..f9bada933 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -1,6 +1,6 @@ use num_traits::Float; use types::{LineString, Polygon, Bbox, Point}; -use algorithm::contains::Contains; +use traits::{LineStringTrait, PolygonTrait, PointTrait}; /// Checks if the geometry A intersects the geometry B. @@ -8,6 +8,7 @@ pub trait Intersects { /// Checks if the geometry A intersects the geometry B. /// /// ``` + /// /* /// use geo::{Coordinate, Point, LineString}; /// use geo::algorithm::intersects::Intersects; /// @@ -16,64 +17,70 @@ pub trait Intersects { /// /// assert!(linestring.intersects(&LineString(vec![p(3., 4.), p(8., 4.)]))); /// assert!(!linestring.intersects(&LineString(vec![p(9., 2.), p(11., 5.)]))); + /// */ /// /// ``` /// fn intersects(&self, rhs: &Rhs) -> bool; } -impl Intersects> for LineString - where T: Float + ::num_traits::FromPrimitive +pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, line_string2: &'a L2) -> bool + where T: 'a + Float + ::num_traits::FromPrimitive, + L1: 'a + LineStringTrait<'a, T> + ?Sized, + L2: 'a + LineStringTrait<'a, T> + ?Sized, { // See: https://github.com/brandonxiang/geojson-python-utils/blob/33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py - fn intersects(&self, linestring: &LineString) -> bool { - let vect0 = &self.0; - let vect1 = &linestring.0; - if vect0.is_empty() || vect1.is_empty() { - return false; - } - for a in vect0.windows(2) { - for b in vect1.windows(2) { - let u_b = (b[1].y() - b[0].y()) * (a[1].x() - a[0].x()) - - (b[1].x() - b[0].x()) * (a[1].y() - a[0].y()); - if u_b == T::zero() { - continue; - } - let ua_t = (b[1].x() - b[0].x()) * (a[0].y() - b[0].y()) - - (b[1].y() - b[0].y()) * (a[0].x() - b[0].x()); - let ub_t = (a[1].x() - a[0].x()) * (a[0].y() - b[0].y()) - - (a[1].y() - a[0].y()) * (a[0].x() - b[0].x()); - let u_a = ua_t / u_b; - let u_b = ub_t / u_b; - if (T::zero() <= u_a) && (u_a <= T::one()) && (T::zero() <= u_b) && (u_b <= T::one()) { - return true; - } + // TODO: remove `collect` + let vect0 = line_string1.points().collect::>(); + let vect1 = line_string2.points().collect::>(); + if vect0.is_empty() || vect1.is_empty() { + return false; + } + for a in vect0.windows(2) { + for b in vect1.windows(2) { + let u_b = (b[1].y() - b[0].y()) * (a[1].x() - a[0].x()) - + (b[1].x() - b[0].x()) * (a[1].y() - a[0].y()); + if u_b == T::zero() { + continue; + } + let ua_t = (b[1].x() - b[0].x()) * (a[0].y() - b[0].y()) - + (b[1].y() - b[0].y()) * (a[0].x() - b[0].x()); + let ub_t = (a[1].x() - a[0].x()) * (a[0].y() - b[0].y()) - + (a[1].y() - a[0].y()) * (a[0].x() - b[0].x()); + let u_a = ua_t / u_b; + let u_b = ub_t / u_b; + if (T::zero() <= u_a) && (u_a <= T::one()) && (T::zero() <= u_b) && (u_b <= T::one()) { + return true; } } - false } + false } -impl Intersects> for Polygon - where T: Float + ::num_traits::FromPrimitive +pub fn polygon_intersects_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool + where T: 'a + Float + ::num_traits::FromPrimitive, + P: 'a + PolygonTrait<'a, T> + ?Sized, + L: 'a + LineStringTrait<'a, T> + Sized, { - fn intersects(&self, linestring: &LineString) -> bool { - // line intersects inner or outer polygon edge - if self.exterior.intersects(linestring) || self.interiors.iter().any(|inner| inner.intersects(linestring)) { - return true; - } else { - // or if it's contained in the polygon - return linestring.0.iter().any(|point| self.contains(point)) - } + let mut rings = polygon.rings(); + let exterior_ring = rings.next().expect("no outer ring"); + + // line intersects inner or outer polygon edge + if exterior_ring.intersects_line_string(line_string) || rings.any(|inner| inner.intersects_line_string(line_string)) { + return true; + } else { + // or if it's contained in the polygon + return line_string.points().any(|point| polygon.contains_point(point)) } } +/* impl Intersects> for Bbox where T: Float + ::num_traits::FromPrimitive { fn intersects(&self, bbox: &Bbox) -> bool { // line intersects inner or outer polygon edge - if bbox.contains(&self) { + if bbox.contains_point(&self) { return false } else { (self.xmin >= bbox.xmin && self.xmin <= bbox.xmax || self.xmax >= bbox.xmin && self.xmax <= bbox.xmax) && @@ -81,6 +88,7 @@ impl Intersects> for Bbox } } } +*/ impl Intersects> for Bbox where T: Float + ::num_traits::FromPrimitive @@ -109,45 +117,46 @@ impl Intersects> for Polygon { fn intersects(&self, polygon: &Polygon) -> bool { // self intersects (or contains) any line in polygon - self.intersects(&polygon.exterior) || - polygon.interiors.iter().any(|inner_line_string| self.intersects(inner_line_string)) || + self.intersects_line_string(&polygon.exterior) || + polygon.interiors.iter().any(|inner_line_string| self.intersects_line_string(inner_line_string)) || // self is contained inside polygon - polygon.intersects(&self.exterior) + polygon.intersects_line_string(&self.exterior) } } #[cfg(test)] mod test { - use types::{Coordinate, Point, LineString, Polygon, Bbox}; + use types::{Coordinate, Point, LineString, Polygon}; use algorithm::intersects::Intersects; + use traits::{PolygonTrait, LineStringTrait}; /// Tests: intersection LineString and LineString #[test] fn empty_linestring1_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(3., 2.), p(7., 6.)]); - assert!(!LineString(Vec::new()).intersects(&linestring)); + assert!(!LineString(Vec::new()).intersects_line_string(&linestring)); } #[test] fn empty_linestring2_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(3., 2.), p(7., 6.)]); - assert!(!linestring.intersects(&LineString(Vec::new()))); + assert!(!linestring.intersects_line_string(&LineString(Vec::new()))); } #[test] fn empty_all_linestring_test() { - assert!(!LineString::(Vec::new()).intersects(&LineString(Vec::new()))); + assert!(!LineString::(Vec::new()).intersects_line_string(&LineString(Vec::new()))); } #[test] fn intersect_linestring_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(3., 2.), p(7., 6.)]); - assert!(linestring.intersects(&LineString(vec![p(3., 4.), p(8., 4.)]))); + assert!(linestring.intersects_line_string(&LineString(vec![p(3., 4.), p(8., 4.)]))); } #[test] fn parallel_linestrings_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(3., 2.), p(7., 6.)]); - assert!(!linestring.intersects(&LineString(vec![p(3., 1.), p(7., 5.)]))); + assert!(!linestring.intersects_line_string(&LineString(vec![p(3., 1.), p(7., 5.)]))); } /// Tests: intersection LineString and Polygon #[test] @@ -155,31 +164,31 @@ mod test { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]); let poly = Polygon::new(linestring, Vec::new()); - assert!(poly.intersects(&LineString(vec![p(2., 2.), p(3., 3.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(2., 2.), p(3., 3.)]))); } #[test] fn linestring_on_boundary_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), Vec::new()); - assert!(poly.intersects(&LineString(vec![p(0., 0.), p(5., 0.)]))); - assert!(poly.intersects(&LineString(vec![p(5., 0.), p(5., 6.)]))); - assert!(poly.intersects(&LineString(vec![p(5., 6.), p(0., 6.)]))); - assert!(poly.intersects(&LineString(vec![p(0., 6.), p(0., 0.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(0., 0.), p(5., 0.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(5., 0.), p(5., 6.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(5., 6.), p(0., 6.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(0., 6.), p(0., 0.)]))); } #[test] fn intersect_linestring_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), Vec::new()); - assert!(poly.intersects(&LineString(vec![p(2., 2.), p(6., 6.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(2., 2.), p(6., 6.)]))); } #[test] fn linestring_outside_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), Vec::new()); - assert!(!poly.intersects(&LineString(vec![p(7., 2.), p(9., 4.)]))); + assert!(!poly.intersects_line_string(&LineString(vec![p(7., 2.), p(9., 4.)]))); } #[test] fn linestring_in_inner_polygon_test() { @@ -187,8 +196,8 @@ mod test { let e = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]); let v = vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])]; let poly = Polygon::new(e, v); - assert!(!poly.intersects(&LineString(vec![p(2., 2.), p(3., 3.)]))); - assert!(poly.intersects(&LineString(vec![p(2., 2.), p(4., 4.)]))); + assert!(!poly.intersects_line_string(&LineString(vec![p(2., 2.), p(3., 3.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(2., 2.), p(4., 4.)]))); } #[test] fn linestring_traverse_polygon_test() { @@ -196,7 +205,7 @@ mod test { let e = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]); let v = vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])]; let poly = Polygon::new(e, v); - assert!(poly.intersects(&LineString(vec![p(2., 0.5), p(2., 5.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(2., 0.5), p(2., 5.)]))); } #[test] fn linestring_in_inner_with_2_inner_polygon_test() { @@ -229,10 +238,10 @@ mod test { let v = vec![LineString(vec![p(4., 3.), p(7., 3.), p(7., 6.), p(4., 6.), p(4., 3.)]), LineString(vec![p(9., 3.), p(12., 3.), p(12., 6.), p(9., 6.), p(9., 3.)])]; let poly = Polygon::new(e, v); - assert!(!poly.intersects(&LineString(vec![p(5., 4.), p(6., 5.)]))); - assert!(poly.intersects(&LineString(vec![p(11., 2.5), p(11., 7.)]))); - assert!(poly.intersects(&LineString(vec![p(4., 7.), p(6., 7.)]))); - assert!(poly.intersects(&LineString(vec![p(8., 1.), p(8., 9.)]))); + assert!(!poly.intersects_line_string(&LineString(vec![p(5., 4.), p(6., 5.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(11., 2.5), p(11., 7.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(4., 7.), p(6., 7.)]))); + assert!(poly.intersects_line_string(&LineString(vec![p(8., 1.), p(8., 9.)]))); } #[test] fn polygons_do_not_intersect() { @@ -278,6 +287,7 @@ mod test { assert!(p1.intersects(&p2)); assert!(p2.intersects(&p1)); } + /* #[test] fn polygon_intersects_bbox_test() { // Polygon poly = @@ -330,4 +340,5 @@ mod test { assert_eq!(true, bbox_sm.intersects(&bbox_s2)); assert_eq!(true, bbox_s2.intersects(&bbox_sm)); } + */ } diff --git a/src/traits.rs b/src/traits.rs index 311f829ba..e8f754362 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -50,6 +50,10 @@ pub trait LineStringTrait<'a, T> fn contains_point>(&'a self, other: &'a P) -> bool { ::algorithm::contains::line_string_contains_point(self, other) } + + fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { + ::algorithm::intersects::line_string_intersects_line_string(self, line_string) + } } pub trait PolygonTrait<'a, T> @@ -69,6 +73,18 @@ pub trait PolygonTrait<'a, T> fn centroid(&'a self) -> Option<::Point> { ::algorithm::centroid::polygon(self) } + + fn contains_point>(&'a self, point: &'a P) -> bool { + ::algorithm::contains::polygon_contains_point(self, point) + } + + fn contains_line_string>(&'a self, line_string: &'a L) -> bool { + ::algorithm::contains::polygon_contains_line_string(self, line_string) + } + + fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { + ::algorithm::intersects::polygon_intersects_line_string(self, line_string) + } } pub trait MultiPointTrait<'a, T> @@ -109,4 +125,8 @@ pub trait MultiPolygonTrait<'a, T> fn centroid(&'a self) -> Option<::Point> { ::algorithm::centroid::multi_polygon(self) } + + fn contains_point>(&'a self, point: &'a P) -> bool { + ::algorithm::contains::multi_polygon_contains_point(self, point) + } } diff --git a/src/types.rs b/src/types.rs index 447f3e649..ea5dfa620 100644 --- a/src/types.rs +++ b/src/types.rs @@ -26,6 +26,25 @@ pub struct Bbox pub ymax: T, } +// TODO: complete this: +/* +impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Bbox { + type ItemType = LineString; + type Iter = Box + 'a>; + + fn rings(&'a self) -> Self::Iter { + let line_string = ::LineString(vec![ + Point(Coordinate { x: self.xmin, y: self.ymax }), + Point(Coordinate { x: self.xmax, y: self.ymax }), + Point(Coordinate { x: self.xmax, y: self.ymin }), + Point(Coordinate { x: self.xmin, y: self.ymin }), + ]); + let iter = ::std::iter::once(line_string); + Box::new(iter) + } +} +*/ + #[derive(PartialEq, Clone, Copy, Debug)] pub struct Point (pub Coordinate) where T: Float + FromPrimitive; From d042777d6db96f45a11fcdbe0e13f46530b283ea Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 25 Jan 2017 08:00:15 -0500 Subject: [PATCH 29/34] polygon intersect polygon impl --- src/algorithm/intersects.rs | 66 ++++++++++++++----------------------- src/traits.rs | 4 +++ 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index f9bada933..e7c9ed122 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -1,29 +1,6 @@ use num_traits::Float; -use types::{LineString, Polygon, Bbox, Point}; use traits::{LineStringTrait, PolygonTrait, PointTrait}; -/// Checks if the geometry A intersects the geometry B. - -pub trait Intersects { - /// Checks if the geometry A intersects the geometry B. - /// - /// ``` - /// /* - /// use geo::{Coordinate, Point, LineString}; - /// use geo::algorithm::intersects::Intersects; - /// - /// let p = |x, y| Point(Coordinate { x: x, y: y }); - /// let linestring = LineString(vec![p(3., 2.), p(7., 6.)]); - /// - /// assert!(linestring.intersects(&LineString(vec![p(3., 4.), p(8., 4.)]))); - /// assert!(!linestring.intersects(&LineString(vec![p(9., 2.), p(11., 5.)]))); - /// */ - /// - /// ``` - /// - fn intersects(&self, rhs: &Rhs) -> bool; -} - pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, line_string2: &'a L2) -> bool where T: 'a + Float + ::num_traits::FromPrimitive, L1: 'a + LineStringTrait<'a, T> + ?Sized, @@ -88,7 +65,6 @@ impl Intersects> for Bbox } } } -*/ impl Intersects> for Bbox where T: Float + ::num_traits::FromPrimitive @@ -111,23 +87,29 @@ impl Intersects> for Polygon self.intersects(&p) } } +*/ -impl Intersects> for Polygon - where T: Float + ::num_traits::FromPrimitive +pub fn polygon_intersects_polygon<'a, P1, P2, T>(polygon1: &'a P1, polygon2: &'a P2) -> bool + where T: 'a + Float + ::num_traits::FromPrimitive, + P1: 'a + PolygonTrait<'a, T> + ?Sized, + P2: 'a + PolygonTrait<'a, T> + ?Sized, { - fn intersects(&self, polygon: &Polygon) -> bool { - // self intersects (or contains) any line in polygon - self.intersects_line_string(&polygon.exterior) || - polygon.interiors.iter().any(|inner_line_string| self.intersects_line_string(inner_line_string)) || - // self is contained inside polygon - polygon.intersects_line_string(&self.exterior) - } + let mut polygon1_rings = polygon1.rings(); + let polygon1_exterior_ring = polygon1_rings.next().expect("no outer ring"); + + let mut polygon2_rings = polygon2.rings(); + let polygon2_exterior_ring = polygon2_rings.next().expect("no outer ring"); + + // self intersects (or contains) any line in polygon + polygon1.intersects_line_string(polygon2_exterior_ring) || + polygon2_rings.any(|inner_line_string| polygon1.intersects_line_string(inner_line_string)) || + // self is contained inside polygon + polygon2.intersects_line_string(polygon1_exterior_ring) } #[cfg(test)] mod test { use types::{Coordinate, Point, LineString, Polygon}; - use algorithm::intersects::Intersects; use traits::{PolygonTrait, LineStringTrait}; /// Tests: intersection LineString and LineString #[test] @@ -251,8 +233,8 @@ mod test { let p2 = Polygon::new(LineString(vec![p(10., 30.), p(30., 30.), p(30., 50.), p(10., 50.), p(10., 30.)]), Vec::new()); - assert!(!p1.intersects(&p2)); - assert!(!p2.intersects(&p1)); + assert!(!p1.intersects_polygon(&p2)); + assert!(!p2.intersects_polygon(&p1)); } #[test] fn polygons_overlap() { @@ -262,8 +244,8 @@ mod test { let p2 = Polygon::new(LineString(vec![p(2., 3.), p(4., 3.), p(4., 7.), p(2., 7.), p(2., 3.)]), Vec::new()); - assert!(p1.intersects(&p2)); - assert!(p2.intersects(&p1)); + assert!(p1.intersects_polygon(&p2)); + assert!(p2.intersects_polygon(&p1)); } #[test] fn polygon_contained() { @@ -273,8 +255,8 @@ mod test { let p2 = Polygon::new(LineString(vec![p(2., 4.), p(3., 4.), p(3., 5.), p(2., 5.), p(2., 4.)]), Vec::new()); - assert!(p1.intersects(&p2)); - assert!(p2.intersects(&p1)); + assert!(p1.intersects_polygon(&p2)); + assert!(p2.intersects_polygon(&p1)); } #[test] fn polygons_conincident() { @@ -284,8 +266,8 @@ mod test { let p2 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]), Vec::new()); - assert!(p1.intersects(&p2)); - assert!(p2.intersects(&p1)); + assert!(p1.intersects_polygon(&p2)); + assert!(p2.intersects_polygon(&p1)); } /* #[test] diff --git a/src/traits.rs b/src/traits.rs index e8f754362..a23ec0a72 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -85,6 +85,10 @@ pub trait PolygonTrait<'a, T> fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { ::algorithm::intersects::polygon_intersects_line_string(self, line_string) } + + fn intersects_polygon>(&'a self, polygon: &'a P) -> bool { + ::algorithm::intersects::polygon_intersects_polygon(self, polygon) + } } pub trait MultiPointTrait<'a, T> From 39a7db84787f08f3e04cbaf08910465f7ae3d618 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 25 Jan 2017 08:04:33 -0500 Subject: [PATCH 30/34] remove contains trait --- src/algorithm/contains.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index c50890dc3..4120a32e0 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -3,36 +3,6 @@ use num_traits::{Float, FromPrimitive}; use types::COORD_PRECISION; use traits::{PointTrait, LineStringTrait, PolygonTrait, MultiPolygonTrait}; -/// Checks if the geometry A is completely inside the B geometry. - -trait Contains { - /// Checks if the geometry A is completely inside the B geometry. - /// - /// ``` - /// /* - /// use geo::{Coordinate, Point, LineString, Polygon}; - /// use geo::algorithm::contains::Contains; - /// - /// let p = |x, y| Point(Coordinate { x: x, y: y }); - /// let v = Vec::new(); - /// let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); - /// let poly = Polygon::new(linestring.clone(), v); - /// - /// //Point in Point - /// assert!(p(2., 0.).contains(&p(2., 0.))); - /// - /// //Point in Linestring - /// assert!(linestring.contains(&p(2., 0.))); - /// - /// //Point in Polygon - /// assert!(poly.contains(&p(1., 1.))); - /// */ - /// - /// ``` - /// - fn contains(&self, rhs: &Rhs) -> bool; -} - pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bool where T: 'a + Float + FromPrimitive, P1: 'a + PointTrait + ?Sized, From 8f86aa73b4490308312b1afa682cb16017abdf7f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 25 Jan 2017 08:13:05 -0500 Subject: [PATCH 31/34] add reverse impl --- src/traits.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/traits.rs b/src/traits.rs index a23ec0a72..a0b87e52e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -54,6 +54,10 @@ pub trait LineStringTrait<'a, T> fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { ::algorithm::intersects::line_string_intersects_line_string(self, line_string) } + + fn intersects_polygon>(&'a self, polygon: &'a P) -> bool { + ::algorithm::intersects::polygon_intersects_line_string(polygon, self) + } } pub trait PolygonTrait<'a, T> From c78b494324c002a728e16b4f00ae0fe9c31dc810 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 26 Jan 2017 21:26:04 -0500 Subject: [PATCH 32/34] impl distance things --- src/algorithm/distance.rs | 172 +++++++++++++----------------------- src/algorithm/intersects.rs | 2 +- src/traits.rs | 32 ++++++- 3 files changed, 91 insertions(+), 115 deletions(-) diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index fa8f45c64..83d762519 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -1,70 +1,10 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; -use num_traits::{Float, ToPrimitive, FromPrimitive}; -use types::{Point, LineString, Polygon}; +use num_traits::{Float, FromPrimitive}; +use types::Point; use traits::{PointTrait, LineStringTrait, PolygonTrait}; use num_traits::pow::pow; -/// Returns the distance between two geometries. - -pub trait Distance { - /// Returns the distance between two geometries - /// - /// If a `Point` is contained by a `Polygon`, the distance is `0.0` - /// If a `Point` lies on a `Polygon`'s exterior or interior rings, the distance is `0.0` - /// If a `Point` lies on a `LineString`, the distance is `0.0` - /// The distance between a `Point` and an empty `LineString` is `0.0` - /// - /// ``` - /// /* - /// use geo::{COORD_PRECISION, Point, LineString, Polygon}; - /// use geo::algorithm::distance::Distance; - /// - /// // Point to Point example - /// let p = Point::new(-72.1235, 42.3521); - /// let dist = p.distance(&Point::new(-72.1260, 42.45)); - /// assert!(dist < COORD_PRECISION); - /// - /// // Point to Polygon example - /// let points = vec![ - /// (5., 1.), - /// (4., 2.), - /// (4., 3.), - /// (5., 4.), - /// (6., 4.), - /// (7., 3.), - /// (7., 2.), - /// (6., 1.), - /// (5., 1.) - /// ]; - /// let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); - /// let poly = Polygon::new(ls, vec![]); - /// // A Random point outside the polygon - /// let p = Point::new(2.5, 0.5); - /// let dist = p.distance(&poly); - /// assert_eq!(dist, 2.1213203435596424); - /// - /// // Point to LineString example - /// let points = vec![ - /// (5., 1.), - /// (4., 2.), - /// (4., 3.), - /// (5., 4.), - /// (6., 4.), - /// (7., 3.), - /// (7., 2.), - /// (6., 1.), - /// ]; - /// let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); - /// // A Random point outside the LineString - /// let p = Point::new(5.5, 2.1); - /// let dist = p.distance(&ls); - /// assert_eq!(dist, 1.1313708498984758); - /// */ - /// ``` - fn distance(&self, rhs: &Rhs) -> T; -} - pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T where T: 'a + Float + FromPrimitive, P1: 'a + PointTrait + ?Sized, @@ -85,8 +25,11 @@ pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T // then it's halfway between. If t is less than 0 or greater than 1, it // falls on the line past one end or the other of the segment. In that case the // distance to the segment will be the distance to the nearer end -fn line_segment_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + ToPrimitive + ::num_traits::FromPrimitive +pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, end: &'a P3) -> T + where T: 'a + Float + FromPrimitive, + P1: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized, + P3: 'a + PointTrait + ?Sized, { let dist_squared = pow(start.distance_to_point(end), 2); // Implies that start == end @@ -97,7 +40,7 @@ fn line_segment_distance(point: &Point, start: &Point, end: &Point) // We find the projection of the point onto the line // This falls where t = [(point - start) . (end - start)] / |end - start|^2, where . is the dot product // We constrain t to a 0, 1 interval to handle points outside the segment start, end - let t = T::zero().max(T::one().min((*point - *start).dot(&(*end - *start)) / dist_squared)); + let t = T::zero().max(T::one().min(point.sub(start).dot(&end.sub(start)) / dist_squared)); let projected = Point::new(start.x() + t * (end.x() - start.x()), start.y() + t * (end.y() - start.y())); point.distance_to_point(&projected) @@ -127,57 +70,60 @@ impl PartialOrd for Mindist impl Eq for Mindist where T: Float + ::num_traits::FromPrimitive {} // Minimum distance from a Point to a Polygon -impl Distance> for Point - where T: Float + ::num_traits::FromPrimitive +pub fn polygon_to_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> T + where T: 'a + Float + FromPrimitive, + P1: 'a + PolygonTrait<'a, T> + ?Sized, + P2: 'a + PointTrait + ?Sized, { - fn distance(&self, polygon: &Polygon) -> T { - // get exterior ring - let exterior = &polygon.exterior; - // exterior ring as a LineString - let ext_ring = &exterior.0; - // No need to continue if the polygon contains the point, or is zero-length - if polygon.contains_point(self) || ext_ring.is_empty() { - return T::zero(); - } - // minimum priority queue - let mut dist_queue: BinaryHeap> = BinaryHeap::new(); - // we've got interior rings - for ring in &polygon.interiors { - dist_queue.push(Mindist { distance: self.distance(ring) }) - } - for chunk in ext_ring.windows(2) { - let dist = line_segment_distance(self, &chunk[0], &chunk[1]); - dist_queue.push(Mindist { distance: dist }); - } - dist_queue.pop().unwrap().distance + // get exterior ring + // exterior ring as a LineString + let mut rings = polygon.rings(); + // TODO: remove `collect` + let ext_ring = rings.next().expect("no outer ring").points().collect::>(); + + // No need to continue if the polygon contains the point, or is zero-length + if polygon.contains_point(point) || ext_ring.is_empty() { + return T::zero(); + } + // minimum priority queue + let mut dist_queue: BinaryHeap> = BinaryHeap::new(); + // we've got interior rings + for ring in rings { + dist_queue.push(Mindist { distance: ring.distance_to_point(point) }) + } + for chunk in ext_ring.windows(2) { + let dist = line_segment_distance(point, chunk[0], chunk[1]); + dist_queue.push(Mindist { distance: dist }); } + dist_queue.pop().unwrap().distance } // Minimum distance from a Point to a LineString -impl Distance> for Point - where T: Float + ::num_traits::FromPrimitive +pub fn line_string_to_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> T + where T: 'a + Float + FromPrimitive, + L: 'a + LineStringTrait<'a, T> + ?Sized, + P: 'a + PointTrait + ?Sized, { - fn distance(&self, linestring: &LineString) -> T { - // No need to continue if the point is on the LineString, or it's empty - if linestring.contains_point(self) || linestring.0.len() == 0 { - return T::zero(); - } - // minimum priority queue - let mut dist_queue: BinaryHeap> = BinaryHeap::new(); - // get points vector - let points = &linestring.0; - for chunk in points.windows(2) { - let dist = line_segment_distance(self, &chunk[0], &chunk[1]); - dist_queue.push(Mindist { distance: dist }); - } - dist_queue.pop().unwrap().distance + // No need to continue if the point is on the LineString, or it's empty + if line_string.contains_point(point) || line_string.points().next().is_none() { + return T::zero(); + } + // minimum priority queue + let mut dist_queue: BinaryHeap> = BinaryHeap::new(); + // get points vector + // TODO: remove `collect` + let points = line_string.points().collect::>(); + for chunk in points.windows(2) { + let dist = line_segment_distance(point, chunk[0], chunk[1]); + dist_queue.push(Mindist { distance: dist }); } + dist_queue.pop().unwrap().distance } #[cfg(test)] mod test { use types::{Point, LineString, Polygon}; - use algorithm::distance::{Distance, line_segment_distance}; + use algorithm::distance::{line_segment_distance}; use test_helpers::within_epsilon; use traits::PointTrait; @@ -214,7 +160,7 @@ mod test { let poly = Polygon::new(ls, vec![]); // A Random point outside the octagon let p = Point::new(2.5, 0.5); - let dist = p.distance(&poly); + let dist = p.distance_to_polygon(&poly); assert!(within_epsilon(dist, 2.1213203435596424, 1.0e-15)); } #[test] @@ -227,7 +173,7 @@ mod test { let poly = Polygon::new(ls, vec![]); // A Random point inside the octagon let p = Point::new(5.5, 2.1); - let dist = p.distance(&poly); + let dist = p.distance_to_polygon(&poly); assert!(within_epsilon(dist, 0.0, 1.0e-15)); } #[test] @@ -240,7 +186,7 @@ mod test { let poly = Polygon::new(ls, vec![]); // A point on the octagon let p = Point::new(5.0, 1.0); - let dist = p.distance(&poly); + let dist = p.distance_to_polygon(&poly); assert!(within_epsilon(dist, 0.0, 1.0e-15)); } #[test] @@ -252,7 +198,7 @@ mod test { let poly = Polygon::new(ls, vec![]); // A point on the octagon let p = Point::new(2.5, 0.5); - let dist = p.distance(&poly); + let dist = p.distance_to_polygon(&poly); assert!(within_epsilon(dist, 0.0, 1.0e-15)); } #[test] @@ -282,7 +228,7 @@ mod test { let poly = Polygon::new(ls_ext, vec![ls_int]); // A point inside the cutout triangle let p = Point::new(3.5, 2.5); - let dist = p.distance(&poly); + let dist = p.distance_to_polygon(&poly); // 0.41036467732879783 <-- Shapely assert!(within_epsilon(dist, 0.41036467732879767, 1.0e-15)); } @@ -303,7 +249,7 @@ mod test { let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); // A Random point "inside" the LineString let p = Point::new(5.5, 2.1); - let dist = p.distance(&ls); + let dist = p.distance_to_line_string(&ls); assert!(within_epsilon(dist, 1.1313708498984758, 1.0e-15)); } #[test] @@ -323,7 +269,7 @@ mod test { let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); // A point which lies on the LineString let p = Point::new(5.0, 4.0); - let dist = p.distance(&ls); + let dist = p.distance_to_line_string(&ls); assert!(within_epsilon(dist, 0.0, 1.0e-15)); } #[test] @@ -337,7 +283,7 @@ mod test { ]; let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); let p = Point::new(3.5, 2.5); - let dist = p.distance(&ls); + let dist = p.distance_to_line_string(&ls); assert!(within_epsilon(dist, 0.5, 1.0e-15)); } #[test] @@ -346,7 +292,7 @@ mod test { let points = vec![]; let ls = LineString(points); let p = Point::new(5.0, 4.0); - let dist = p.distance(&ls); + let dist = p.distance_to_line_string(&ls); assert!(within_epsilon(dist, 0.0, 1.0e-15)); } #[test] diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index e7c9ed122..e06120aa1 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -37,7 +37,7 @@ pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, l pub fn polygon_intersects_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool where T: 'a + Float + ::num_traits::FromPrimitive, P: 'a + PolygonTrait<'a, T> + ?Sized, - L: 'a + LineStringTrait<'a, T> + Sized, + L: 'a + LineStringTrait<'a, T> + ?Sized, { let mut rings = polygon.rings(); let exterior_ring = rings.next().expect("no outer ring"); diff --git a/src/traits.rs b/src/traits.rs index a0b87e52e..010443040 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -14,6 +14,14 @@ pub trait PointTrait: Sized { fn x(&self) -> T; fn y(&self) -> T; + // TODO: keep this? + fn sub>(&self, other: &P) -> ::Point { + ::Point(::Coordinate { + x: self.x() - other.x(), + y: self.y() - other.y(), + }) + } + // TODO: keep this? fn eq_coordinates>(&self, other: &P) -> bool { self.x() == other.x() && self.y() == other.y() @@ -23,6 +31,20 @@ pub trait PointTrait: Sized { ::algorithm::distance::point_to_point(self, other) } + // TODO: remove N + fn distance_to_line_string<'a, N: 'a + Float + FromPrimitive, L: LineStringTrait<'a, N>>(&'a self, line_string: &'a L) -> N + where Self: PointTrait + { + ::algorithm::distance::line_string_to_point(line_string, self) + } + + // TODO: remove N + fn distance_to_polygon<'a, N: 'a + Float + FromPrimitive, P: PolygonTrait<'a, N>>(&'a self, polygon: &'a P) -> N + where Self: PointTrait + { + ::algorithm::distance::polygon_to_point(polygon, self) + } + fn contains_point>(&self, other: &P) -> bool { ::algorithm::contains::point_contains_point(self, other) } @@ -51,7 +73,11 @@ pub trait LineStringTrait<'a, T> ::algorithm::contains::line_string_contains_point(self, other) } - fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { + fn distance_to_point>(&'a self, point: &'a P) -> T { + ::algorithm::distance::line_string_to_point(self, point) + } + + fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { ::algorithm::intersects::line_string_intersects_line_string(self, line_string) } @@ -86,6 +112,10 @@ pub trait PolygonTrait<'a, T> ::algorithm::contains::polygon_contains_line_string(self, line_string) } + fn distance_to_point>(&'a self, point: &'a P) -> T { + ::algorithm::distance::polygon_to_point(self, point) + } + fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { ::algorithm::intersects::polygon_intersects_line_string(self, line_string) } From 97cd9ad015bfd4799c3e41cde7962a4f8592715d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 26 Jan 2017 21:42:35 -0500 Subject: [PATCH 33/34] remove fromprimitive trait --- src/algorithm/area.rs | 9 +++---- src/algorithm/boundingbox.rs | 16 +++++------ src/algorithm/centroid.rs | 11 ++++---- src/algorithm/contains.rs | 16 +++++------ src/algorithm/distance.rs | 18 ++++++------- src/algorithm/intersects.rs | 12 ++++----- src/algorithm/length.rs | 4 +-- src/algorithm/simplify.rs | 8 +++--- src/algorithm/simplifyvw.rs | 18 ++++++------- src/traits.rs | 21 +++++++-------- src/types.rs | 51 ++++++++++++++++++------------------ src/vw_orig.rs | 2 +- 12 files changed, 92 insertions(+), 94 deletions(-) diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 778a04d7d..770b56adb 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,8 +1,8 @@ -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , G: 'a + LineStringTrait<'a, T> { let mut points = linestring.points(); @@ -18,9 +18,8 @@ fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T tmp / (T::one() + T::one()) } -// FIXME: remove FromPrimitive pub fn polygon<'a, G, T>(polygon: &'a G) -> T - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , G: 'a + PolygonTrait<'a, T> + ?Sized { let mut rings = polygon.rings(); @@ -32,7 +31,7 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> T } pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , G: 'a + MultiPolygonTrait<'a, T> + ?Sized { multi_polygon.polygons().map(polygon).fold(T::zero(), |acc, n| acc + n) diff --git a/src/algorithm/boundingbox.rs b/src/algorithm/boundingbox.rs index 0cf3fbe04..237c9854a 100644 --- a/src/algorithm/boundingbox.rs +++ b/src/algorithm/boundingbox.rs @@ -4,7 +4,7 @@ use types::{Bbox, Point, MultiPoint, LineString, MultiLineString, Polygon, Multi /// Calculation of the bounding box of a geometry. -pub trait BoundingBox { +pub trait BoundingBox { /// Return a Bounding Box of a geometry /// /// ``` @@ -29,13 +29,13 @@ pub trait BoundingBox { fn get_min_max(p: T, min: T, max: T) -> (T, T) - where T: Float + ::num_traits::FromPrimitive + where T: Float { if p > max {(min, p)} else if p < min {(p, max)} else {(min, max)} } fn get_bbox<'a, I, T>(collection: I) -> Option> - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , I: 'a + IntoIterator> { let mut iter = collection.into_iter(); @@ -55,7 +55,7 @@ fn get_bbox<'a, I, T>(collection: I) -> Option> impl BoundingBox for MultiPoint - where T: Float + ::num_traits::FromPrimitive + where T: Float { /// /// Return the BoundingBox for a MultiPoint @@ -66,7 +66,7 @@ impl BoundingBox for MultiPoint } impl BoundingBox for LineString - where T: Float + ::num_traits::FromPrimitive + where T: Float { /// /// Return the BoundingBox for a LineString @@ -77,7 +77,7 @@ impl BoundingBox for LineString } impl BoundingBox for MultiLineString - where T: Float + ::num_traits::FromPrimitive + where T: Float { /// /// Return the BoundingBox for a MultiLineString @@ -88,7 +88,7 @@ impl BoundingBox for MultiLineString } impl BoundingBox for Polygon - where T: Float + ::num_traits::FromPrimitive + where T: Float { /// /// Return the BoundingBox for a Polygon @@ -100,7 +100,7 @@ impl BoundingBox for Polygon } impl BoundingBox for MultiPolygon - where T: Float + ::num_traits::FromPrimitive + where T: Float { /// /// Return the BoundingBox for a MultiPolygon diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index c8c44f5d3..dc913e1e3 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -1,10 +1,10 @@ -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; use types::Point; use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , G: 'a + LineStringTrait<'a, T> + ?Sized { // TODO: remove `collect` @@ -31,7 +31,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> } pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , G: 'a + PolygonTrait<'a, T> + ?Sized { // TODO: consideration of inner polygons; @@ -52,13 +52,14 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> sum_x = sum_x + ((ps[1].x() + ps[0].x()) * tmp); sum_y = sum_y + ((ps[1].y() + ps[0].y()) * tmp); } - let six = T::from_i32(6).unwrap(); + let six = T::one() + T::one() + T::one() + + T::one() + T::one() + T::one(); Some(Point::new(sum_x / (six * area), sum_y / (six * area))) } } pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , G: 'a + MultiPolygonTrait<'a, T> + ?Sized { // See: https://fotino.me/calculating-centroids/ diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 4120a32e0..7275d7d42 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -1,10 +1,10 @@ -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; use types::COORD_PRECISION; use traits::{PointTrait, LineStringTrait, PolygonTrait, MultiPolygonTrait}; pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bool - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P1: 'a + PointTrait + ?Sized, P2: 'a + PointTrait + ?Sized, { @@ -12,7 +12,7 @@ pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bo } pub fn line_string_contains_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> bool - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , L: 'a + LineStringTrait<'a, T> + ?Sized, P: 'a + PointTrait + ?Sized, { @@ -55,7 +55,7 @@ enum PositionPoint { } fn get_position<'a, P, L, T>(point: &'a P, line_string: &'a L) -> PositionPoint - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P: 'a + PointTrait + ?Sized, L: 'a + LineStringTrait<'a, T> + ?Sized, { @@ -101,7 +101,7 @@ fn get_position<'a, P, L, T>(point: &'a P, line_string: &'a L) -> PositionPoint } pub fn polygon_contains_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> bool - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P1: 'a + PolygonTrait<'a, T> + ?Sized, P2: 'a + PointTrait + ?Sized, { @@ -115,7 +115,7 @@ pub fn polygon_contains_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> } pub fn multi_polygon_contains_point<'a, M, P, T>(multi_polygon: &'a M, point: &'a P) -> bool - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , M: 'a + MultiPolygonTrait<'a, T> + ?Sized, P: 'a + PointTrait + ?Sized, { @@ -123,7 +123,7 @@ pub fn multi_polygon_contains_point<'a, M, P, T>(multi_polygon: &'a M, point: &' } pub fn polygon_contains_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , P: 'a + PolygonTrait<'a, T> + ?Sized, L: 'a + LineStringTrait<'a, T> + Sized, { @@ -137,7 +137,7 @@ pub fn polygon_contains_line_string<'a, P, L, T>(polygon: &'a P, line_string: &' /* impl Contains> for Bbox - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn contains(&self, bbox: &Bbox) -> bool { // All points of LineString must be in the polygon ? diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 83d762519..3c2a8d0bb 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -1,12 +1,12 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; use types::Point; use traits::{PointTrait, LineStringTrait, PolygonTrait}; use num_traits::pow::pow; pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P1: 'a + PointTrait + ?Sized, P2: 'a + PointTrait + ?Sized, { @@ -26,7 +26,7 @@ pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T // falls on the line past one end or the other of the segment. In that case the // distance to the segment will be the distance to the nearer end pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, end: &'a P3) -> T - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P1: 'a + PointTrait + ?Sized, P2: 'a + PointTrait + ?Sized, P3: 'a + PointTrait + ?Sized, @@ -48,30 +48,30 @@ pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, en #[derive(PartialEq, Debug)] struct Mindist - where T: Float + ::num_traits::FromPrimitive + where T: Float { distance: T, } // These impls give us a min-heap when used with BinaryHeap impl Ord for Mindist - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn cmp(&self, other: &Mindist) -> Ordering { other.distance.partial_cmp(&self.distance).unwrap() } } impl PartialOrd for Mindist - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn partial_cmp(&self, other: &Mindist) -> Option { Some(self.cmp(other)) } } -impl Eq for Mindist where T: Float + ::num_traits::FromPrimitive {} +impl Eq for Mindist where T: Float {} // Minimum distance from a Point to a Polygon pub fn polygon_to_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> T - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , P1: 'a + PolygonTrait<'a, T> + ?Sized, P2: 'a + PointTrait + ?Sized, { @@ -100,7 +100,7 @@ pub fn polygon_to_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> T // Minimum distance from a Point to a LineString pub fn line_string_to_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> T - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , L: 'a + LineStringTrait<'a, T> + ?Sized, P: 'a + PointTrait + ?Sized, { diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index e06120aa1..6a3e2175e 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -2,7 +2,7 @@ use num_traits::Float; use traits::{LineStringTrait, PolygonTrait, PointTrait}; pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, line_string2: &'a L2) -> bool - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , L1: 'a + LineStringTrait<'a, T> + ?Sized, L2: 'a + LineStringTrait<'a, T> + ?Sized, { @@ -35,7 +35,7 @@ pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, l } pub fn polygon_intersects_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , P: 'a + PolygonTrait<'a, T> + ?Sized, L: 'a + LineStringTrait<'a, T> + ?Sized, { @@ -53,7 +53,7 @@ pub fn polygon_intersects_line_string<'a, P, L, T>(polygon: &'a P, line_string: /* impl Intersects> for Bbox - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn intersects(&self, bbox: &Bbox) -> bool { // line intersects inner or outer polygon edge @@ -67,7 +67,7 @@ impl Intersects> for Bbox } impl Intersects> for Bbox - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn intersects(&self, polygon: &Polygon) -> bool { polygon.intersects(self) @@ -75,7 +75,7 @@ impl Intersects> for Bbox } impl Intersects> for Polygon - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn intersects(&self, bbox: &Bbox) -> bool { let p = Polygon::new(LineString(vec![Point::new(bbox.xmin, bbox.ymin), @@ -90,7 +90,7 @@ impl Intersects> for Polygon */ pub fn polygon_intersects_polygon<'a, P1, P2, T>(polygon1: &'a P1, polygon2: &'a P2) -> bool - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , P1: 'a + PolygonTrait<'a, T> + ?Sized, P2: 'a + PolygonTrait<'a, T> + ?Sized, { diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index a1266e5b5..ee428a4bb 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -3,7 +3,7 @@ use num_traits::Float; use traits::{PointTrait, LineStringTrait, MultiLineStringTrait}; pub fn line_string<'a, G, T>(line_string: &'a G) -> T - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , G: 'a + LineStringTrait<'a, T> + ?Sized { // FIXME: don't collect @@ -13,7 +13,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> T } pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T - where T: 'a + Float + ::num_traits::FromPrimitive, + where T: 'a + Float , G: 'a + MultiLineStringTrait<'a, T> + ?Sized { multi_line_string.lines().fold(T::zero(), |total, line| total + line.length()) diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index 9d9885e97..8de18170d 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -4,7 +4,7 @@ use traits::PointTrait; // perpendicular distance from a point to a line fn point_line_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + ::num_traits::FromPrimitive + where T: Float { if start == end { point.distance_to_point(start) @@ -19,7 +19,7 @@ fn point_line_distance(point: &Point, start: &Point, end: &Point) -> // Ramer–Douglas-Peucker line simplification algorithm fn rdp(points: &[Point], epsilon: &T) -> Vec> - where T: Float + ::num_traits::FromPrimitive + where T: Float { if points.is_empty() { return points.to_vec(); @@ -70,11 +70,11 @@ pub trait Simplify { /// let simplified = linestring.simplify(&1.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplify(&self, epsilon: &T) -> Self where T: Float + ::num_traits::FromPrimitive; + fn simplify(&self, epsilon: &T) -> Self where T: Float ; } impl Simplify for LineString - where T: Float + ::num_traits::FromPrimitive + where T: Float { fn simplify(&self, epsilon: &T) -> LineString { LineString(rdp(&self.0, epsilon)) diff --git a/src/algorithm/simplifyvw.rs b/src/algorithm/simplifyvw.rs index 22e60b9f7..ae0412a9f 100644 --- a/src/algorithm/simplifyvw.rs +++ b/src/algorithm/simplifyvw.rs @@ -1,13 +1,13 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; use types::{Point, LineString}; // A helper struct for `visvalingam`, defined out here because // #[deriving] doesn't work inside functions. #[derive(PartialEq, Debug)] struct VScore - where T: Float + FromPrimitive + where T: Float { area: T, current: usize, @@ -17,7 +17,7 @@ struct VScore // These impls give us a min-heap impl Ord for VScore - where T: Float + FromPrimitive + where T: Float { fn cmp(&self, other: &VScore) -> Ordering { other.area.partial_cmp(&self.area).unwrap() @@ -25,14 +25,14 @@ impl Ord for VScore } impl PartialOrd for VScore - where T: Float + FromPrimitive + where T: Float { fn partial_cmp(&self, other: &VScore) -> Option { Some(self.cmp(other)) } } -impl Eq for VScore where T: Float + FromPrimitive {} +impl Eq for VScore where T: Float {} /// Simplify a line using the [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) algorithm /// @@ -47,7 +47,7 @@ impl Eq for VScore where T: Float + FromPrimitive {} // It's OK to remove triangles with areas below the epsilon, // then recalculate the new triangle area and push it onto the heap pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> - where T: Float + FromPrimitive + where T: Float { // No need to continue without at least three points if orig.len() < 3 || orig.is_empty() { @@ -138,7 +138,7 @@ pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> // Area of a triangle given three vertices fn area(p1: &Point, p2: &Point, p3: &Point) -> T - where T: Float + FromPrimitive + where T: Float { ((p1.x() - p3.x()) * (p2.y() - p3.y()) - (p2.x() - p3.x()) * (p1.y() - p3.y())).abs() / (T::one() + T::one()) @@ -168,11 +168,11 @@ pub trait SimplifyVW { /// let simplified = linestring.simplifyvw(&30.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplifyvw(&self, epsilon: &T) -> Self where T: Float + FromPrimitive; + fn simplifyvw(&self, epsilon: &T) -> Self where T: Float ; } impl SimplifyVW for LineString - where T: Float + FromPrimitive + where T: Float { fn simplifyvw(&self, epsilon: &T) -> LineString { LineString(visvalingam(&self.0, epsilon)) diff --git a/src/traits.rs b/src/traits.rs index 010443040..c6f09cbd1 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,16 +1,15 @@ pub use ::Geometry; -use num_traits::{Float, FromPrimitive}; +use num_traits::Float; -pub trait ToGeo +pub trait ToGeo { fn to_geo(&self) -> Geometry; } // FIXME: find good names for these traits, don't use XyzTrait naming scheme -// FIXME: remove FromPrimitive trait -pub trait PointTrait: Sized { +pub trait PointTrait: Sized { fn x(&self) -> T; fn y(&self) -> T; @@ -32,14 +31,14 @@ pub trait PointTrait: Sized { } // TODO: remove N - fn distance_to_line_string<'a, N: 'a + Float + FromPrimitive, L: LineStringTrait<'a, N>>(&'a self, line_string: &'a L) -> N + fn distance_to_line_string<'a, N: 'a + Float , L: LineStringTrait<'a, N>>(&'a self, line_string: &'a L) -> N where Self: PointTrait { ::algorithm::distance::line_string_to_point(line_string, self) } // TODO: remove N - fn distance_to_polygon<'a, N: 'a + Float + FromPrimitive, P: PolygonTrait<'a, N>>(&'a self, polygon: &'a P) -> N + fn distance_to_polygon<'a, N: 'a + Float , P: PolygonTrait<'a, N>>(&'a self, polygon: &'a P) -> N where Self: PointTrait { ::algorithm::distance::polygon_to_point(polygon, self) @@ -51,7 +50,7 @@ pub trait PointTrait: Sized { } pub trait LineStringTrait<'a, T> - where T: 'a + Float + FromPrimitive + where T: 'a + Float { type ItemType: 'a + PointTrait; type Iter: Iterator; @@ -87,7 +86,7 @@ pub trait LineStringTrait<'a, T> } pub trait PolygonTrait<'a, T> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , { type ItemType: 'a + LineStringTrait<'a, T>; type Iter: 'a + Iterator; @@ -126,7 +125,7 @@ pub trait PolygonTrait<'a, T> } pub trait MultiPointTrait<'a, T> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , { type ItemType: 'a + PointTrait; type Iter: Iterator; @@ -135,7 +134,7 @@ pub trait MultiPointTrait<'a, T> } pub trait MultiLineStringTrait<'a, T> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , { type ItemType: 'a + LineStringTrait<'a, T>; type Iter: Iterator; @@ -149,7 +148,7 @@ pub trait MultiLineStringTrait<'a, T> } pub trait MultiPolygonTrait<'a, T> - where T: 'a + Float + FromPrimitive, + where T: 'a + Float , { type ItemType: 'a + PolygonTrait<'a, T>; type Iter: Iterator; diff --git a/src/types.rs b/src/types.rs index ea5dfa620..94194c48c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,16 +1,15 @@ -// FIXME: remove FromPrimitive use std::ops::Add; use std::ops::AddAssign; use std::ops::Neg; use std::ops::Sub; -use num_traits::{Float, ToPrimitive, FromPrimitive}; +use num_traits::{Float, ToPrimitive}; pub static COORD_PRECISION: f32 = 1e-1; // 0.1m #[derive(PartialEq, Clone, Copy, Debug)] pub struct Coordinate - where T: Float + FromPrimitive + where T: Float { pub x: T, pub y: T, @@ -18,7 +17,7 @@ pub struct Coordinate #[derive(PartialEq, Clone, Copy, Debug)] pub struct Bbox - where T: Float + FromPrimitive + where T: Float { pub xmin: T, pub xmax: T, @@ -28,7 +27,7 @@ pub struct Bbox // TODO: complete this: /* -impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Bbox { +impl<'a, T: 'a + Float > ::PolygonTrait<'a, T> for Bbox { type ItemType = LineString; type Iter = Box + 'a>; @@ -46,10 +45,10 @@ impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Bbox { */ #[derive(PartialEq, Clone, Copy, Debug)] -pub struct Point (pub Coordinate) where T: Float + FromPrimitive; +pub struct Point (pub Coordinate) where T: Float ; impl Point - where T: Float + ToPrimitive + FromPrimitive + where T: Float + ToPrimitive { /// Creates a new point. /// @@ -192,7 +191,7 @@ impl Point } impl Neg for Point - where T: Float + Neg + ToPrimitive + FromPrimitive + where T: Float + Neg + ToPrimitive { type Output = Point; @@ -212,7 +211,7 @@ impl Neg for Point } impl Add for Point - where T: Float + ToPrimitive + FromPrimitive + where T: Float + ToPrimitive { type Output = Point; @@ -232,7 +231,7 @@ impl Add for Point } impl Sub for Point - where T: Float + ToPrimitive + FromPrimitive + where T: Float + ToPrimitive { type Output = Point; @@ -251,7 +250,7 @@ impl Sub for Point } } -impl ::PointTrait for Point { +impl ::PointTrait for Point { fn x(&self) -> T { self.x() } @@ -262,7 +261,7 @@ impl ::PointTrait for Point { } impl Add for Bbox - where T: Float + ToPrimitive + FromPrimitive + where T: Float + ToPrimitive { type Output = Bbox; @@ -291,7 +290,7 @@ impl Add for Bbox } impl AddAssign for Bbox - where T: Float + ToPrimitive + FromPrimitive + where T: Float + ToPrimitive { /// Add a boundingox to the given boundingbox. /// @@ -317,9 +316,9 @@ impl AddAssign for Bbox #[derive(PartialEq, Clone, Debug)] -pub struct MultiPoint(pub Vec>) where T: Float + FromPrimitive; +pub struct MultiPoint(pub Vec>) where T: Float ; -impl<'a, T: 'a + Float + FromPrimitive> ::MultiPointTrait<'a, T> for MultiPoint { +impl<'a, T: 'a + Float > ::MultiPointTrait<'a, T> for MultiPoint { type ItemType = Point; type Iter = Box + 'a>; @@ -329,9 +328,9 @@ impl<'a, T: 'a + Float + FromPrimitive> ::MultiPointTrait<'a, T> for MultiPoint< } #[derive(PartialEq, Clone, Debug)] -pub struct LineString(pub Vec>) where T: Float + FromPrimitive; +pub struct LineString(pub Vec>) where T: Float ; -impl<'a, T: 'a + Float + FromPrimitive> ::LineStringTrait<'a, T> for LineString { +impl<'a, T: 'a + Float > ::LineStringTrait<'a, T> for LineString { type ItemType = Point; type Iter = Box + 'a>; @@ -341,9 +340,9 @@ impl<'a, T: 'a + Float + FromPrimitive> ::LineStringTrait<'a, T> for LineString< } #[derive(PartialEq, Clone, Debug)] -pub struct MultiLineString(pub Vec>) where T: Float + FromPrimitive; +pub struct MultiLineString(pub Vec>) where T: Float ; -impl<'a, T: 'a + Float + FromPrimitive> ::MultiLineStringTrait<'a, T> for MultiLineString { +impl<'a, T: 'a + Float > ::MultiLineStringTrait<'a, T> for MultiLineString { type ItemType = LineString; type Iter = Box + 'a>; @@ -354,14 +353,14 @@ impl<'a, T: 'a + Float + FromPrimitive> ::MultiLineStringTrait<'a, T> for MultiL #[derive(PartialEq, Clone, Debug)] pub struct Polygon - where T: Float + FromPrimitive + where T: Float { pub exterior: LineString, pub interiors: Vec> } impl Polygon - where T: Float + FromPrimitive + where T: Float { /// Creates a new polygon. /// @@ -381,7 +380,7 @@ impl Polygon } } -impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Polygon { +impl<'a, T: 'a + Float > ::PolygonTrait<'a, T> for Polygon { type ItemType = LineString; type Iter = Box + 'a>; @@ -393,9 +392,9 @@ impl<'a, T: 'a + Float + FromPrimitive> ::PolygonTrait<'a, T> for Polygon { } #[derive(PartialEq, Clone, Debug)] -pub struct MultiPolygon(pub Vec>) where T: Float + FromPrimitive; +pub struct MultiPolygon(pub Vec>) where T: Float ; -impl<'a, T: 'a + Float + FromPrimitive> ::MultiPolygonTrait<'a, T> for MultiPolygon { +impl<'a, T: 'a + Float > ::MultiPolygonTrait<'a, T> for MultiPolygon { type ItemType = Polygon; type Iter = Box + 'a>; @@ -405,11 +404,11 @@ impl<'a, T: 'a + Float + FromPrimitive> ::MultiPolygonTrait<'a, T> for MultiPoly } #[derive(PartialEq, Clone, Debug)] -pub struct GeometryCollection(pub Vec>) where T: Float + FromPrimitive; +pub struct GeometryCollection(pub Vec>) where T: Float ; #[derive(PartialEq, Clone, Debug)] pub enum Geometry - where T: Float + FromPrimitive + where T: Float { Point(Point), LineString(LineString), diff --git a/src/vw_orig.rs b/src/vw_orig.rs index 1fa6f8390..175298a04 100644 --- a/src/vw_orig.rs +++ b/src/vw_orig.rs @@ -402,4 +402,4 @@ vec![ [37.538471, 55.76757], [37.569962, 55.77998] ] - \ No newline at end of file + From 47c7ccc173dae6c116e794480fc712a4297b3d60 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 26 Jan 2017 21:59:05 -0500 Subject: [PATCH 34/34] cargo fmt --- examples/algorithm.rs | 10 +-- examples/types.rs | 2 +- src/algorithm/area.rs | 20 ++--- src/algorithm/boundingbox.rs | 93 ++++++++++++++++------ src/algorithm/centroid.rs | 23 +++--- src/algorithm/contains.rs | 59 +++++++------- src/algorithm/distance.rs | 84 ++++++-------------- src/algorithm/intersects.rs | 98 ++++++++++++++--------- src/algorithm/length.rs | 14 ++-- src/algorithm/simplify.rs | 19 ++--- src/algorithm/simplifyvw.rs | 39 +++++----- src/test_helpers.rs | 5 +- src/traits.rs | 37 +++++---- src/types.rs | 146 ++++++++++++++++++++++++----------- 14 files changed, 374 insertions(+), 275 deletions(-) diff --git a/examples/algorithm.rs b/examples/algorithm.rs index 34848b0be..621b41133 100644 --- a/examples/algorithm.rs +++ b/examples/algorithm.rs @@ -2,15 +2,15 @@ extern crate geo; use geo::{Point, LineString, Coordinate, LineStringTrait}; -fn main() { +fn main() { let mut vec = Vec::new(); - vec.push(Point(Coordinate{ + vec.push(Point(Coordinate { x: 40.02f64, - y: 116.34 + y: 116.34, })); - vec.push(Point(Coordinate{ + vec.push(Point(Coordinate { x: 41.02f64, - y: 116.34 + y: 116.34, })); let linestring = LineString(vec); println!("Centroid {:?}", linestring.centroid()); diff --git a/examples/types.rs b/examples/types.rs index c76f222d1..7a771d95c 100644 --- a/examples/types.rs +++ b/examples/types.rs @@ -5,7 +5,7 @@ use geo::{Point, Coordinate}; fn main() { let c = Coordinate { x: 40.02f64, - y: 116.34 + y: 116.34, }; let p = Point(c); diff --git a/src/algorithm/area.rs b/src/algorithm/area.rs index 770b56adb..4b12661a5 100644 --- a/src/algorithm/area.rs +++ b/src/algorithm/area.rs @@ -1,8 +1,8 @@ use num_traits::Float; -use ::{MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; +use {MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait}; fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T - where T: 'a + Float , + where T: 'a + Float, G: 'a + LineStringTrait<'a, T> { let mut points = linestring.points(); @@ -19,19 +19,18 @@ fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T } pub fn polygon<'a, G, T>(polygon: &'a G) -> T - where T: 'a + Float , + where T: 'a + Float, G: 'a + PolygonTrait<'a, T> + ?Sized { let mut rings = polygon.rings(); let outer_ring = rings.next().expect("no outer ring in polygon"); let outer_ring_area = get_linestring_area(outer_ring); - rings.fold(outer_ring_area, |acc, inner_ring| { - acc - get_linestring_area(inner_ring) - }) + rings.fold(outer_ring_area, + |acc, inner_ring| acc - get_linestring_area(inner_ring)) } pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T - where T: 'a + Float , + where T: 'a + Float, G: 'a + MultiPolygonTrait<'a, T> + ?Sized { multi_polygon.polygons().map(polygon).fold(T::zero(), |acc, n| acc + n) @@ -42,7 +41,7 @@ mod test { use num_traits::Float; use types::{Coordinate, Point, LineString, Polygon, MultiPolygon}; use test_helpers::within_epsilon; - use ::{PolygonTrait, MultiPolygonTrait}; + use {PolygonTrait, MultiPolygonTrait}; #[test] fn area_empty_polygon_test() { @@ -76,7 +75,10 @@ mod test { #[test] fn area_multipolygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly0 = Polygon::new(LineString(vec![p(0., 0.), p(10., 0.), p(10., 10.), p(0., 10.), + let poly0 = Polygon::new(LineString(vec![p(0., 0.), + p(10., 0.), + p(10., 10.), + p(0., 10.), p(0., 0.)]), Vec::new()); let poly1 = Polygon::new(LineString(vec![p(1., 1.), p(2., 1.), p(2., 2.), p(1., 2.), diff --git a/src/algorithm/boundingbox.rs b/src/algorithm/boundingbox.rs index 237c9854a..cb53068e0 100644 --- a/src/algorithm/boundingbox.rs +++ b/src/algorithm/boundingbox.rs @@ -4,7 +4,7 @@ use types::{Bbox, Point, MultiPoint, LineString, MultiLineString, Polygon, Multi /// Calculation of the bounding box of a geometry. -pub trait BoundingBox { +pub trait BoundingBox { /// Return a Bounding Box of a geometry /// /// ``` @@ -29,16 +29,22 @@ pub trait BoundingBox { fn get_min_max(p: T, min: T, max: T) -> (T, T) - where T: Float + where T: Float { - if p > max {(min, p)} else if p < min {(p, max)} else {(min, max)} + if p > max { + (min, p) + } else if p < min { + (p, max) + } else { + (min, max) + } } fn get_bbox<'a, I, T>(collection: I) -> Option> - where T: 'a + Float , + where T: 'a + Float, I: 'a + IntoIterator> { - let mut iter = collection.into_iter(); + 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()); @@ -47,15 +53,19 @@ fn get_bbox<'a, I, T>(collection: I) -> Option> xrange = get_min_max(px, xrange.0, xrange.1); yrange = get_min_max(py, yrange.0, yrange.1); } - return Some(Bbox{xmin: xrange.0, xmax: xrange.1, - ymin: yrange.0, ymax: yrange.1}) + return Some(Bbox { + xmin: xrange.0, + xmax: xrange.1, + ymin: yrange.0, + ymax: yrange.1, + }); } None } impl BoundingBox for MultiPoint - where T: Float + where T: Float { /// /// Return the BoundingBox for a MultiPoint @@ -66,7 +76,7 @@ impl BoundingBox for MultiPoint } impl BoundingBox for LineString - where T: Float + where T: Float { /// /// Return the BoundingBox for a LineString @@ -77,7 +87,7 @@ impl BoundingBox for LineString } impl BoundingBox for MultiLineString - where T: Float + where T: Float { /// /// Return the BoundingBox for a MultiLineString @@ -88,7 +98,7 @@ impl BoundingBox for MultiLineString } impl BoundingBox for Polygon - where T: Float + where T: Float { /// /// Return the BoundingBox for a Polygon @@ -100,7 +110,7 @@ impl BoundingBox for Polygon } impl BoundingBox for MultiPolygon - where T: Float + where T: Float { /// /// Return the BoundingBox for a MultiPolygon @@ -114,7 +124,8 @@ impl BoundingBox for MultiPolygon #[cfg(test)] mod test { - use types::{Bbox, Coordinate, Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon}; + use types::{Bbox, Coordinate, Point, MultiPoint, LineString, MultiLineString, Polygon, + MultiPolygon}; use algorithm::boundingbox::BoundingBox; #[test] @@ -130,14 +141,24 @@ mod test { let mut vect = Vec::>::new(); vect.push(p); let linestring = LineString(vect); - let bbox = Bbox{xmin: 40.02f64, ymax: 116.34, xmax: 40.02, ymin: 116.34}; + let bbox = Bbox { + xmin: 40.02f64, + ymax: 116.34, + xmax: 40.02, + ymin: 116.34, + }; assert_eq!(bbox, linestring.bbox().unwrap()); } #[test] fn linestring_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(1., 1.), p(2., -2.), p(-3., -3.), p(-4., 4.)]); - let bbox = Bbox{xmin: -4., ymax: 4., xmax: 2., ymin: -3.}; + let bbox = Bbox { + xmin: -4., + ymax: 4., + xmax: 2., + ymin: -3., + }; assert_eq!(bbox, linestring.bbox().unwrap()); } #[test] @@ -147,18 +168,28 @@ mod test { LineString(vec![p(1., 1.), p(50., 1.)]), LineString(vec![p(1., 1.), p(1., -60.)]), LineString(vec![p(1., 1.), p(1., 70.)])]); - let bbox = Bbox{xmin: -40., ymax: 70., xmax: 50., ymin: -60.}; + let bbox = Bbox { + xmin: -40., + ymax: 70., + xmax: 50., + ymin: -60., + }; assert_eq!(bbox, multiline.bbox().unwrap()); } #[test] fn multipoint_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let multipoint = MultiPoint(vec![p(1., 1.), p(2., -2.), p(-3., -3.), p(-4., 4.)]); - let bbox = Bbox{xmin: -4., ymax: 4., xmax: 2., ymin: -3.}; + let bbox = Bbox { + xmin: -4., + ymax: 4., + xmax: 2., + ymin: -3., + }; assert_eq!(bbox, multipoint.bbox().unwrap()); } #[test] - fn polygon_test(){ + fn polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]); let line_bbox = linestring.bbox().unwrap(); @@ -166,13 +197,27 @@ mod test { assert_eq!(line_bbox, poly.bbox().unwrap()); } #[test] - fn multipolygon_test(){ + fn multipolygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let mpoly = MultiPolygon(vec![Polygon::new(LineString(vec![p(0., 0.), p(50., 0.), p(0., -70.), p(0., 0.)]), Vec::new()), - Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(0., 80.), p(0., 0.)]), Vec::new()), - Polygon::new(LineString(vec![p(0., 0.), p(-60., 0.), p(0., 6.), p(0., 0.)]), Vec::new()), - ]); - let bbox = Bbox{xmin: -60., ymax: 80., xmax: 50., ymin: -70.}; + let mpoly = MultiPolygon(vec![Polygon::new(LineString(vec![p(0., 0.), + p(50., 0.), + p(0., -70.), + p(0., 0.)]), + Vec::new()), + Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), + p(0., 80.), p(0., 0.)]), + Vec::new()), + Polygon::new(LineString(vec![p(0., 0.), + p(-60., 0.), + p(0., 6.), + p(0., 0.)]), + Vec::new())]); + let bbox = Bbox { + xmin: -60., + ymax: 80., + xmax: 50., + ymin: -70., + }; assert_eq!(bbox, mpoly.bbox().unwrap()); } } diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index dc913e1e3..071f331ae 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -3,8 +3,8 @@ use num_traits::Float; use types::Point; use traits::{PolygonTrait, LineStringTrait, PointTrait, MultiPolygonTrait}; -pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> - where T: 'a + Float , +pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> + where T: 'a + Float, G: 'a + LineStringTrait<'a, T> + ?Sized { // TODO: remove `collect` @@ -13,8 +13,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> return None; } if vect.len() == 1 { - Some(Point::new(vect[0].x(), - vect[0].y())) + Some(Point::new(vect[0].x(), vect[0].y())) } else { let mut sum_x = T::zero(); let mut sum_y = T::zero(); @@ -30,8 +29,8 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option> } } -pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> - where T: 'a + Float , +pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> + where T: 'a + Float, G: 'a + PolygonTrait<'a, T> + ?Sized { // TODO: consideration of inner polygons; @@ -52,14 +51,13 @@ pub fn polygon<'a, G, T>(polygon: &'a G) -> Option> sum_x = sum_x + ((ps[1].x() + ps[0].x()) * tmp); sum_y = sum_y + ((ps[1].y() + ps[0].y()) * tmp); } - let six = T::one() + T::one() + T::one() + - T::one() + T::one() + T::one(); + let six = T::one() + T::one() + T::one() + T::one() + T::one() + T::one(); Some(Point::new(sum_x / (six * area), sum_y / (six * area))) } } -pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> - where T: 'a + Float , +pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> Option> + where T: 'a + Float, G: 'a + MultiPolygonTrait<'a, T> + ?Sized { // See: https://fotino.me/calculating-centroids/ @@ -154,7 +152,10 @@ mod test { let poly1 = Polygon::new(linestring, Vec::new()); let linestring = LineString(vec![p(7., 1.), p(8., 1.), p(8., 2.), p(7., 2.), p(7., 1.)]); let poly2 = Polygon::new(linestring, Vec::new()); - let dist = MultiPolygon(vec![poly1, poly2]).centroid().unwrap().distance_to_point(&p(4.07142857142857, 1.92857142857143)); + let dist = MultiPolygon(vec![poly1, poly2]) + .centroid() + .unwrap() + .distance_to_point(&p(4.07142857142857, 1.92857142857143)); assert!(dist < COORD_PRECISION); } } diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 7275d7d42..a7886544b 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -4,17 +4,17 @@ use types::COORD_PRECISION; use traits::{PointTrait, LineStringTrait, PolygonTrait, MultiPolygonTrait}; pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bool - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PointTrait + ?Sized, - P2: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized { point1.distance_to_point(point2).to_f32().unwrap() < COORD_PRECISION } pub fn line_string_contains_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> bool - where T: 'a + Float , + where T: 'a + Float, L: 'a + LineStringTrait<'a, T> + ?Sized, - P: 'a + PointTrait + ?Sized, + P: 'a + PointTrait + ?Sized { // FIXME: remove collect let vect = line_string.points().collect::>(); @@ -55,13 +55,14 @@ enum PositionPoint { } fn get_position<'a, P, L, T>(point: &'a P, line_string: &'a L) -> PositionPoint - where T: 'a + Float , + where T: 'a + Float, P: 'a + PointTrait + ?Sized, - L: 'a + LineStringTrait<'a, T> + ?Sized, + L: 'a + LineStringTrait<'a, T> + ?Sized { // See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // http://geospatialpython.com/search - // ?updated-min=2011-01-01T00:00:00-06:00&updated-max=2012-01-01T00:00:00-06:00&max-results=19 + // ?updated-min=2011-01-01T00:00:00-06:00 + // &updated-max=2012-01-01T00:00:00-06:00&max-results=19 // Return the position of the point relative to a linestring // TODO: remove `collect` call here @@ -101,9 +102,9 @@ fn get_position<'a, P, L, T>(point: &'a P, line_string: &'a L) -> PositionPoint } pub fn polygon_contains_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> bool - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PolygonTrait<'a, T> + ?Sized, - P2: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized { let mut rings = polygon.rings(); let exterior_ring = rings.next().expect("expected outer ring"); @@ -115,17 +116,17 @@ pub fn polygon_contains_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> } pub fn multi_polygon_contains_point<'a, M, P, T>(multi_polygon: &'a M, point: &'a P) -> bool - where T: 'a + Float , + where T: 'a + Float, M: 'a + MultiPolygonTrait<'a, T> + ?Sized, - P: 'a + PointTrait + ?Sized, + P: 'a + PointTrait + ?Sized { multi_polygon.polygons().any(|poly| poly.contains_point(point)) } pub fn polygon_contains_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool - where T: 'a + Float , + where T: 'a + Float, P: 'a + PolygonTrait<'a, T> + ?Sized, - L: 'a + LineStringTrait<'a, T> + Sized, + L: 'a + LineStringTrait<'a, T> + Sized { // All points of LineString must be in the polygon ? if line_string.points().all(|point| polygon.contains_point(point)) { @@ -137,11 +138,12 @@ pub fn polygon_contains_line_string<'a, P, L, T>(polygon: &'a P, line_string: &' /* impl Contains> for Bbox - where T: Float + where T: Float { fn contains(&self, bbox: &Bbox) -> bool { // All points of LineString must be in the polygon ? - self.xmin <= bbox.xmin && self.xmax >= bbox.xmax && self.ymin <= bbox.ymin && self.ymax >= bbox.ymax + self.xmin <= bbox.xmin && self.xmax >= bbox.xmax + && self.ymin <= bbox.ymin && self.ymax >= bbox.ymax } } */ @@ -218,11 +220,8 @@ mod test { fn point_polygon_with_inner_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]); - let inner_linestring = LineString(vec![p(0.5, 0.5), - p(1.5, 0.5), - p(1.5, 1.5), - p(0.0, 1.5), - p(0.0, 0.0)]); + let inner_linestring = + LineString(vec![p(0.5, 0.5), p(1.5, 0.5), p(1.5, 1.5), p(0.0, 1.5), p(0.0, 0.0)]); let poly = Polygon::new(linestring, vec![inner_linestring]); assert!(poly.contains_point(&p(0.25, 0.25))); assert!(!poly.contains_point(&p(1., 1.))); @@ -238,9 +237,11 @@ mod test { #[test] fn empty_multipolygon_two_polygons_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly1 = Polygon::new(LineString(vec![p(0., 0.), p(1., 0.), p(1., 1.), p(0., 1.), p(0., 0.)]), + let poly1 = Polygon::new(LineString(vec![p(0., 0.), p(1., 0.), p(1., 1.), p(0., 1.), + p(0., 0.)]), Vec::new()); - let poly2 = Polygon::new(LineString(vec![p(2., 0.), p(3., 0.), p(3., 1.), p(2., 1.), p(2., 0.)]), + let poly2 = Polygon::new(LineString(vec![p(2., 0.), p(3., 0.), p(3., 1.), p(2., 1.), + p(2., 0.)]), Vec::new()); let multipoly = MultiPolygon(vec![poly1, poly2]); assert!(multipoly.contains_point(&Point::new(0.5, 0.5))); @@ -250,9 +251,11 @@ mod test { #[test] fn empty_multipolygon_two_polygons_and_inner_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly1 = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), - vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 1.)])]); - let poly2 = Polygon::new(LineString(vec![p(9., 0.), p(14., 0.), p(14., 4.), p(9., 4.), p(9., 0.)]), + let poly1 = + Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), + vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 1.)])]); + let poly2 = Polygon::new(LineString(vec![p(9., 0.), p(14., 0.), p(14., 4.), p(9., 4.), + p(9., 0.)]), Vec::new()); let multipoly = MultiPolygon(vec![poly1, poly2]); @@ -284,8 +287,10 @@ mod test { fn linestring_in_inner_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), - vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])]); + let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), + p(0., 0.)]), + vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), + p(1., 4.), p(1., 1.)])]); assert!(!poly.contains_line_string(&LineString(vec![p(2., 2.), p(3., 3.)]))); assert!(!poly.contains_line_string(&LineString(vec![p(2., 2.), p(2., 5.)]))); assert!(!poly.contains_line_string(&LineString(vec![p(3., 0.5), p(3., 5.)]))); diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 3c2a8d0bb..fa008f43c 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -6,9 +6,9 @@ use traits::{PointTrait, LineStringTrait, PolygonTrait}; use num_traits::pow::pow; pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PointTrait + ?Sized, - P2: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized { let (dx, dy) = (point1.x() - point2.x(), point1.y() - point2.y()); dx.hypot(dy) @@ -26,10 +26,10 @@ pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T // falls on the line past one end or the other of the segment. In that case the // distance to the segment will be the distance to the nearer end pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, end: &'a P3) -> T - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PointTrait + ?Sized, P2: 'a + PointTrait + ?Sized, - P3: 'a + PointTrait + ?Sized, + P3: 'a + PointTrait + ?Sized { let dist_squared = pow(start.distance_to_point(end), 2); // Implies that start == end @@ -38,8 +38,9 @@ pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, en } // Consider the line extending the segment, parameterized as start + t (end - start) // We find the projection of the point onto the line - // This falls where t = [(point - start) . (end - start)] / |end - start|^2, where . is the dot product - // We constrain t to a 0, 1 interval to handle points outside the segment start, end + // This falls where t = [(point - start) . (end - start)] / |end - start|^2, where . is the + // dot product We constrain t to a 0, 1 interval to handle points outside the segment start, + // end let t = T::zero().max(T::one().min(point.sub(start).dot(&end.sub(start)) / dist_squared)); let projected = Point::new(start.x() + t * (end.x() - start.x()), start.y() + t * (end.y() - start.y())); @@ -48,32 +49,32 @@ pub fn line_segment_distance<'a, P1, P2, P3, T>(point: &'a P1, start: &'a P2, en #[derive(PartialEq, Debug)] struct Mindist - where T: Float + where T: Float { distance: T, } // These impls give us a min-heap when used with BinaryHeap impl Ord for Mindist - where T: Float + where T: Float { fn cmp(&self, other: &Mindist) -> Ordering { other.distance.partial_cmp(&self.distance).unwrap() } } impl PartialOrd for Mindist - where T: Float + where T: Float { fn partial_cmp(&self, other: &Mindist) -> Option { Some(self.cmp(other)) } } -impl Eq for Mindist where T: Float {} +impl Eq for Mindist where T: Float {} // Minimum distance from a Point to a Polygon pub fn polygon_to_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> T - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PolygonTrait<'a, T> + ?Sized, - P2: 'a + PointTrait + ?Sized, + P2: 'a + PointTrait + ?Sized { // get exterior ring // exterior ring as a LineString @@ -100,9 +101,9 @@ pub fn polygon_to_point<'a, P1, P2, T>(polygon: &'a P1, point: &'a P2) -> T // Minimum distance from a Point to a LineString pub fn line_string_to_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> T - where T: 'a + Float , + where T: 'a + Float, L: 'a + LineStringTrait<'a, T> + ?Sized, - P: 'a + PointTrait + ?Sized, + P: 'a + PointTrait + ?Sized { // No need to continue if the point is on the LineString, or it's empty if line_string.contains_point(point) || line_string.points().next().is_none() { @@ -123,7 +124,7 @@ pub fn line_string_to_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> T #[cfg(test)] mod test { use types::{Point, LineString, Polygon}; - use algorithm::distance::{line_segment_distance}; + use algorithm::distance::line_segment_distance; use test_helpers::within_epsilon; use traits::PointTrait; @@ -205,47 +206,25 @@ mod test { // Point to Polygon with an interior ring fn point_polygon_interior_cutout_test() { // an octagon - let ext_points = vec![ - (4., 1.), - (5., 2.), - (5., 3.), - (4., 4.), - (3., 4.), - (2., 3.), - (2., 2.), - (3., 1.), - (4., 1.), - ]; + let ext_points = vec![(4., 1.), (5., 2.), (5., 3.), (4., 4.), (3., 4.), (2., 3.), + (2., 2.), (3., 1.), (4., 1.)]; // cut out a triangle inside octagon - let int_points = vec![ - (3.5, 3.5), - (4.4, 1.5), - (2.6, 1.5), - (3.5, 3.5) - ]; + let int_points = vec![(3.5, 3.5), (4.4, 1.5), (2.6, 1.5), (3.5, 3.5)]; let ls_ext = LineString(ext_points.iter().map(|e| Point::new(e.0, e.1)).collect()); let ls_int = LineString(int_points.iter().map(|e| Point::new(e.0, e.1)).collect()); let poly = Polygon::new(ls_ext, vec![ls_int]); // A point inside the cutout triangle let p = Point::new(3.5, 2.5); let dist = p.distance_to_polygon(&poly); - // 0.41036467732879783 <-- Shapely + // 0.41036467732879783 <-- Shapely assert!(within_epsilon(dist, 0.41036467732879767, 1.0e-15)); } #[test] // Point to LineString fn point_linestring_distance_test() { // like an octagon, but missing the lowest horizontal segment - let points = vec![ - (5., 1.), - (4., 2.), - (4., 3.), - (5., 4.), - (6., 4.), - (7., 3.), - (7., 2.), - (6., 1.), - ]; + let points = vec![(5., 1.), (4., 2.), (4., 3.), (5., 4.), (6., 4.), (7., 3.), (7., 2.), + (6., 1.)]; let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); // A Random point "inside" the LineString let p = Point::new(5.5, 2.1); @@ -256,16 +235,8 @@ mod test { // Point to LineString, point lies on the LineString fn point_linestring_contains_test() { // like an octagon, but missing the lowest horizontal segment - let points = vec![ - (5., 1.), - (4., 2.), - (4., 3.), - (5., 4.), - (6., 4.), - (7., 3.), - (7., 2.), - (6., 1.), - ]; + let points = vec![(5., 1.), (4., 2.), (4., 3.), (5., 4.), (6., 4.), (7., 3.), (7., 2.), + (6., 1.)]; let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); // A point which lies on the LineString let p = Point::new(5.0, 4.0); @@ -275,12 +246,7 @@ mod test { #[test] // Point to LineString, closed triangle fn point_linestring_triangle_test() { - let points = vec![ - (3.5, 3.5), - (4.4, 2.0), - (2.6, 2.0), - (3.5, 3.5) - ]; + let points = vec![(3.5, 3.5), (4.4, 2.0), (2.6, 2.0), (3.5, 3.5)]; let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect()); let p = Point::new(3.5, 2.5); let dist = p.distance_to_line_string(&ls); diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index 6a3e2175e..bc97e95ac 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -1,12 +1,16 @@ use num_traits::Float; use traits::{LineStringTrait, PolygonTrait, PointTrait}; -pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, line_string2: &'a L2) -> bool - where T: 'a + Float , +pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, + line_string2: &'a L2) + -> bool + where T: 'a + Float, L1: 'a + LineStringTrait<'a, T> + ?Sized, - L2: 'a + LineStringTrait<'a, T> + ?Sized, + L2: 'a + LineStringTrait<'a, T> + ?Sized { - // See: https://github.com/brandonxiang/geojson-python-utils/blob/33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py + // See: https://github.com/brandonxiang/geojson-python-utils/blob/ + // 33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py + // // TODO: remove `collect` let vect0 = line_string1.points().collect::>(); let vect1 = line_string2.points().collect::>(); @@ -35,39 +39,42 @@ pub fn line_string_intersects_line_string<'a, L1, L2, T>(line_string1: &'a L1, l } pub fn polygon_intersects_line_string<'a, P, L, T>(polygon: &'a P, line_string: &'a L) -> bool - where T: 'a + Float , + where T: 'a + Float, P: 'a + PolygonTrait<'a, T> + ?Sized, - L: 'a + LineStringTrait<'a, T> + ?Sized, + L: 'a + LineStringTrait<'a, T> + ?Sized { let mut rings = polygon.rings(); let exterior_ring = rings.next().expect("no outer ring"); // line intersects inner or outer polygon edge - if exterior_ring.intersects_line_string(line_string) || rings.any(|inner| inner.intersects_line_string(line_string)) { + if exterior_ring.intersects_line_string(line_string) || + rings.any(|inner| inner.intersects_line_string(line_string)) { return true; } else { // or if it's contained in the polygon - return line_string.points().any(|point| polygon.contains_point(point)) + return line_string.points().any(|point| polygon.contains_point(point)); } } /* impl Intersects> for Bbox - where T: Float + where T: Float { fn intersects(&self, bbox: &Bbox) -> bool { // line intersects inner or outer polygon edge if bbox.contains_point(&self) { return false } else { - (self.xmin >= bbox.xmin && self.xmin <= bbox.xmax || self.xmax >= bbox.xmin && self.xmax <= bbox.xmax) && - (self.ymin >= bbox.ymin && self.ymin <= bbox.ymax || self.ymax >= bbox.ymin && self.ymax <= bbox.ymax) + (self.xmin >= bbox.xmin && self.xmin <= bbox.xmax + || self.xmax >= bbox.xmin && self.xmax <= bbox.xmax) && + (self.ymin >= bbox.ymin && self.ymin <= bbox.ymax + || self.ymax >= bbox.ymin && self.ymax <= bbox.ymax) } } } impl Intersects> for Bbox - where T: Float + where T: Float { fn intersects(&self, polygon: &Polygon) -> bool { polygon.intersects(self) @@ -75,7 +82,7 @@ impl Intersects> for Bbox } impl Intersects> for Polygon - where T: Float + where T: Float { fn intersects(&self, bbox: &Bbox) -> bool { let p = Polygon::new(LineString(vec![Point::new(bbox.xmin, bbox.ymin), @@ -90,9 +97,9 @@ impl Intersects> for Polygon */ pub fn polygon_intersects_polygon<'a, P1, P2, T>(polygon1: &'a P1, polygon2: &'a P2) -> bool - where T: 'a + Float , + where T: 'a + Float, P1: 'a + PolygonTrait<'a, T> + ?Sized, - P2: 'a + PolygonTrait<'a, T> + ?Sized, + P2: 'a + PolygonTrait<'a, T> + ?Sized { let mut polygon1_rings = polygon1.rings(); let polygon1_exterior_ring = polygon1_rings.next().expect("no outer ring"); @@ -102,7 +109,9 @@ pub fn polygon_intersects_polygon<'a, P1, P2, T>(polygon1: &'a P1, polygon2: &'a // self intersects (or contains) any line in polygon polygon1.intersects_line_string(polygon2_exterior_ring) || - polygon2_rings.any(|inner_line_string| polygon1.intersects_line_string(inner_line_string)) || + polygon2_rings.any(|inner_line_string| { + polygon1.intersects_line_string(inner_line_string) + }) || // self is contained inside polygon polygon2.intersects_line_string(polygon1_exterior_ring) } @@ -151,7 +160,8 @@ mod test { #[test] fn linestring_on_boundary_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), + let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), + p(0., 0.)]), Vec::new()); assert!(poly.intersects_line_string(&LineString(vec![p(0., 0.), p(5., 0.)]))); assert!(poly.intersects_line_string(&LineString(vec![p(5., 0.), p(5., 6.)]))); @@ -161,14 +171,16 @@ mod test { #[test] fn intersect_linestring_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), + let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), + p(0., 0.)]), Vec::new()); assert!(poly.intersects_line_string(&LineString(vec![p(2., 2.), p(6., 6.)]))); } #[test] fn linestring_outside_polygon_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]), + let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), + p(0., 0.)]), Vec::new()); assert!(!poly.intersects_line_string(&LineString(vec![p(7., 2.), p(9., 4.)]))); } @@ -228,10 +240,15 @@ mod test { #[test] fn polygons_do_not_intersect() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), p(1., 3.)]), - Vec::new()); - let p2 = Polygon::new(LineString(vec![p(10., 30.), p(30., 30.), p(30., 50.), p(10., 50.), p(10., 30.)]), - Vec::new()); + let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), + p(1., 3.)]), + Vec::new()); + let p2 = Polygon::new(LineString(vec![p(10., 30.), + p(30., 30.), + p(30., 50.), + p(10., 50.), + p(10., 30.)]), + Vec::new()); assert!(!p1.intersects_polygon(&p2)); assert!(!p2.intersects_polygon(&p1)); @@ -239,10 +256,12 @@ mod test { #[test] fn polygons_overlap() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), p(1., 3.)]), - Vec::new()); - let p2 = Polygon::new(LineString(vec![p(2., 3.), p(4., 3.), p(4., 7.), p(2., 7.), p(2., 3.)]), - Vec::new()); + let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), + p(1., 3.)]), + Vec::new()); + let p2 = Polygon::new(LineString(vec![p(2., 3.), p(4., 3.), p(4., 7.), p(2., 7.), + p(2., 3.)]), + Vec::new()); assert!(p1.intersects_polygon(&p2)); assert!(p2.intersects_polygon(&p1)); @@ -250,10 +269,12 @@ mod test { #[test] fn polygon_contained() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]), - Vec::new()); - let p2 = Polygon::new(LineString(vec![p(2., 4.), p(3., 4.), p(3., 5.), p(2., 5.), p(2., 4.)]), - Vec::new()); + let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), + p(1., 3.)]), + Vec::new()); + let p2 = Polygon::new(LineString(vec![p(2., 4.), p(3., 4.), p(3., 5.), p(2., 5.), + p(2., 4.)]), + Vec::new()); assert!(p1.intersects_polygon(&p2)); assert!(p2.intersects_polygon(&p1)); @@ -261,10 +282,12 @@ mod test { #[test] fn polygons_conincident() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]), - Vec::new()); - let p2 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]), - Vec::new()); + let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), + p(1., 3.)]), + Vec::new()); + let p2 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), + p(1., 3.)]), + Vec::new()); assert!(p1.intersects_polygon(&p2)); assert!(p2.intersects_polygon(&p1)); @@ -292,8 +315,9 @@ mod test { // └──────────────────────┘ // (0,0) (12,0) let p = |x, y| Point(Coordinate { x: x, y: y }); - let poly = Polygon::new(LineString(vec![p(0., 0.), p(12., 0.), p(12., 8.), p(0., 8.), p(0., 0.)]), - vec![LineString(vec![p(7., 4.), p(11., 4.), p(11., 7.), p(7., 7.), p(7., 4.)])]); + let poly = Polygon::new(LineString( + vec![p(0., 0.), p(12., 0.), p(12., 8.), p(0., 8.), p(0., 0.)]), + vec![LineString(vec![p(7., 4.), p(11., 4.), p(11., 7.), p(7., 7.), p(7., 4.)])]); let b1 = Bbox { xmin: 11.0, xmax: 13.0, ymin: 1.0, ymax: 2.0 }; let b2 = Bbox { xmin: 2.0, xmax: 8.0, ymin: 2.0, ymax: 5.0 }; let b3 = Bbox { xmin: 8.0, xmax: 10.0, ymin: 5.0, ymax: 6.0 }; diff --git a/src/algorithm/length.rs b/src/algorithm/length.rs index ee428a4bb..55a2c2d01 100644 --- a/src/algorithm/length.rs +++ b/src/algorithm/length.rs @@ -2,18 +2,19 @@ use num_traits::Float; use traits::{PointTrait, LineStringTrait, MultiLineStringTrait}; -pub fn line_string<'a, G, T>(line_string: &'a G) -> T - where T: 'a + Float , +pub fn line_string<'a, G, T>(line_string: &'a G) -> T + where T: 'a + Float, G: 'a + LineStringTrait<'a, T> + ?Sized { // FIXME: don't collect let v = line_string.points().collect::>(); v.windows(2) - .fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(p[1])) + .fold(T::zero(), + |total_length, p| total_length + p[0].distance_to_point(p[1])) } -pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T - where T: 'a + Float , +pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T + where T: 'a + Float, G: 'a + MultiLineStringTrait<'a, T> + ?Sized { multi_line_string.lines().fold(T::zero(), |total, line| total + line.length()) @@ -43,7 +44,8 @@ mod test { #[test] fn multilinestring_test() { let p = |x, y| Point(Coordinate { x: x, y: y }); - let mline = MultiLineString(vec![LineString(vec![p(1., 0.), p(7., 0.), p(8., 0.), p(9., 0.), p(10., 0.), p(11., 0.)]), + let mline = MultiLineString(vec![LineString(vec![p(1., 0.), p(7., 0.), p(8., 0.), + p(9., 0.), p(10., 0.), p(11., 0.)]), LineString(vec![p(0., 0.), p(0., 5.)])]); assert_eq!(15.0_f64, mline.length()); } diff --git a/src/algorithm/simplify.rs b/src/algorithm/simplify.rs index 8de18170d..328b9af97 100644 --- a/src/algorithm/simplify.rs +++ b/src/algorithm/simplify.rs @@ -4,7 +4,7 @@ use traits::PointTrait; // perpendicular distance from a point to a line fn point_line_distance(point: &Point, start: &Point, end: &Point) -> T - where T: Float + where T: Float { if start == end { point.distance_to_point(start) @@ -19,7 +19,7 @@ fn point_line_distance(point: &Point, start: &Point, end: &Point) -> // Ramer–Douglas-Peucker line simplification algorithm fn rdp(points: &[Point], epsilon: &T) -> Vec> - where T: Float + where T: Float { if points.is_empty() { return points.to_vec(); @@ -29,9 +29,7 @@ fn rdp(points: &[Point], epsilon: &T) -> Vec> let mut distance: T; for (i, _) in points.iter().enumerate().take(points.len() - 1).skip(1) { - distance = point_line_distance(&points[i], - &points[0], - &*points.last().unwrap()); + distance = point_line_distance(&points[i], &points[0], &*points.last().unwrap()); if distance > dmax { index = i; dmax = distance; @@ -48,7 +46,10 @@ fn rdp(points: &[Point], epsilon: &T) -> Vec> } pub trait Simplify { - /// Returns the simplified representation of a LineString, using the [Ramer–Douglas–Peucker](https://en.wikipedia.org/wiki/Ramer–Douglas–Peucker_algorithm) algorithm + /// Returns the simplified representation of a LineString, using the + /// [Ramer–Douglas–Peucker] + /// (https://en.wikipedia.org/wiki/Ramer–Douglas–Peucker_algorithm) + /// algorithm /// /// ``` /// use geo::{Point, LineString}; @@ -70,11 +71,11 @@ pub trait Simplify { /// let simplified = linestring.simplify(&1.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplify(&self, epsilon: &T) -> Self where T: Float ; + fn simplify(&self, epsilon: &T) -> Self where T: Float; } impl Simplify for LineString - where T: Float + where T: Float { fn simplify(&self, epsilon: &T) -> LineString { LineString(rdp(&self.0, epsilon)) @@ -83,7 +84,7 @@ impl Simplify for LineString #[cfg(test)] mod test { - use types::{Point}; + use types::Point; use super::{point_line_distance, rdp}; use test_helpers::within_epsilon; diff --git a/src/algorithm/simplifyvw.rs b/src/algorithm/simplifyvw.rs index ae0412a9f..b1ae0560b 100644 --- a/src/algorithm/simplifyvw.rs +++ b/src/algorithm/simplifyvw.rs @@ -7,7 +7,7 @@ use types::{Point, LineString}; // #[deriving] doesn't work inside functions. #[derive(PartialEq, Debug)] struct VScore - where T: Float + where T: Float { area: T, current: usize, @@ -17,7 +17,7 @@ struct VScore // These impls give us a min-heap impl Ord for VScore - where T: Float + where T: Float { fn cmp(&self, other: &VScore) -> Ordering { other.area.partial_cmp(&self.area).unwrap() @@ -25,16 +25,17 @@ impl Ord for VScore } impl PartialOrd for VScore - where T: Float + where T: Float { fn partial_cmp(&self, other: &VScore) -> Option { Some(self.cmp(other)) } } -impl Eq for VScore where T: Float {} +impl Eq for VScore where T: Float {} -/// Simplify a line using the [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) algorithm +/// Simplify a line using the +/// [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) algorithm /// /// epsilon is the minimum triangle area // The paper states that: @@ -47,7 +48,7 @@ impl Eq for VScore where T: Float {} // It's OK to remove triangles with areas below the epsilon, // then recalculate the new triangle area and push it onto the heap pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> - where T: Float + where T: Float { // No need to continue without at least three points if orig.len() < 3 || orig.is_empty() { @@ -60,12 +61,10 @@ pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> // linked list with indices into `orig`. Big number (larger than or equal to // `max`) means no next element, and (0, 0) means deleted element. let mut adjacent: Vec<(_)> = (0..orig.len()) - .map(|i| { - if i == 0 { - (-1_i32, 1_i32) - } else { - ((i - 1) as i32, (i + 1) as i32) - } + .map(|i| if i == 0 { + (-1_i32, 1_i32) + } else { + ((i - 1) as i32, (i + 1) as i32) }) .collect(); @@ -132,22 +131,24 @@ pub fn visvalingam(orig: &[Point], epsilon: &T) -> Vec> // Filter out the points that have been deleted, returning remaining points orig.iter() .zip(adjacent.iter()) - .filter_map(|(tup, adj)| { if *adj != (0, 0) { Some(*tup) } else { None } }) + .filter_map(|(tup, adj)| if *adj != (0, 0) { Some(*tup) } else { None }) .collect::>>() } // Area of a triangle given three vertices fn area(p1: &Point, p2: &Point, p3: &Point) -> T - where T: Float + where T: Float { ((p1.x() - p3.x()) * (p2.y() - p3.y()) - (p2.x() - p3.x()) * (p1.y() - p3.y())).abs() / (T::one() + T::one()) } pub trait SimplifyVW { - /// Returns the simplified representation of a LineString, using the [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) algorithm - /// - /// See [here](https://bost.ocks.org/mike/simplify/) for a graphical explanation + /// Returns the simplified representation of a LineString, using the + /// [Visvalingam-Whyatt](http://www.tandfonline.com/doi/abs/10.1179/000870493786962263) + /// algorithm + /// + /// See [here](https://bost.ocks.org/mike/simplify/) for a graphical explanation /// /// ``` /// use geo::{Point, LineString}; @@ -168,11 +169,11 @@ pub trait SimplifyVW { /// let simplified = linestring.simplifyvw(&30.0); /// assert_eq!(simplified, ls_compare) /// ``` - fn simplifyvw(&self, epsilon: &T) -> Self where T: Float ; + fn simplifyvw(&self, epsilon: &T) -> Self where T: Float; } impl SimplifyVW for LineString - where T: Float + where T: Float { fn simplifyvw(&self, epsilon: &T) -> LineString { LineString(visvalingam(&self.0, epsilon)) diff --git a/src/test_helpers.rs b/src/test_helpers.rs index def424633..da36a7a52 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -5,10 +5,7 @@ pub fn within_epsilon(x: F, y: F, epsilon: F) -> bool { let b = y.abs(); let delta = (a - b).abs(); - if a.is_infinite() || - a.is_nan() || - b.is_infinite() || - b.is_nan() { + if a.is_infinite() || a.is_nan() || b.is_infinite() || b.is_nan() { false } else if a == b { true diff --git a/src/traits.rs b/src/traits.rs index c6f09cbd1..694761ecc 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,15 +1,14 @@ -pub use ::Geometry; +pub use Geometry; use num_traits::Float; -pub trait ToGeo -{ +pub trait ToGeo { fn to_geo(&self) -> Geometry; } // FIXME: find good names for these traits, don't use XyzTrait naming scheme -pub trait PointTrait: Sized { +pub trait PointTrait: Sized { fn x(&self) -> T; fn y(&self) -> T; @@ -31,14 +30,16 @@ pub trait PointTrait: Sized { } // TODO: remove N - fn distance_to_line_string<'a, N: 'a + Float , L: LineStringTrait<'a, N>>(&'a self, line_string: &'a L) -> N + fn distance_to_line_string<'a, N: 'a + Float, L: LineStringTrait<'a, N>>(&'a self, + line_string: &'a L) + -> N where Self: PointTrait { ::algorithm::distance::line_string_to_point(line_string, self) } // TODO: remove N - fn distance_to_polygon<'a, N: 'a + Float , P: PolygonTrait<'a, N>>(&'a self, polygon: &'a P) -> N + fn distance_to_polygon<'a, N: 'a + Float, P: PolygonTrait<'a, N>>(&'a self, polygon: &'a P) -> N where Self: PointTrait { ::algorithm::distance::polygon_to_point(polygon, self) @@ -50,10 +51,10 @@ pub trait PointTrait: Sized { } pub trait LineStringTrait<'a, T> - where T: 'a + Float + where T: 'a + Float { type ItemType: 'a + PointTrait; - type Iter: Iterator; + type Iter: Iterator; fn points(&'a self) -> Self::Iter; @@ -76,7 +77,9 @@ pub trait LineStringTrait<'a, T> ::algorithm::distance::line_string_to_point(self, point) } - fn intersects_line_string>(&'a self, line_string: &'a L) -> bool { + fn intersects_line_string>(&'a self, + line_string: &'a L) + -> bool { ::algorithm::intersects::line_string_intersects_line_string(self, line_string) } @@ -86,10 +89,10 @@ pub trait LineStringTrait<'a, T> } pub trait PolygonTrait<'a, T> - where T: 'a + Float , + where T: 'a + Float { type ItemType: 'a + LineStringTrait<'a, T>; - type Iter: 'a + Iterator; + type Iter: 'a + Iterator; fn rings(&'a self) -> Self::Iter; @@ -125,19 +128,19 @@ pub trait PolygonTrait<'a, T> } pub trait MultiPointTrait<'a, T> - where T: 'a + Float , + where T: 'a + Float { type ItemType: 'a + PointTrait; - type Iter: Iterator; + type Iter: Iterator; fn points(&'a self) -> Self::Iter; } pub trait MultiLineStringTrait<'a, T> - where T: 'a + Float , + where T: 'a + Float { type ItemType: 'a + LineStringTrait<'a, T>; - type Iter: Iterator; + type Iter: Iterator; fn lines(&'a self) -> Self::Iter; @@ -148,10 +151,10 @@ pub trait MultiLineStringTrait<'a, T> } pub trait MultiPolygonTrait<'a, T> - where T: 'a + Float , + where T: 'a + Float { type ItemType: 'a + PolygonTrait<'a, T>; - type Iter: Iterator; + type Iter: Iterator; fn polygons(&'a self) -> Self::Iter; diff --git a/src/types.rs b/src/types.rs index 94194c48c..17d6cb9cb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -9,7 +9,7 @@ pub static COORD_PRECISION: f32 = 1e-1; // 0.1m #[derive(PartialEq, Clone, Copy, Debug)] pub struct Coordinate - where T: Float + where T: Float { pub x: T, pub y: T, @@ -17,7 +17,7 @@ pub struct Coordinate #[derive(PartialEq, Clone, Copy, Debug)] pub struct Bbox - where T: Float + where T: Float { pub xmin: T, pub xmax: T, @@ -44,11 +44,25 @@ impl<'a, T: 'a + Float > ::PolygonTrait<'a, T> for Bbox { } */ + + + + + + + + + + + + + + #[derive(PartialEq, Clone, Copy, Debug)] -pub struct Point (pub Coordinate) where T: Float ; +pub struct Point(pub Coordinate) where T: Float; impl Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive { /// Creates a new point. /// @@ -191,7 +205,7 @@ impl Point } impl Neg for Point - where T: Float + Neg + ToPrimitive + where T: Float + Neg + ToPrimitive { type Output = Point; @@ -211,7 +225,7 @@ impl Neg for Point } impl Add for Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive { type Output = Point; @@ -231,7 +245,7 @@ impl Add for Point } impl Sub for Point - where T: Float + ToPrimitive + where T: Float + ToPrimitive { type Output = Point; @@ -250,7 +264,7 @@ impl Sub for Point } } -impl ::PointTrait for Point { +impl ::PointTrait for Point { fn x(&self) -> T { self.x() } @@ -261,7 +275,7 @@ impl ::PointTrait for Point { } impl Add for Bbox - where T: Float + ToPrimitive + where T: Float + ToPrimitive { type Output = Bbox; @@ -280,17 +294,33 @@ impl Add for Bbox /// assert_eq!(1000., bbox.ymax); /// ``` fn add(self, rhs: Bbox) -> Bbox { - Bbox{ - xmin: if self.xmin <= rhs.xmin {self.xmin} else {rhs.xmin}, - xmax: if self.xmax >= rhs.xmax {self.xmax} else {rhs.xmax}, - ymin: if self.ymin <= rhs.ymin {self.ymin} else {rhs.ymin}, - ymax: if self.ymax >= rhs.ymax {self.ymax} else {rhs.ymax}, + Bbox { + xmin: if self.xmin <= rhs.xmin { + self.xmin + } else { + rhs.xmin + }, + xmax: if self.xmax >= rhs.xmax { + self.xmax + } else { + rhs.xmax + }, + ymin: if self.ymin <= rhs.ymin { + self.ymin + } else { + rhs.ymin + }, + ymax: if self.ymax >= rhs.ymax { + self.ymax + } else { + rhs.ymax + }, } } } impl AddAssign for Bbox - where T: Float + ToPrimitive + where T: Float + ToPrimitive { /// Add a boundingox to the given boundingbox. /// @@ -306,21 +336,37 @@ impl AddAssign for Bbox /// assert_eq!(10., bbox0.ymin); /// assert_eq!(1000., bbox0.ymax); /// ``` - fn add_assign(&mut self, rhs: Bbox){ - self.xmin = if self.xmin <= rhs.xmin {self.xmin} else {rhs.xmin}; - self.xmax = if self.xmax >= rhs.xmax {self.xmax} else {rhs.xmax}; - self.ymin = if self.ymin <= rhs.ymin {self.ymin} else {rhs.ymin}; - self.ymax = if self.ymax >= rhs.ymax {self.ymax} else {rhs.ymax}; + fn add_assign(&mut self, rhs: Bbox) { + self.xmin = if self.xmin <= rhs.xmin { + self.xmin + } else { + rhs.xmin + }; + self.xmax = if self.xmax >= rhs.xmax { + self.xmax + } else { + rhs.xmax + }; + self.ymin = if self.ymin <= rhs.ymin { + self.ymin + } else { + rhs.ymin + }; + self.ymax = if self.ymax >= rhs.ymax { + self.ymax + } else { + rhs.ymax + }; } } #[derive(PartialEq, Clone, Debug)] -pub struct MultiPoint(pub Vec>) where T: Float ; +pub struct MultiPoint(pub Vec>) where T: Float; -impl<'a, T: 'a + Float > ::MultiPointTrait<'a, T> for MultiPoint { +impl<'a, T: 'a + Float> ::MultiPointTrait<'a, T> for MultiPoint { type ItemType = Point; - type Iter = Box + 'a>; + type Iter = Box + 'a>; fn points(&'a self) -> Self::Iter { Box::new(self.0.iter()) @@ -328,11 +374,11 @@ impl<'a, T: 'a + Float > ::MultiPointTrait<'a, T> for MultiPoint { } #[derive(PartialEq, Clone, Debug)] -pub struct LineString(pub Vec>) where T: Float ; +pub struct LineString(pub Vec>) where T: Float; -impl<'a, T: 'a + Float > ::LineStringTrait<'a, T> for LineString { +impl<'a, T: 'a + Float> ::LineStringTrait<'a, T> for LineString { type ItemType = Point; - type Iter = Box + 'a>; + type Iter = Box + 'a>; fn points(&'a self) -> Self::Iter { Box::new(self.0.iter()) @@ -340,11 +386,11 @@ impl<'a, T: 'a + Float > ::LineStringTrait<'a, T> for LineString { } #[derive(PartialEq, Clone, Debug)] -pub struct MultiLineString(pub Vec>) where T: Float ; +pub struct MultiLineString(pub Vec>) where T: Float; -impl<'a, T: 'a + Float > ::MultiLineStringTrait<'a, T> for MultiLineString { +impl<'a, T: 'a + Float> ::MultiLineStringTrait<'a, T> for MultiLineString { type ItemType = LineString; - type Iter = Box + 'a>; + type Iter = Box + 'a>; fn lines(&'a self) -> Self::Iter { Box::new(self.0.iter()) @@ -353,14 +399,14 @@ impl<'a, T: 'a + Float > ::MultiLineStringTrait<'a, T> for MultiLineString { #[derive(PartialEq, Clone, Debug)] pub struct Polygon - where T: Float + where T: Float { pub exterior: LineString, - pub interiors: Vec> + pub interiors: Vec>, } impl Polygon - where T: Float + where T: Float { /// Creates a new polygon. /// @@ -376,27 +422,29 @@ impl Polygon /// assert_eq!(p.interiors, interiors); /// ``` pub fn new(exterior: LineString, interiors: Vec>) -> Polygon { - Polygon { exterior: exterior, interiors: interiors } + Polygon { + exterior: exterior, + interiors: interiors, + } } } -impl<'a, T: 'a + Float > ::PolygonTrait<'a, T> for Polygon { +impl<'a, T: 'a + Float> ::PolygonTrait<'a, T> for Polygon { type ItemType = LineString; - type Iter = Box + 'a>; + type Iter = Box + 'a>; fn rings(&'a self) -> Self::Iter { - let iter = ::std::iter::once(&self.exterior) - .chain(self.interiors.iter()); + let iter = ::std::iter::once(&self.exterior).chain(self.interiors.iter()); Box::new(iter) } } #[derive(PartialEq, Clone, Debug)] -pub struct MultiPolygon(pub Vec>) where T: Float ; +pub struct MultiPolygon(pub Vec>) where T: Float; -impl<'a, T: 'a + Float > ::MultiPolygonTrait<'a, T> for MultiPolygon { +impl<'a, T: 'a + Float> ::MultiPolygonTrait<'a, T> for MultiPolygon { type ItemType = Polygon; - type Iter = Box + 'a>; + type Iter = Box + 'a>; fn polygons(&'a self) -> Self::Iter { Box::new(self.0.iter()) @@ -404,11 +452,11 @@ impl<'a, T: 'a + Float > ::MultiPolygonTrait<'a, T> for MultiPolygon { } #[derive(PartialEq, Clone, Debug)] -pub struct GeometryCollection(pub Vec>) where T: Float ; +pub struct GeometryCollection(pub Vec>) where T: Float; #[derive(PartialEq, Clone, Debug)] pub enum Geometry - where T: Float + where T: Float { Point(Point), LineString(LineString), @@ -416,7 +464,7 @@ pub enum Geometry MultiPoint(MultiPoint), MultiLineString(MultiLineString), MultiPolygon(MultiPolygon), - GeometryCollection(GeometryCollection) + GeometryCollection(GeometryCollection), } #[cfg(test)] @@ -440,10 +488,14 @@ mod test { #[test] fn polygon_new_test() { - let exterior = LineString(vec![Point::new(0., 0.), Point::new(1., 1.), - Point::new(1., 0.), Point::new(0., 0.)]); - let interiors = vec![LineString(vec![Point::new(0.1, 0.1), Point::new(0.9, 0.9), - Point::new(0.9, 0.1), Point::new(0.1, 0.1)])]; + let exterior = LineString(vec![Point::new(0., 0.), + Point::new(1., 1.), + Point::new(1., 0.), + Point::new(0., 0.)]); + let interiors = vec![LineString(vec![Point::new(0.1, 0.1), + Point::new(0.9, 0.9), + Point::new(0.9, 0.1), + Point::new(0.1, 0.1)])]; let p = Polygon::new(exterior.clone(), interiors.clone()); assert_eq!(p.exterior, exterior);