geoarrow_array/builder/
geometrycollection.rs1use std::sync::Arc;
2
3use arrow_array::OffsetSizeTrait;
4use arrow_buffer::NullBufferBuilder;
5use geo_traits::{
6 GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait,
7 MultiPolygonTrait, PointTrait, PolygonTrait,
8};
9use geoarrow_schema::GeometryCollectionType;
10use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
11
12use crate::GeoArrowArray;
13use crate::array::{GenericWkbArray, GeometryCollectionArray};
14use crate::builder::geo_trait_wrappers::{LineWrapper, RectWrapper, TriangleWrapper};
15use crate::builder::{MixedGeometryBuilder, OffsetsBuilder};
16use crate::capacity::GeometryCollectionCapacity;
17use crate::trait_::{GeoArrowArrayAccessor, GeoArrowArrayBuilder};
18
19#[derive(Debug)]
24pub struct GeometryCollectionBuilder {
25 data_type: GeometryCollectionType,
26
27 pub(crate) geoms: MixedGeometryBuilder,
28
29 pub(crate) geom_offsets: OffsetsBuilder<i32>,
30
31 pub(crate) validity: NullBufferBuilder,
32}
33
34impl<'a> GeometryCollectionBuilder {
35 pub fn new(typ: GeometryCollectionType) -> Self {
37 Self::with_capacity(typ, Default::default())
38 }
39
40 pub fn with_capacity(
43 typ: GeometryCollectionType,
44 capacity: GeometryCollectionCapacity,
45 ) -> Self {
46 Self {
47 geoms: MixedGeometryBuilder::with_capacity_and_options(
48 typ.dimension(),
49 capacity.mixed_capacity,
50 typ.coord_type(),
51 ),
52 geom_offsets: OffsetsBuilder::with_capacity(capacity.geom_capacity),
53 validity: NullBufferBuilder::new(capacity.geom_capacity),
54 data_type: typ,
55 }
56 }
57
58 pub fn with_prefer_multi(self, prefer_multi: bool) -> Self {
70 Self {
71 geoms: self.geoms.with_prefer_multi(prefer_multi),
72 ..self
73 }
74 }
75
76 pub fn reserve(&mut self, additional: GeometryCollectionCapacity) {
82 self.geoms.reserve(additional.mixed_capacity);
83 self.geom_offsets.reserve(additional.geom_capacity);
84 }
85
86 pub fn reserve_exact(&mut self, additional: GeometryCollectionCapacity) {
98 self.geoms.reserve_exact(additional.mixed_capacity);
99 self.geom_offsets.reserve_exact(additional.geom_capacity);
100 }
101
102 pub fn shrink_to_fit(&mut self) {
104 self.geoms.shrink_to_fit();
105 self.geom_offsets.shrink_to_fit();
106 }
108
109 pub fn finish(mut self) -> GeometryCollectionArray {
111 let validity = self.validity.finish();
112 GeometryCollectionArray::new(
113 self.geoms.finish(),
114 self.geom_offsets.finish(),
115 validity,
116 self.data_type.metadata().clone(),
117 )
118 }
119
120 #[inline]
122 fn push_point(&mut self, value: Option<&impl PointTrait<T = f64>>) -> GeoArrowResult<()> {
123 if let Some(geom) = value {
124 self.geoms.push_point(geom)?;
125 self.geom_offsets.try_push_usize(1)?;
126 self.validity.append(value.is_some());
127 } else {
128 self.push_null();
129 }
130 Ok(())
131 }
132
133 #[inline]
135 fn push_line_string(
136 &mut self,
137 value: Option<&impl LineStringTrait<T = f64>>,
138 ) -> GeoArrowResult<()> {
139 if let Some(geom) = value {
140 self.geoms.push_line_string(geom)?;
141 self.geom_offsets.try_push_usize(1)?;
142 self.validity.append(value.is_some());
143 } else {
144 self.push_null();
145 }
146 Ok(())
147 }
148
149 #[inline]
151 fn push_polygon(&mut self, value: Option<&impl PolygonTrait<T = f64>>) -> GeoArrowResult<()> {
152 if let Some(geom) = value {
153 self.geoms.push_polygon(geom)?;
154 self.geom_offsets.try_push_usize(1)?;
155 self.validity.append(value.is_some());
156 } else {
157 self.push_null();
158 }
159 Ok(())
160 }
161
162 #[inline]
164 fn push_multi_point(
165 &mut self,
166 value: Option<&impl MultiPointTrait<T = f64>>,
167 ) -> GeoArrowResult<()> {
168 if let Some(geom) = value {
169 self.geoms.push_multi_point(geom)?;
170 self.geom_offsets.try_push_usize(1)?;
171 self.validity.append(value.is_some());
172 } else {
173 self.push_null();
174 }
175 Ok(())
176 }
177
178 #[inline]
180 fn push_multi_line_string(
181 &mut self,
182 value: Option<&impl MultiLineStringTrait<T = f64>>,
183 ) -> GeoArrowResult<()> {
184 if let Some(geom) = value {
185 self.geoms.push_multi_line_string(geom)?;
186 self.geom_offsets.try_push_usize(1)?;
187 self.validity.append(value.is_some());
188 } else {
189 self.push_null();
190 }
191 Ok(())
192 }
193
194 #[inline]
196 fn push_multi_polygon(
197 &mut self,
198 value: Option<&impl MultiPolygonTrait<T = f64>>,
199 ) -> GeoArrowResult<()> {
200 if let Some(geom) = value {
201 self.geoms.push_multi_polygon(geom)?;
202 self.geom_offsets.try_push_usize(1)?;
203 self.validity.append(value.is_some());
204 } else {
205 self.push_null();
206 }
207 Ok(())
208 }
209
210 #[inline]
212 pub fn push_geometry(
213 &mut self,
214 value: Option<&impl GeometryTrait<T = f64>>,
215 ) -> GeoArrowResult<()> {
216 use geo_traits::GeometryType::*;
217
218 if let Some(g) = value {
219 match g.as_type() {
220 Point(p) => self.push_point(Some(p))?,
221 LineString(p) => {
222 self.push_line_string(Some(p))?;
223 }
224 Polygon(p) => self.push_polygon(Some(p))?,
225 MultiPoint(p) => self.push_multi_point(Some(p))?,
226 MultiLineString(p) => self.push_multi_line_string(Some(p))?,
227 MultiPolygon(p) => self.push_multi_polygon(Some(p))?,
228 GeometryCollection(p) => self.push_geometry_collection(Some(p))?,
229 Rect(r) => self.push_polygon(Some(&RectWrapper::try_new(r)?))?,
230 Triangle(tri) => self.push_polygon(Some(&TriangleWrapper(tri)))?,
231 Line(l) => self.push_line_string(Some(&LineWrapper(l)))?,
232 }
233 } else {
234 self.push_null();
235 };
236 Ok(())
237 }
238
239 #[inline]
241 pub fn push_geometry_collection(
242 &mut self,
243 value: Option<&impl GeometryCollectionTrait<T = f64>>,
244 ) -> GeoArrowResult<()> {
245 if let Some(gc) = value {
246 let num_geoms = gc.num_geometries();
247 for g in gc.geometries() {
248 self.geoms.push_geometry(&g)?;
249 }
250 self.try_push_length(num_geoms)?;
251 } else {
252 self.push_null();
253 }
254 Ok(())
255 }
256
257 pub fn extend_from_iter(
259 &mut self,
260 geoms: impl Iterator<Item = Option<&'a (impl GeometryCollectionTrait<T = f64> + 'a)>>,
261 ) {
262 geoms
263 .into_iter()
264 .try_for_each(|maybe_gc| self.push_geometry_collection(maybe_gc))
265 .unwrap();
266 }
267
268 #[inline]
269 pub(crate) fn try_push_length(&mut self, geom_offsets_length: usize) -> GeoArrowResult<()> {
270 self.geom_offsets.try_push_usize(geom_offsets_length)?;
271 self.validity.append(true);
272 Ok(())
273 }
274
275 #[inline]
276 pub(crate) fn push_null(&mut self) {
277 self.geom_offsets.extend_constant(1);
278 self.validity.append(false);
279 }
280
281 pub fn from_geometry_collections(
283 geoms: &[impl GeometryCollectionTrait<T = f64>],
284 typ: GeometryCollectionType,
285 ) -> GeoArrowResult<Self> {
286 let capacity =
287 GeometryCollectionCapacity::from_geometry_collections(geoms.iter().map(Some))?;
288 let mut array = Self::with_capacity(typ, capacity);
289 array.extend_from_iter(geoms.iter().map(Some));
290 Ok(array)
291 }
292
293 pub fn from_nullable_geometry_collections(
295 geoms: &[Option<impl GeometryCollectionTrait<T = f64>>],
296 typ: GeometryCollectionType,
297 ) -> GeoArrowResult<Self> {
298 let capacity = GeometryCollectionCapacity::from_geometry_collections(
299 geoms.iter().map(|x| x.as_ref()),
300 )?;
301 let mut array = Self::with_capacity(typ, capacity);
302 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
303 Ok(array)
304 }
305
306 pub fn from_nullable_geometries(
308 geoms: &[Option<impl GeometryTrait<T = f64>>],
309 typ: GeometryCollectionType,
310 ) -> GeoArrowResult<Self> {
311 let capacity =
312 GeometryCollectionCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
313 let mut array = Self::with_capacity(typ, capacity);
314 for geom in geoms {
315 array.push_geometry(geom.as_ref())?;
316 }
317 Ok(array)
318 }
319}
320
321impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, GeometryCollectionType)>
322 for GeometryCollectionBuilder
323{
324 type Error = GeoArrowError;
325
326 fn try_from(
327 (value, typ): (GenericWkbArray<O>, GeometryCollectionType),
328 ) -> GeoArrowResult<Self> {
329 let wkb_objects = value
330 .iter()
331 .map(|x| x.transpose())
332 .collect::<GeoArrowResult<Vec<_>>>()?;
333 Self::from_nullable_geometries(&wkb_objects, typ)
334 }
335}
336
337impl GeoArrowArrayBuilder for GeometryCollectionBuilder {
338 fn len(&self) -> usize {
339 self.geom_offsets.len_proxy()
340 }
341
342 fn push_null(&mut self) {
343 self.push_null();
344 }
345
346 fn push_geometry(
347 &mut self,
348 geometry: Option<&impl GeometryTrait<T = f64>>,
349 ) -> GeoArrowResult<()> {
350 self.push_geometry(geometry)
351 }
352
353 fn finish(self) -> Arc<dyn GeoArrowArray> {
354 Arc::new(self.finish())
355 }
356}