geoarrow_array/builder/
multipolygon.rs1use std::sync::Arc;
2
3use arrow_array::OffsetSizeTrait;
4use arrow_buffer::NullBufferBuilder;
5use geo_traits::{
6 CoordTrait, GeometryTrait, GeometryType, LineStringTrait, MultiPolygonTrait, PolygonTrait,
7};
8use geoarrow_schema::MultiPolygonType;
9use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
10
11use crate::GeoArrowArray;
12use crate::array::{GenericWkbArray, MultiPolygonArray};
13use crate::builder::geo_trait_wrappers::RectWrapper;
14use crate::builder::{CoordBufferBuilder, OffsetsBuilder};
15use crate::capacity::MultiPolygonCapacity;
16use crate::trait_::{GeoArrowArrayAccessor, GeoArrowArrayBuilder};
17use crate::util::GeometryTypeName;
18
19#[derive(Debug)]
23pub struct MultiPolygonBuilder {
24 data_type: MultiPolygonType,
25
26 pub(crate) coords: CoordBufferBuilder,
27
28 pub(crate) geom_offsets: OffsetsBuilder<i32>,
30
31 pub(crate) polygon_offsets: OffsetsBuilder<i32>,
33
34 pub(crate) ring_offsets: OffsetsBuilder<i32>,
36
37 pub(crate) validity: NullBufferBuilder,
39}
40
41impl MultiPolygonBuilder {
42 pub fn new(typ: MultiPolygonType) -> Self {
44 Self::with_capacity(typ, Default::default())
45 }
46
47 pub fn with_capacity(typ: MultiPolygonType, capacity: MultiPolygonCapacity) -> Self {
49 let coords = CoordBufferBuilder::with_capacity(
50 capacity.coord_capacity,
51 typ.coord_type(),
52 typ.dimension(),
53 );
54 Self {
55 coords,
56 geom_offsets: OffsetsBuilder::with_capacity(capacity.geom_capacity),
57 polygon_offsets: OffsetsBuilder::with_capacity(capacity.polygon_capacity),
58 ring_offsets: OffsetsBuilder::with_capacity(capacity.ring_capacity),
59 validity: NullBufferBuilder::new(capacity.geom_capacity),
60 data_type: typ,
61 }
62 }
63
64 pub fn reserve(&mut self, additional: MultiPolygonCapacity) {
70 self.coords.reserve(additional.coord_capacity);
71 self.ring_offsets.reserve(additional.ring_capacity);
72 self.polygon_offsets.reserve(additional.polygon_capacity);
73 self.geom_offsets.reserve(additional.geom_capacity);
74 }
75
76 pub fn reserve_exact(&mut self, additional: MultiPolygonCapacity) {
88 self.coords.reserve_exact(additional.coord_capacity);
89 self.ring_offsets.reserve_exact(additional.ring_capacity);
90 self.polygon_offsets
91 .reserve_exact(additional.polygon_capacity);
92 self.geom_offsets.reserve_exact(additional.geom_capacity);
93 }
94
95 pub fn shrink_to_fit(&mut self) {
97 self.coords.shrink_to_fit();
98 self.ring_offsets.shrink_to_fit();
99 self.polygon_offsets.shrink_to_fit();
100 self.geom_offsets.shrink_to_fit();
101 }
103
104 pub fn finish(mut self) -> MultiPolygonArray {
106 let validity = self.validity.finish();
107
108 MultiPolygonArray::new(
109 self.coords.finish(),
110 self.geom_offsets.finish(),
111 self.polygon_offsets.finish(),
112 self.ring_offsets.finish(),
113 validity,
114 self.data_type.metadata().clone(),
115 )
116 }
117
118 #[inline]
124 pub fn push_polygon(
125 &mut self,
126 value: Option<&impl PolygonTrait<T = f64>>,
127 ) -> GeoArrowResult<()> {
128 if let Some(polygon) = value {
129 let exterior_ring = polygon.exterior();
130 if exterior_ring.is_none() {
131 self.push_empty()?;
132 return Ok(());
133 }
134
135 if let Some(ext_ring) = polygon.exterior() {
136 let num_polygons = 1;
138 self.geom_offsets.try_push_usize(num_polygons)?;
139
140 for coord in ext_ring.coords() {
141 self.coords.push_coord(&coord);
142 }
143
144 self.polygon_offsets
146 .try_push_usize(polygon.num_interiors() + 1)?;
147
148 self.ring_offsets.try_push_usize(ext_ring.num_coords())?;
150
151 for int_ring in polygon.interiors() {
152 self.ring_offsets.try_push_usize(int_ring.num_coords())?;
153
154 for coord in int_ring.coords() {
155 self.coords.push_coord(&coord);
156 }
157 }
158 } else {
159 let num_polygons = 0;
160 self.geom_offsets.try_push_usize(num_polygons)?;
161 }
162 } else {
163 self.push_null();
164 };
165 Ok(())
166 }
167
168 #[inline]
174 pub fn push_multi_polygon(
175 &mut self,
176 value: Option<&impl MultiPolygonTrait<T = f64>>,
177 ) -> GeoArrowResult<()> {
178 if let Some(multi_polygon) = value {
179 let num_polygons = multi_polygon.num_polygons();
181 self.try_push_geom_offset(num_polygons)?;
182
183 for polygon in multi_polygon.polygons() {
185 let ext_ring = polygon.exterior().unwrap();
188 for coord in ext_ring.coords() {
189 self.coords.push_coord(&coord);
190 }
191
192 self.polygon_offsets
194 .try_push_usize(polygon.num_interiors() + 1)?;
195
196 self.ring_offsets.try_push_usize(ext_ring.num_coords())?;
198
199 for int_ring in polygon.interiors() {
200 self.ring_offsets.try_push_usize(int_ring.num_coords())?;
201
202 for coord in int_ring.coords() {
203 self.coords.push_coord(&coord);
204 }
205 }
206 }
207 } else {
208 self.push_null();
209 };
210 Ok(())
211 }
212
213 #[inline]
217 pub fn push_geometry(
218 &mut self,
219 value: Option<&impl GeometryTrait<T = f64>>,
220 ) -> GeoArrowResult<()> {
221 if let Some(value) = value {
222 match value.as_type() {
223 GeometryType::Polygon(g) => self.push_polygon(Some(g))?,
224 GeometryType::MultiPolygon(g) => self.push_multi_polygon(Some(g))?,
225 GeometryType::Rect(g) => self.push_polygon(Some(&RectWrapper::try_new(g)?))?,
226 gt => {
227 return Err(GeoArrowError::IncorrectGeometryType(format!(
228 "Expected MultiPolygon compatible geometry, got {}",
229 gt.name()
230 )));
231 }
232 }
233 } else {
234 self.push_null();
235 };
236 Ok(())
237 }
238
239 pub fn extend_from_iter<'a>(
241 &mut self,
242 geoms: impl Iterator<Item = Option<&'a (impl MultiPolygonTrait<T = f64> + 'a)>>,
243 ) {
244 geoms
245 .into_iter()
246 .try_for_each(|maybe_multi_polygon| self.push_multi_polygon(maybe_multi_polygon))
247 .unwrap();
248 }
249
250 pub fn extend_from_geometry_iter<'a>(
252 &mut self,
253 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
254 ) -> GeoArrowResult<()> {
255 geoms.into_iter().try_for_each(|g| self.push_geometry(g))?;
256 Ok(())
257 }
258
259 #[inline]
266 pub(crate) fn try_push_geom_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
267 self.geom_offsets.try_push_usize(offsets_length)?;
268 self.validity.append(true);
269 Ok(())
270 }
271
272 #[inline]
279 pub(crate) fn try_push_polygon_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
280 self.polygon_offsets.try_push_usize(offsets_length)?;
281 Ok(())
282 }
283
284 #[inline]
291 pub(crate) fn try_push_ring_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
292 self.ring_offsets.try_push_usize(offsets_length)?;
293 Ok(())
294 }
295
296 #[inline]
303 pub unsafe fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
304 self.coords.push_coord(coord);
305 Ok(())
306 }
307
308 #[inline]
309 pub(crate) fn push_empty(&mut self) -> GeoArrowResult<()> {
310 self.geom_offsets.try_push_usize(0)?;
311 self.validity.append(true);
312 Ok(())
313 }
314
315 #[inline]
316 pub(crate) fn push_null(&mut self) {
317 self.geom_offsets.extend_constant(1);
321 self.validity.append(false);
322 }
323
324 pub fn from_multi_polygons(
326 geoms: &[impl MultiPolygonTrait<T = f64>],
327 typ: MultiPolygonType,
328 ) -> Self {
329 let capacity = MultiPolygonCapacity::from_multi_polygons(geoms.iter().map(Some));
330 let mut array = Self::with_capacity(typ, capacity);
331 array.extend_from_iter(geoms.iter().map(Some));
332 array
333 }
334
335 pub fn from_nullable_multi_polygons(
337 geoms: &[Option<impl MultiPolygonTrait<T = f64>>],
338 typ: MultiPolygonType,
339 ) -> Self {
340 let capacity = MultiPolygonCapacity::from_multi_polygons(geoms.iter().map(|x| x.as_ref()));
341 let mut array = Self::with_capacity(typ, capacity);
342 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
343 array
344 }
345
346 pub fn from_nullable_geometries(
348 geoms: &[Option<impl GeometryTrait<T = f64>>],
349 typ: MultiPolygonType,
350 ) -> GeoArrowResult<Self> {
351 let capacity = MultiPolygonCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
352 let mut array = Self::with_capacity(typ, capacity);
353 array.extend_from_geometry_iter(geoms.iter().map(|x| x.as_ref()))?;
354 Ok(array)
355 }
356}
357
358impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, MultiPolygonType)> for MultiPolygonBuilder {
359 type Error = GeoArrowError;
360
361 fn try_from((value, typ): (GenericWkbArray<O>, MultiPolygonType)) -> GeoArrowResult<Self> {
362 let wkb_objects = value
363 .iter()
364 .map(|x| x.transpose())
365 .collect::<GeoArrowResult<Vec<_>>>()?;
366 Self::from_nullable_geometries(&wkb_objects, typ)
367 }
368}
369
370impl GeoArrowArrayBuilder for MultiPolygonBuilder {
371 fn len(&self) -> usize {
372 self.geom_offsets.len_proxy()
373 }
374
375 fn push_null(&mut self) {
376 self.push_null();
377 }
378
379 fn push_geometry(
380 &mut self,
381 geometry: Option<&impl GeometryTrait<T = f64>>,
382 ) -> GeoArrowResult<()> {
383 self.push_geometry(geometry)
384 }
385
386 fn finish(self) -> Arc<dyn GeoArrowArray> {
387 Arc::new(self.finish())
388 }
389}