geoarrow_geojson/encoder/
polygon.rs1use 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
8pub 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}