geoarrow_array/builder/
multipoint.rs1use std::sync::Arc;
2
3use arrow_array::OffsetSizeTrait;
4use arrow_buffer::NullBufferBuilder;
5use geo_traits::{CoordTrait, GeometryTrait, GeometryType, MultiPointTrait, PointTrait};
6use geoarrow_schema::MultiPointType;
7use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
8
9use crate::GeoArrowArray;
10use crate::array::{GenericWkbArray, MultiPointArray};
11use crate::builder::{CoordBufferBuilder, OffsetsBuilder};
12use crate::capacity::MultiPointCapacity;
13use crate::trait_::{GeoArrowArrayAccessor, GeoArrowArrayBuilder};
14use crate::util::GeometryTypeName;
15
16#[derive(Debug)]
20pub struct MultiPointBuilder {
21 data_type: MultiPointType,
22
23 coords: CoordBufferBuilder,
24
25 geom_offsets: OffsetsBuilder<i32>,
26
27 validity: NullBufferBuilder,
29}
30
31impl MultiPointBuilder {
32 pub fn new(typ: MultiPointType) -> Self {
34 Self::with_capacity(typ, Default::default())
35 }
36
37 pub fn with_capacity(typ: MultiPointType, capacity: MultiPointCapacity) -> Self {
39 let coords = CoordBufferBuilder::with_capacity(
40 capacity.coord_capacity,
41 typ.coord_type(),
42 typ.dimension(),
43 );
44 Self {
45 coords,
46 geom_offsets: OffsetsBuilder::with_capacity(capacity.geom_capacity),
47 validity: NullBufferBuilder::new(capacity.geom_capacity),
48 data_type: typ,
49 }
50 }
51
52 pub fn reserve(&mut self, capacity: MultiPointCapacity) {
58 self.coords.reserve(capacity.coord_capacity);
59 self.geom_offsets.reserve(capacity.geom_capacity);
60 }
61
62 pub fn reserve_exact(&mut self, capacity: MultiPointCapacity) {
74 self.coords.reserve_exact(capacity.coord_capacity);
75 self.geom_offsets.reserve_exact(capacity.geom_capacity);
76 }
77
78 pub fn shrink_to_fit(&mut self) {
80 self.coords.shrink_to_fit();
81 self.geom_offsets.shrink_to_fit();
82 }
84
85 pub fn finish(mut self) -> MultiPointArray {
87 let validity = self.validity.finish();
88 MultiPointArray::new(
89 self.coords.finish(),
90 self.geom_offsets.finish(),
91 validity,
92 self.data_type.metadata().clone(),
93 )
94 }
95
96 pub fn extend_from_iter<'a>(
98 &mut self,
99 geoms: impl Iterator<Item = Option<&'a (impl MultiPointTrait<T = f64> + 'a)>>,
100 ) {
101 geoms
102 .into_iter()
103 .try_for_each(|maybe_multi_point| self.push_multi_point(maybe_multi_point))
104 .unwrap();
105 }
106
107 pub fn extend_from_geometry_iter<'a>(
109 &mut self,
110 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
111 ) -> GeoArrowResult<()> {
112 geoms.into_iter().try_for_each(|g| self.push_geometry(g))?;
113 Ok(())
114 }
115
116 #[inline]
122 pub fn push_point(&mut self, value: Option<&impl PointTrait<T = f64>>) -> GeoArrowResult<()> {
123 if let Some(point) = value {
124 self.coords.push_point(point);
125 self.try_push_length(1)?;
126 } else {
127 self.push_null();
128 }
129
130 Ok(())
131 }
132
133 #[inline]
139 pub fn push_multi_point(
140 &mut self,
141 value: Option<&impl MultiPointTrait<T = f64>>,
142 ) -> GeoArrowResult<()> {
143 if let Some(multi_point) = value {
144 let num_points = multi_point.num_points();
145 for point in multi_point.points() {
146 self.coords.push_point(&point);
147 }
148 self.try_push_length(num_points)?;
149 } else {
150 self.push_null();
151 }
152 Ok(())
153 }
154
155 #[inline]
159 pub fn push_geometry(
160 &mut self,
161 value: Option<&impl GeometryTrait<T = f64>>,
162 ) -> GeoArrowResult<()> {
163 if let Some(value) = value {
164 match value.as_type() {
165 GeometryType::Point(g) => self.push_point(Some(g))?,
166 GeometryType::MultiPoint(g) => self.push_multi_point(Some(g))?,
167 gt => {
168 return Err(GeoArrowError::IncorrectGeometryType(format!(
169 "Expected MultiPoint compatible geometry, got {}",
170 gt.name()
171 )));
172 }
173 }
174 } else {
175 self.push_null();
176 };
177 Ok(())
178 }
179
180 #[inline]
187 #[allow(dead_code)]
188 pub(crate) fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
189 self.coords.try_push_coord(coord)
190 }
191
192 #[inline]
195 pub(crate) fn try_push_length(&mut self, geom_offsets_length: usize) -> GeoArrowResult<()> {
196 self.geom_offsets.try_push_usize(geom_offsets_length)?;
197 self.validity.append(true);
198 Ok(())
199 }
200
201 #[inline]
202 pub(crate) fn push_null(&mut self) {
203 self.geom_offsets.extend_constant(1);
204 self.validity.append(false);
205 }
206
207 pub fn from_multi_points(geoms: &[impl MultiPointTrait<T = f64>], typ: MultiPointType) -> Self {
209 let capacity = MultiPointCapacity::from_multi_points(geoms.iter().map(Some));
210 let mut array = Self::with_capacity(typ, capacity);
211 array.extend_from_iter(geoms.iter().map(Some));
212 array
213 }
214
215 pub fn from_nullable_multi_points(
217 geoms: &[Option<impl MultiPointTrait<T = f64>>],
218 typ: MultiPointType,
219 ) -> Self {
220 let capacity = MultiPointCapacity::from_multi_points(geoms.iter().map(|x| x.as_ref()));
221 let mut array = Self::with_capacity(typ, capacity);
222 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
223 array
224 }
225
226 pub fn from_nullable_geometries(
228 geoms: &[Option<impl GeometryTrait<T = f64>>],
229 typ: MultiPointType,
230 ) -> GeoArrowResult<Self> {
231 let capacity = MultiPointCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
232 let mut array = Self::with_capacity(typ, capacity);
233 array.extend_from_geometry_iter(geoms.iter().map(|x| x.as_ref()))?;
234 Ok(array)
235 }
236}
237
238impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, MultiPointType)> for MultiPointBuilder {
239 type Error = GeoArrowError;
240
241 fn try_from((value, typ): (GenericWkbArray<O>, MultiPointType)) -> GeoArrowResult<Self> {
242 let wkb_objects = value
243 .iter()
244 .map(|x| x.transpose())
245 .collect::<GeoArrowResult<Vec<_>>>()?;
246 Self::from_nullable_geometries(&wkb_objects, typ)
247 }
248}
249
250impl GeoArrowArrayBuilder for MultiPointBuilder {
251 fn len(&self) -> usize {
252 self.geom_offsets.len_proxy()
253 }
254
255 fn push_null(&mut self) {
256 self.push_null();
257 }
258
259 fn push_geometry(
260 &mut self,
261 geometry: Option<&impl GeometryTrait<T = f64>>,
262 ) -> GeoArrowResult<()> {
263 self.push_geometry(geometry)
264 }
265
266 fn finish(self) -> Arc<dyn GeoArrowArray> {
267 Arc::new(self.finish())
268 }
269}