Skip to main content

geoarrow_geojson/encoder/
polygon.rs

1use arrow_json::Encoder;
2use geo_traits::{LineStringTrait, PolygonTrait};
3use geoarrow_array::GeoArrowArrayAccessor;
4use geoarrow_array::array::PolygonArray;
5
6use crate::encoder::linestring::encode_coords;
7
8// An [Encoder] for [PolygonArray].
9pub struct PolygonEncoder(PolygonArray);
10
11impl PolygonEncoder {
12    pub fn new(array: PolygonArray) -> Self {
13        Self(array)
14    }
15}
16
17impl Encoder for PolygonEncoder {
18    fn encode(&mut self, idx: usize, out: &mut Vec<u8>) {
19        let geom = self.0.value(idx).unwrap();
20        encode_polygon(&geom, out);
21    }
22}
23
24pub(crate) fn encode_polygon(geom: &impl PolygonTrait<T = f64>, out: &mut Vec<u8>) {
25    out.extend(br#"{"type":"Polygon","coordinates":"#);
26    encode_polygon_rings(geom, out);
27    out.push(b'}');
28}
29
30pub(crate) fn encode_polygon_rings(geom: &impl PolygonTrait<T = f64>, out: &mut Vec<u8>) {
31    out.push(b'[');
32    if let Some(exterior) = geom.exterior() {
33        encode_coords(exterior.coords(), out);
34    }
35
36    let num_interiors = geom.num_interiors();
37    if num_interiors > 0 {
38        out.push(b',');
39    }
40
41    for (idx, interior) in geom.interiors().enumerate() {
42        encode_coords(interior.coords(), out);
43        if idx < num_interiors - 1 {
44            out.push(b',');
45        }
46    }
47    out.push(b']');
48}
49
50#[cfg(test)]
51mod test {
52    use std::str::FromStr;
53
54    use geoarrow_array::test::polygon::array;
55    use geoarrow_schema::{CoordType, Dimension};
56
57    use super::*;
58
59    #[test]
60    fn encode_polygon() {
61        let mut encoder = PolygonEncoder::new(array(CoordType::Separated, Dimension::XY));
62
63        let mut out = vec![];
64        encoder.encode(0, &mut out);
65        let s = String::from_utf8(out).unwrap();
66        let expected =
67            r#"{"type":"Polygon","coordinates":[[[30,10],[40,40],[20,40],[10,20],[30,10]]]}"#;
68        assert_eq!(s, expected);
69
70        geojson::Geometry::from_str(expected).expect("Should be valid GeoJSON");
71    }
72}