-
Notifications
You must be signed in to change notification settings - Fork 206
/
Copy patharea.rs
115 lines (106 loc) · 4 KB
/
area.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use num_traits::Float;
use types::{LineString, Polygon, MultiPolygon, Bbox};
/// Calculation of the area.
pub trait Area<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(&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 tmp = T::zero();
for ps in linestring.0.windows(2) {
tmp = tmp + (ps[0].x() * ps[1].y() - ps[1].x() * ps[0].y());
}
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
{
fn area(&self) -> T {
self.0.iter().fold(T::zero(), |total, next| total + next.area())
}
}
impl<T> Area<T> for Bbox<T>
where T: Float
{
fn area(&self) -> T {
(self.xmax - self.xmin) * (self.ymax - self.ymin)
}
}
#[cfg(test)]
mod test {
use num_traits::Float;
use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox};
use algorithm::area::Area;
use test_helpers::within_epsilon;
// Area of the polygon
#[test]
fn area_empty_polygon_test() {
let poly = Polygon::<f64>::new(LineString(Vec::new()), Vec::new());
assert!(within_epsilon(poly.area(), 0., Float::epsilon()));
}
#[test]
fn area_one_point_polygon_test() {
let poly = Polygon::new(LineString(vec![Point::new(1., 0.)]), Vec::new());
assert!(within_epsilon(poly.area(), 0., Float::epsilon()));
}
#[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::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 });
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::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.),
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.);
assert!(within_epsilon(mpoly.area(), 102., Float::epsilon()));
}
}