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
use types::Polygon;

/// Calculation of the area.

pub trait Area {
    /// 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(linestring, v);
    /// assert_eq!(poly.area(), 30.);
    /// ```
    fn area(&self) -> f64;
}

impl Area for Polygon {
    fn area(&self) -> f64 {
        // TODO: consideration of inner polygons;
        let linestring = &self.0;
        if linestring.0.is_empty() || linestring.0.len() == 1 {
            return 0.;
        }
        let mut tmp = 0.;
        for (p1, p2) in linestring.0.iter().zip(linestring.0[1..].iter()) {
            tmp += p1.lng() * p2.lat() - p2.lng() * p1.lat();
        }
        tmp / 2.
    }
}

#[cfg(test)]
mod test {
    use types::{Coordinate, Point, LineString, Polygon};
    use algorithm::area::Area;
    // Area of the polygon
    #[test]
    fn area_empty_polygon_test() {
        let poly = Polygon(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());
        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());
        assert_eq!(poly.area(), 30.);
    }
}