Skip to main content

geoarrow_geojson/encoder/
linestring.rs

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