geoarrow_array/geozero/import/
multipoint.rs

1use geoarrow_schema::MultiPointType;
2use geozero::{GeomProcessor, GeozeroGeometry};
3
4use crate::array::MultiPointArray;
5use crate::builder::MultiPointBuilder;
6use crate::capacity::MultiPointCapacity;
7use crate::geozero::import::util::{from_xy, from_xyzm};
8
9/// GeoZero trait to convert to GeoArrow MultiPointArray.
10pub trait ToMultiPointArray {
11    /// Convert to GeoArrow MultiPointArray
12    fn to_multi_point_array(&self, typ: MultiPointType) -> geozero::error::Result<MultiPointArray> {
13        Ok(self.to_multi_point_builder(typ)?.finish())
14    }
15
16    /// Convert to a GeoArrow MultiPointBuilder
17    fn to_multi_point_builder(
18        &self,
19        typ: MultiPointType,
20    ) -> geozero::error::Result<MultiPointBuilder>;
21}
22
23impl<T: GeozeroGeometry> ToMultiPointArray for T {
24    fn to_multi_point_builder(
25        &self,
26        typ: MultiPointType,
27    ) -> geozero::error::Result<MultiPointBuilder> {
28        let mut mutable_array = MultiPointBuilder::new(typ);
29        self.process_geom(&mut mutable_array)?;
30        Ok(mutable_array)
31    }
32}
33
34#[allow(unused_variables)]
35impl GeomProcessor for MultiPointBuilder {
36    fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> geozero::error::Result<()> {
37        let capacity = MultiPointCapacity::new(0, size);
38        self.reserve(capacity);
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 multipoint_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 multipoint_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    fn point_begin(&mut self, idx: usize) -> geozero::error::Result<()> {
70        let capacity = MultiPointCapacity::new(1, 0);
71        self.reserve(capacity);
72        self.try_push_length(1).unwrap();
73        Ok(())
74    }
75
76    fn point_end(&mut self, idx: usize) -> geozero::error::Result<()> {
77        Ok(())
78    }
79
80    fn multipoint_begin(&mut self, size: usize, idx: usize) -> geozero::error::Result<()> {
81        let capacity = MultiPointCapacity::new(size, 0);
82        self.reserve(capacity);
83        self.try_push_length(size).unwrap();
84        Ok(())
85    }
86
87    fn multipoint_end(&mut self, idx: usize) -> geozero::error::Result<()> {
88        Ok(())
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use geo_types::{Geometry, MultiPoint};
95    use geoarrow_schema::Dimension;
96    use geozero::error::Result;
97
98    use super::*;
99    use crate::test::multipoint::{mp0, mp1};
100
101    #[test]
102    fn from_geozero() -> Result<()> {
103        let geo_geoms = vec![mp0(), MultiPoint(vec![]), mp1()];
104
105        let geo = Geometry::GeometryCollection(
106            geo_geoms
107                .clone()
108                .into_iter()
109                .map(Geometry::MultiPoint)
110                .collect(),
111        );
112        let typ = MultiPointType::new(Dimension::XY, Default::default());
113        let geo_arr = geo.to_multi_point_array(typ.clone()).unwrap();
114
115        let geo_arr2 = MultiPointBuilder::from_multi_points(&geo_geoms, typ).finish();
116
117        // These are constructed with two different code paths
118        assert_eq!(geo_arr, geo_arr2);
119        Ok(())
120    }
121}