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

Trait-based geometry types (no cost abstractions!) WIP. #85

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
04c96e9
Add traits for each geometry type.
frewsxcv Jan 15, 2017
7e7731f
Rename traits to differentiate for now.
frewsxcv Jan 15, 2017
2e00a1a
Beginning of an area implementation.
frewsxcv Jan 15, 2017
a177188
Make traits float-generic, not based on f64.
frewsxcv Jan 15, 2017
4099e98
Remove opt_foo for now
frewsxcv Jan 15, 2017
e35f977
Remove lifetimes on geometry trait types
frewsxcv Jan 15, 2017
cf76f43
sorta kinda implement area operation generically
frewsxcv Jan 15, 2017
0564d17
incorporate interiors
frewsxcv Jan 15, 2017
4c860ed
aint nobody got time for bboxes
frewsxcv Jan 15, 2017
05dda09
fewer clones, redesign traits
frewsxcv Jan 15, 2017
196b8c4
move area algorithm as method
frewsxcv Jan 15, 2017
add8518
unused imports
frewsxcv Jan 15, 2017
a46853b
remove area trait
frewsxcv Jan 15, 2017
1440816
implement area for multipolygon
frewsxcv Jan 16, 2017
3ee7fd3
implement centroid for polygon
frewsxcv Jan 22, 2017
c056b0a
implement centroid for multipolygon
frewsxcv Jan 22, 2017
533aa01
ditch centroid impl for bbox
frewsxcv Jan 22, 2017
1f46dc1
impl distance for point
frewsxcv Jan 22, 2017
8bbb4ef
implement centroid for linestring
frewsxcv Jan 22, 2017
c94cf72
remove unused trait
frewsxcv Jan 22, 2017
4ceab87
remove unused imports
frewsxcv Jan 22, 2017
4b4837f
impl length for linestring
frewsxcv Jan 22, 2017
d8e81f2
migrate from num to num-traits
frewsxcv Jan 22, 2017
39966cc
implement length for multilinestring
frewsxcv Jan 22, 2017
72a6d85
point to point rename
frewsxcv Jan 22, 2017
e20e29c
implement contains for point and linestring
frewsxcv Jan 22, 2017
6efd5df
rename method
frewsxcv Jan 22, 2017
ed2b205
impl contains and intersects
frewsxcv Jan 25, 2017
d042777
polygon intersect polygon impl
frewsxcv Jan 25, 2017
39a7db8
remove contains trait
frewsxcv Jan 25, 2017
8f86aa7
add reverse impl
frewsxcv Jan 25, 2017
c78b494
impl distance things
frewsxcv Jan 27, 2017
97cd9ad
remove fromprimitive trait
frewsxcv Jan 27, 2017
47c7ccc
cargo fmt
frewsxcv Jan 27, 2017
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
13 changes: 6 additions & 7 deletions examples/algorithm.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
extern crate geo;

use geo::{Point, LineString, Coordinate};
use geo::algorithm::centroid::Centroid;
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());
Expand Down
2 changes: 1 addition & 1 deletion examples/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
87 changes: 33 additions & 54 deletions src/algorithm/area.rs
Original file line number Diff line number Diff line change
@@ -1,69 +1,48 @@
use num_traits::Float;
use types::{LineString, Polygon, MultiPolygon, Bbox};
use {MultiPolygonTrait, PolygonTrait, LineStringTrait, PointTrait};

/// Calculation of the area.

pub trait Area<T> where T: Float
fn get_linestring_area<'a, T, G>(linestring: &'a G) -> T
where T: 'a + Float,
G: 'a + LineStringTrait<'a, T>
{
/// 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(&self) -> T;
}

fn get_linestring_area<T>(linestring: &LineString<T>) -> T where T: Float {
if linestring.0.is_empty() || linestring.0.len() == 1 {
return T::zero();
}
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<T> Area<T> for Polygon<T>
where T: Float
{
fn area(&self) -> T {
self.interiors.iter().fold(get_linestring_area(&self.exterior),
|total, next| total - get_linestring_area(next))
}
}

impl<T> Area<T> for MultiPolygon<T>
where 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.0.iter().fold(T::zero(), |total, next| total + next.area())
}
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))
}

impl<T> Area<T> for Bbox<T>
where T: Float
pub fn multi_polygon<'a, G, T>(multi_polygon: &'a G) -> T
where T: 'a + Float,
G: 'a + MultiPolygonTrait<'a, T> + ?Sized
{
fn area(&self) -> T {
(self.xmax - self.xmin) * (self.ymax - self.ymin)
}
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 algorithm::area::Area;
use types::{Coordinate, Point, LineString, Polygon, MultiPolygon};
use test_helpers::within_epsilon;
// Area of the polygon
use {PolygonTrait, MultiPolygonTrait};

#[test]
fn area_empty_polygon_test() {
let poly = Polygon::<f64>::new(LineString(Vec::new()), Vec::new());
Expand All @@ -82,11 +61,7 @@ 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 });
Expand All @@ -96,10 +71,14 @@ 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 });
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.),
Expand Down
77 changes: 61 additions & 16 deletions src/algorithm/boundingbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ pub trait BoundingBox<T: Float> {
fn get_min_max<T>(p: T, min: T, max: T) -> (T, T)
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<Bbox<T>>
where T: 'a + Float,
I: 'a + IntoIterator<Item = &'a Point<T>>
{
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());
Expand All @@ -47,8 +53,12 @@ fn get_bbox<'a, I, T>(collection: I) -> Option<Bbox<T>>
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
}
Expand Down Expand Up @@ -114,7 +124,8 @@ impl<T> BoundingBox<T> for MultiPolygon<T>

#[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]
Expand All @@ -130,14 +141,24 @@ mod test {
let mut vect = Vec::<Point<f64>>::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]
Expand All @@ -147,32 +168,56 @@ 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();
let poly = Polygon::new(linestring, Vec::new());
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());
}
}
Loading