Skip to main content

geoarrow_geojson/encoder/
multipolygon.rs

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