Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Polygon struct parameters #68

Merged
4 commits merged into from
Oct 16, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Document Polygon struct parameters
Addresses #60

Replaces the Polygon tuple struct with a regular struct:

```
pub struct Polygon<T>
    where T: Float
{
    pub exterior: LineString<T>,
    pub interiors: Vec<LineString<T>>
}
```

I'm new to rust and eager to learn so comment away!

This breaks the existing Polygon constructor since (correct me if
I'm wrong) structs must be instaniated with curly braces and named
arguments. To mitigate the effect of this change on existing code,
`Polygon` implements a `new` method that preserve the old interface:

`Polygon::new(exterior, interiors)`

I choose `exterior` and `interiors` over `outer` and `inners` as I
believe the former pair is more commonly used. I don't feel strongly
about this choice and will change it upon request.
  • Loading branch information
mbattifarano committed Oct 8, 2016
commit 9ed14199c6ce1893af07720f69d5a192e9d17b14
29 changes: 16 additions & 13 deletions src/algorithm/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait Area<T> where T: Float
/// 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(linestring, v);
/// let poly = Polygon::new(linestring, v);
/// assert_eq!(poly.area(), 30.);
/// ```
fn area(&self) -> T;
Expand All @@ -36,8 +36,8 @@ impl<T> Area<T> for Polygon<T>
where T: Float
{
fn area(&self) -> T {
self.1.iter().fold(get_linestring_area(&self.0),
|total, next| total - get_linestring_area(next))
self.interiors.iter().fold(get_linestring_area(&self.exterior),
|total, next| total - get_linestring_area(next))
}
}

Expand All @@ -64,20 +64,20 @@ mod test {
// Area of the polygon
#[test]
fn area_empty_polygon_test() {
let poly = Polygon::<f64>(LineString(Vec::new()), Vec::new());
let poly = Polygon::<f64>::new(LineString(Vec::new()), Vec::new());
assert_eq!(poly.area(), 0.);
}

#[test]
fn area_one_point_polygon_test() {
let poly = Polygon(LineString(vec![Point::new(1., 0.)]), Vec::new());
let poly = Polygon::new(LineString(vec![Point::new(1., 0.)]), Vec::new());
assert_eq!(poly.area(), 0.);
}
#[test]
fn area_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 poly = Polygon(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert_eq!(poly.area(), 30.);
}
#[test]
Expand All @@ -91,18 +91,21 @@ mod test {
let outer = LineString(vec![p(0., 0.), p(10., 0.), p(10., 10.), p(0., 10.), p(0., 0.)]);
let inner0 = LineString(vec![p(1., 1.), p(2., 1.), p(2., 2.), p(1., 2.), p(1., 1.)]);
let inner1 = LineString(vec![p(5., 5.), p(6., 5.), p(6., 6.), p(5., 6.), p(5., 5.)]);
let poly = Polygon(outer, vec![inner0, inner1]);
let poly = Polygon::new(outer, vec![inner0, inner1]);
assert_eq!(poly.area(), 98.);
}
#[test]
fn area_multipolygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly0 = Polygon(LineString(vec![p(0., 0.), p(10., 0.), p(10., 10.), p(0., 10.), p(0., 0.)]),
Vec::new());
let poly1 = Polygon(LineString(vec![p(1., 1.), p(2., 1.), p(2., 2.), p(1., 2.), p(1., 1.)]),
Vec::new());
let poly2 = Polygon(LineString(vec![p(5., 5.), p(6., 5.), p(6., 6.), p(5., 6.), p(5., 5.)]),
Vec::new());
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.),
p(1., 1.)]),
Vec::new());
let poly2 = Polygon::new(LineString(vec![p(5., 5.), p(6., 5.), p(6., 6.), p(5., 6.),
p(5., 5.)]),
Vec::new());
let mpoly = MultiPolygon(vec![poly0, poly1, poly2]);
assert_eq!(mpoly.area(), 102.);
}
Expand Down
12 changes: 6 additions & 6 deletions src/algorithm/boundingbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl<T> BoundingBox<T> for Polygon<T>
/// Return the BoundingBox for a Polygon
///
fn bbox(&self) -> Option<Bbox<T>> {
let line = &self.0;
let line = &self.exterior;
get_bbox(&line.0)
}
}
Expand All @@ -106,7 +106,7 @@ impl<T> BoundingBox<T> for MultiPolygon<T>
/// Return the BoundingBox for a MultiPolygon
///
fn bbox(&self) -> Option<Bbox<T>> {
get_bbox(self.0.iter().flat_map(|poly| (poly.0).0.iter()))
get_bbox(self.0.iter().flat_map(|poly| (poly.exterior).0.iter()))
}
}

Expand Down Expand Up @@ -162,15 +162,15 @@ 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 line_bbox = linestring.bbox().unwrap();
let poly = Polygon(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert_eq!(line_bbox, poly.bbox().unwrap());
}
#[test]
fn multipolygon_test(){
let p = |x, y| Point(Coordinate { x: x, y: y });
let mpoly = MultiPolygon(vec![Polygon(LineString(vec![p(0., 0.), p(50., 0.), p(0., -70.), p(0., 0.)]), Vec::new()),
Polygon(LineString(vec![p(0., 0.), p(5., 0.), p(0., 80.), p(0., 0.)]), Vec::new()),
Polygon(LineString(vec![p(0., 0.), p(-60., 0.), p(0., 6.), p(0., 0.)]), Vec::new()),
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());
Expand Down
14 changes: 7 additions & 7 deletions src/algorithm/centroid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl<T> Centroid<T> for Polygon<T>
///
fn centroid(&self) -> Option<Point<T>> {
// TODO: consideration of inner polygons;
let linestring = &self.0;
let linestring = &self.exterior;
let vect = &linestring.0;
if vect.is_empty() {
return None;
Expand Down Expand Up @@ -156,23 +156,23 @@ mod test {
let v1 = Vec::new();
let v2 = Vec::new();
let linestring = LineString::<f64>(v1);
let poly = Polygon(linestring, v2);
let poly = Polygon::new(linestring, v2);
assert!(poly.centroid().is_none());
}
#[test]
fn polygon_one_point_test() {
let p = Point(Coordinate { x: 2., y: 1. });
let v = Vec::new();
let linestring = LineString(vec![p]);
let poly = Polygon(linestring, v);
let poly = Polygon::new(linestring, v);
assert_eq!(poly.centroid(), Some(p));
}
#[test]
fn polygon_test() {
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(linestring, v);
let poly = Polygon::new(linestring, v);
assert_eq!(poly.centroid(), Some(p(1., 1.)));
}
/// Tests: Centroid of MultiPolygon
Expand All @@ -184,16 +184,16 @@ mod test {
fn multipolygon_one_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(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert_eq!(MultiPolygon(vec![poly]).centroid(), Some(p(1., 1.)));
}
#[test]
fn multipolygon_two_polygons_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(2., 1.), p(5., 1.), p(5., 3.), p(2., 3.), p(2., 1.)]);
let poly1 = Polygon(linestring, Vec::new());
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(linestring, Vec::new());
let poly2 = Polygon::new(linestring, Vec::new());
let dist = MultiPolygon(vec![poly1, poly2]).centroid().unwrap().distance(&p(4.07142857142857, 1.92857142857143));
assert!(dist < COORD_PRECISION);
}
Expand Down
49 changes: 22 additions & 27 deletions src/algorithm/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub trait Contains<Rhs = Self> {
/// 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(linestring.clone(), v);
/// let poly = Polygon::new(linestring.clone(), v);
///
/// //Point in Point
/// assert!(p(2., 0.).contains(&p(2., 0.)));
Expand Down Expand Up @@ -123,10 +123,10 @@ impl<T> Contains<Point<T>> for Polygon<T>
where T: Float
{
fn contains(&self, p: &Point<T>) -> bool {
match get_position(p, &self.0) {
match get_position(p, &self.exterior) {
PositionPoint::OnBoundary => false,
PositionPoint::Outside => false,
_ => self.1.iter().all(|ls| get_position(p, ls) == PositionPoint::Outside),
_ => self.interiors.iter().all(|ls| get_position(p, ls) == PositionPoint::Outside),
}
}
}
Expand Down Expand Up @@ -188,26 +188,26 @@ mod test {
#[test]
fn empty_polygon_test() {
let linestring = LineString(Vec::new());
let poly = Polygon(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert!(!poly.contains(&Point::new(2., 1.)));
}
#[test]
fn polygon_with_one_point_test() {
let linestring = LineString(vec![Point::new(2., 1.)]);
let poly = Polygon(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert!(!poly.contains(&Point::new(3., 1.)));
}
#[test]
fn polygon_with_one_point_is_vertex_test() {
let linestring = LineString(vec![Point::new(2., 1.)]);
let poly = Polygon(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert!(!poly.contains(&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(linestring, Vec::new());
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.)));
Expand All @@ -217,14 +217,14 @@ mod 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(linestring, Vec::new());
let poly = Polygon::new(linestring, Vec::new());
assert!(poly.contains(&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(linestring, Vec::new());
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)));
Expand All @@ -238,7 +238,7 @@ mod test {
p(1.5, 1.5),
p(0.0, 1.5),
p(0.0, 0.0)]);
let poly = Polygon(linestring, vec![inner_linestring]);
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)));
Expand All @@ -253,12 +253,10 @@ mod test {
#[test]
fn empty_multipolygon_two_polygons_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly1 = Polygon(LineString(vec![p(0., 0.), p(1., 0.), p(1., 1.), p(0., 1.),
p(0., 0.)]),
Vec::new());
let poly2 = Polygon(LineString(vec![p(2., 0.), p(3., 0.), p(3., 1.), p(2., 1.),
p(2., 0.)]),
Vec::new());
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.)]),
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)));
Expand All @@ -267,12 +265,10 @@ mod test {
#[test]
fn empty_multipolygon_two_polygons_and_inner_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly1 = Polygon(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(LineString(vec![p(9., 0.), p(14., 0.), p(14., 4.), p(9., 4.),
p(9., 0.)]),
Vec::new());
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]);
assert!(multipoly.contains(&Point::new(3., 5.)));
Expand All @@ -285,7 +281,7 @@ mod test {
fn linestring_in_polygon_with_linestring_is_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(linestring.clone(), Vec::new());
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.)])));
Expand All @@ -295,17 +291,16 @@ mod 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(linestring, Vec::new());
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.)])));
}
#[test]
fn linestring_in_inner_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });

let poly = Polygon(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(&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.)])));
Expand Down
16 changes: 8 additions & 8 deletions src/algorithm/distance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub trait Distance<T, Rhs = Self> {
/// (5., 1.)
/// ];
/// let ls = LineString(points.iter().map(|e| Point::new(e.0, e.1)).collect());
/// let poly = Polygon(ls, vec![]);
/// 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);
Expand Down Expand Up @@ -130,7 +130,7 @@ impl<T> Distance<T, Polygon<T>> for Point<T>
{
fn distance(&self, polygon: &Polygon<T>) -> T {
// get exterior ring
let exterior = &polygon.0;
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
Expand All @@ -140,7 +140,7 @@ impl<T> Distance<T, Polygon<T>> for Point<T>
// minimum priority queue
let mut dist_queue: BinaryHeap<Mindist<T>> = BinaryHeap::new();
// we've got interior rings
for ring in &polygon.1 {
for ring in &polygon.interiors {
dist_queue.push(Mindist { distance: self.distance(ring) })
}
for chunk in ext_ring.windows(2) {
Expand Down Expand Up @@ -206,7 +206,7 @@ mod test {
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(ls, vec![]);
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);
Expand All @@ -219,7 +219,7 @@ mod test {
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(ls, vec![]);
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);
Expand All @@ -232,7 +232,7 @@ mod test {
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(ls, vec![]);
let poly = Polygon::new(ls, vec![]);
// A point on the octagon
let p = Point::new(5.0, 1.0);
let dist = p.distance(&poly);
Expand All @@ -244,7 +244,7 @@ mod test {
// an empty Polygon
let points = vec![];
let ls = LineString(points);
let poly = Polygon(ls, vec![]);
let poly = Polygon::new(ls, vec![]);
// A point on the octagon
let p = Point::new(2.5, 0.5);
let dist = p.distance(&poly);
Expand Down Expand Up @@ -274,7 +274,7 @@ mod test {
];
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(ls_ext, vec![ls_int]);
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);
Expand Down
Loading