geoarrow_array/scalar/
geometrycollection.rs

1use arrow_buffer::OffsetBuffer;
2use geo_traits::GeometryCollectionTrait;
3use geoarrow_schema::Dimension;
4
5use crate::array::MixedGeometryArray;
6use crate::eq::geometry_collection_eq;
7use crate::scalar::Geometry;
8use crate::util::OffsetBufferUtils;
9
10/// An Arrow equivalent of a GeometryCollection
11///
12/// This implements [GeometryCollectionTrait], which you can use to extract data.
13#[derive(Debug, Clone)]
14pub struct GeometryCollection<'a> {
15    pub(crate) array: &'a MixedGeometryArray,
16
17    /// Offsets into the geometry array where each geometry starts
18    pub(crate) geom_offsets: &'a OffsetBuffer<i32>,
19
20    pub(crate) geom_index: usize,
21
22    start_offset: usize,
23}
24
25impl<'a> GeometryCollection<'a> {
26    pub(crate) fn new(
27        array: &'a MixedGeometryArray,
28        geom_offsets: &'a OffsetBuffer<i32>,
29        geom_index: usize,
30    ) -> Self {
31        let (start_offset, _) = geom_offsets.start_end(geom_index);
32        Self {
33            array,
34            geom_offsets,
35            geom_index,
36            start_offset,
37        }
38    }
39
40    pub(crate) fn native_dim(&self) -> Dimension {
41        self.array.dim
42    }
43}
44
45impl<'a> GeometryCollectionTrait for GeometryCollection<'a> {
46    type GeometryType<'b>
47        = Geometry<'a>
48    where
49        Self: 'b;
50
51    fn num_geometries(&self) -> usize {
52        let (start, end) = self.geom_offsets.start_end(self.geom_index);
53        end - start
54    }
55
56    unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> {
57        self.array.value(self.start_offset + i)
58    }
59}
60
61impl<'a> GeometryCollectionTrait for &'a GeometryCollection<'a> {
62    type GeometryType<'b>
63        = Geometry<'a>
64    where
65        Self: 'b;
66
67    fn num_geometries(&self) -> usize {
68        let (start, end) = self.geom_offsets.start_end(self.geom_index);
69        end - start
70    }
71
72    unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> {
73        self.array.value(self.start_offset + i)
74    }
75}
76
77impl<G: GeometryCollectionTrait<T = f64>> PartialEq<G> for GeometryCollection<'_> {
78    fn eq(&self, other: &G) -> bool {
79        geometry_collection_eq(self, other)
80    }
81}
82
83// #[cfg(test)]
84// mod tests {
85//     use arrow_buffer::OffsetBufferBuilder;
86
87//     use crate::array::PointArray;
88
89//     use super::*;
90
91//     #[test]
92//     fn stack_overflow_repro_issue_979() {
93//         let orig_point = geo::point!(x: 0., y: 0.);
94//         let array: MixedGeometryArray =
95//             PointArray::from((vec![orig_point].as_slice(), Dimension::XY)).into();
96//         let mut offsets = OffsetBufferBuilder::new(1);
97//         offsets.push_length(1);
98//         let offsets = offsets.finish();
99//         let gc = GeometryCollection::new(&array, &offsets, 0);
100
101//         let out: geo::GeometryCollection = gc.into();
102//         assert_eq!(out.0.len(), 1, "should be one point");
103//         assert_eq!(out.0[0], geo::Geometry::Point(orig_point));
104//     }
105// }