geoarrow_array/geozero/import/
polygon.rs

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