geoarrow_array/geozero/import/
linestring.rs

1use geoarrow_schema::LineStringType;
2use geozero::{GeomProcessor, GeozeroGeometry};
3
4use crate::array::LineStringArray;
5use crate::builder::LineStringBuilder;
6use crate::capacity::LineStringCapacity;
7use crate::geozero::import::util::{from_xy, from_xyzm};
8
9/// GeoZero trait to convert to GeoArrow LineStringArray.
10pub trait ToLineStringArray {
11    /// Convert to GeoArrow LineStringArray
12    fn to_line_string_array(&self, typ: LineStringType) -> geozero::error::Result<LineStringArray> {
13        Ok(self.to_line_string_builder(typ)?.finish())
14    }
15
16    /// Convert to a GeoArrow LineStringBuilder
17    fn to_line_string_builder(
18        &self,
19        typ: LineStringType,
20    ) -> geozero::error::Result<LineStringBuilder>;
21}
22
23impl<T: GeozeroGeometry> ToLineStringArray for T {
24    fn to_line_string_builder(
25        &self,
26        typ: LineStringType,
27    ) -> geozero::error::Result<LineStringBuilder> {
28        let mut mutable_array = LineStringBuilder::new(typ);
29        self.process_geom(&mut mutable_array)?;
30        Ok(mutable_array)
31    }
32}
33
34#[allow(unused_variables)]
35impl GeomProcessor for LineStringBuilder {
36    fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> geozero::error::Result<()> {
37        let capacity = LineStringCapacity::new(0, size);
38        self.reserve(capacity);
39        Ok(())
40    }
41
42    fn geometrycollection_end(&mut self, idx: usize) -> geozero::error::Result<()> {
43        // self.shrink_to_fit()
44        Ok(())
45    }
46
47    fn xy(&mut self, x: f64, y: f64, idx: usize) -> geozero::error::Result<()> {
48        // # Safety:
49        // This upholds invariants because we call try_push_length in multipoint_begin to ensure
50        // offset arrays are correct.
51        self.push_coord(&from_xy(x, y).expect("valid coord"))
52            .unwrap();
53        Ok(())
54    }
55
56    fn coordinate(
57        &mut self,
58        x: f64,
59        y: f64,
60        z: Option<f64>,
61        m: Option<f64>,
62        t: Option<f64>,
63        tm: Option<u64>,
64        idx: usize,
65    ) -> geozero::error::Result<()> {
66        // # Safety:
67        // This upholds invariants because we call try_push_length in multipoint_begin to ensure
68        // offset arrays are correct.
69        self.push_coord(&from_xyzm(x, y, z, m).expect("valid coord"))
70            .unwrap();
71        Ok(())
72    }
73
74    fn linestring_begin(
75        &mut self,
76        tagged: bool,
77        size: usize,
78        idx: usize,
79    ) -> geozero::error::Result<()> {
80        let capacity = LineStringCapacity::new(size, 0);
81        self.reserve(capacity);
82        self.try_push_length(size).unwrap();
83        Ok(())
84    }
85
86    fn linestring_end(&mut self, tagged: bool, idx: usize) -> geozero::error::Result<()> {
87        Ok(())
88    }
89}
90
91#[cfg(test)]
92mod test {
93    use geo_types::{Geometry, LineString};
94    use geoarrow_schema::Dimension;
95    use geozero::error::Result;
96
97    use super::*;
98    use crate::test::linestring::{ls0, ls1};
99
100    #[test]
101    fn from_geo_using_geozero() -> Result<()> {
102        let geo_geoms = vec![ls0(), LineString(vec![]), ls1()];
103        let geo = Geometry::GeometryCollection(
104            geo_geoms
105                .clone()
106                .into_iter()
107                .map(Geometry::LineString)
108                .collect(),
109        );
110        let typ = LineStringType::new(Dimension::XY, Default::default());
111        let geo_arr = geo.to_line_string_array(typ.clone()).unwrap();
112
113        let geo_arr2 = LineStringBuilder::from_line_strings(&geo_geoms, typ).finish();
114
115        // These are constructed with two different code paths
116        assert_eq!(geo_arr, geo_arr2);
117        Ok(())
118    }
119}