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 finish(mut self) -> GeometryCollectionArray {
104 let validity = self.validity.finish();
105 GeometryCollectionArray::new(
106 self.geoms.finish(),
107 self.geom_offsets.finish(),
108 validity,
109 self.data_type.metadata().clone(),
110 )
111 }
112
113 #[inline]
115 fn push_point(&mut self, value: Option<&impl PointTrait<T = f64>>) -> GeoArrowResult<()> {
116 if let Some(geom) = value {
117 self.geoms.push_point(geom)?;
118 self.geom_offsets.try_push_usize(1)?;
119 self.validity.append(value.is_some());
120 } else {
121 self.push_null();
122 }
123 Ok(())
124 }
125
126 #[inline]
128 fn push_line_string(
129 &mut self,
130 value: Option<&impl LineStringTrait<T = f64>>,
131 ) -> GeoArrowResult<()> {
132 if let Some(geom) = value {
133 self.geoms.push_line_string(geom)?;
134 self.geom_offsets.try_push_usize(1)?;
135 self.validity.append(value.is_some());
136 } else {
137 self.push_null();
138 }
139 Ok(())
140 }
141
142 #[inline]
144 fn push_polygon(&mut self, value: Option<&impl PolygonTrait<T = f64>>) -> GeoArrowResult<()> {
145 if let Some(geom) = value {
146 self.geoms.push_polygon(geom)?;
147 self.geom_offsets.try_push_usize(1)?;
148 self.validity.append(value.is_some());
149 } else {
150 self.push_null();
151 }
152 Ok(())
153 }
154
155 #[inline]
157 fn push_multi_point(
158 &mut self,
159 value: Option<&impl MultiPointTrait<T = f64>>,
160 ) -> GeoArrowResult<()> {
161 if let Some(geom) = value {
162 self.geoms.push_multi_point(geom)?;
163 self.geom_offsets.try_push_usize(1)?;
164 self.validity.append(value.is_some());
165 } else {
166 self.push_null();
167 }
168 Ok(())
169 }
170
171 #[inline]
173 fn push_multi_line_string(
174 &mut self,
175 value: Option<&impl MultiLineStringTrait<T = f64>>,
176 ) -> GeoArrowResult<()> {
177 if let Some(geom) = value {
178 self.geoms.push_multi_line_string(geom)?;
179 self.geom_offsets.try_push_usize(1)?;
180 self.validity.append(value.is_some());
181 } else {
182 self.push_null();
183 }
184 Ok(())
185 }
186
187 #[inline]
189 fn push_multi_polygon(
190 &mut self,
191 value: Option<&impl MultiPolygonTrait<T = f64>>,
192 ) -> GeoArrowResult<()> {
193 if let Some(geom) = value {
194 self.geoms.push_multi_polygon(geom)?;
195 self.geom_offsets.try_push_usize(1)?;
196 self.validity.append(value.is_some());
197 } else {
198 self.push_null();
199 }
200 Ok(())
201 }
202
203 #[inline]
205 pub fn push_geometry(
206 &mut self,
207 value: Option<&impl GeometryTrait<T = f64>>,
208 ) -> GeoArrowResult<()> {
209 use geo_traits::GeometryType::*;
210
211 if let Some(g) = value {
212 match g.as_type() {
213 Point(p) => self.push_point(Some(p))?,
214 LineString(p) => {
215 self.push_line_string(Some(p))?;
216 }
217 Polygon(p) => self.push_polygon(Some(p))?,
218 MultiPoint(p) => self.push_multi_point(Some(p))?,
219 MultiLineString(p) => self.push_multi_line_string(Some(p))?,
220 MultiPolygon(p) => self.push_multi_polygon(Some(p))?,
221 GeometryCollection(p) => self.push_geometry_collection(Some(p))?,
222 Rect(r) => self.push_polygon(Some(&RectWrapper::try_new(r)?))?,
223 Triangle(tri) => self.push_polygon(Some(&TriangleWrapper(tri)))?,
224 Line(l) => self.push_line_string(Some(&LineWrapper(l)))?,
225 }
226 } else {
227 self.push_null();
228 };
229 Ok(())
230 }
231
232 #[inline]
234 pub fn push_geometry_collection(
235 &mut self,
236 value: Option<&impl GeometryCollectionTrait<T = f64>>,
237 ) -> GeoArrowResult<()> {
238 if let Some(gc) = value {
239 let num_geoms = gc.num_geometries();
240 for g in gc.geometries() {
241 self.geoms.push_geometry(&g)?;
242 }
243 self.try_push_length(num_geoms)?;
244 } else {
245 self.push_null();
246 }
247 Ok(())
248 }
249
250 pub fn extend_from_iter(
252 &mut self,
253 geoms: impl Iterator<Item = Option<&'a (impl GeometryCollectionTrait<T = f64> + 'a)>>,
254 ) {
255 geoms
256 .into_iter()
257 .try_for_each(|maybe_gc| self.push_geometry_collection(maybe_gc))
258 .unwrap();
259 }
260
261 #[inline]
262 pub(crate) fn try_push_length(&mut self, geom_offsets_length: usize) -> GeoArrowResult<()> {
263 self.geom_offsets.try_push_usize(geom_offsets_length)?;
264 self.validity.append(true);
265 Ok(())
266 }
267
268 #[inline]
269 pub(crate) fn push_null(&mut self) {
270 self.geom_offsets.extend_constant(1);
271 self.validity.append(false);
272 }
273
274 pub fn from_geometry_collections(
276 geoms: &[impl GeometryCollectionTrait<T = f64>],
277 typ: GeometryCollectionType,
278 ) -> GeoArrowResult<Self> {
279 let capacity =
280 GeometryCollectionCapacity::from_geometry_collections(geoms.iter().map(Some))?;
281 let mut array = Self::with_capacity(typ, capacity);
282 array.extend_from_iter(geoms.iter().map(Some));
283 Ok(array)
284 }
285
286 pub fn from_nullable_geometry_collections(
288 geoms: &[Option<impl GeometryCollectionTrait<T = f64>>],
289 typ: GeometryCollectionType,
290 ) -> GeoArrowResult<Self> {
291 let capacity = GeometryCollectionCapacity::from_geometry_collections(
292 geoms.iter().map(|x| x.as_ref()),
293 )?;
294 let mut array = Self::with_capacity(typ, capacity);
295 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
296 Ok(array)
297 }
298
299 pub fn from_nullable_geometries(
301 geoms: &[Option<impl GeometryTrait<T = f64>>],
302 typ: GeometryCollectionType,
303 ) -> GeoArrowResult<Self> {
304 let capacity =
305 GeometryCollectionCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
306 let mut array = Self::with_capacity(typ, capacity);
307 for geom in geoms {
308 array.push_geometry(geom.as_ref())?;
309 }
310 Ok(array)
311 }
312}
313
314impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, GeometryCollectionType)>
315 for GeometryCollectionBuilder
316{
317 type Error = GeoArrowError;
318
319 fn try_from(
320 (value, typ): (GenericWkbArray<O>, GeometryCollectionType),
321 ) -> GeoArrowResult<Self> {
322 let wkb_objects = value
323 .iter()
324 .map(|x| x.transpose())
325 .collect::<GeoArrowResult<Vec<_>>>()?;
326 Self::from_nullable_geometries(&wkb_objects, typ)
327 }
328}
329
330impl GeoArrowArrayBuilder for GeometryCollectionBuilder {
331 fn len(&self) -> usize {
332 self.geom_offsets.len_proxy()
333 }
334
335 fn push_null(&mut self) {
336 self.push_null();
337 }
338
339 fn push_geometry(
340 &mut self,
341 geometry: Option<&impl GeometryTrait<T = f64>>,
342 ) -> GeoArrowResult<()> {
343 self.push_geometry(geometry)
344 }
345
346 fn finish(self) -> Arc<dyn GeoArrowArray> {
347 Arc::new(self.finish())
348 }
349}