geoarrow_array/scalar/
multipolygon.rs

1use arrow_buffer::OffsetBuffer;
2use geo_traits::MultiPolygonTrait;
3use geoarrow_schema::Dimension;
4
5use crate::array::CoordBuffer;
6use crate::eq::multi_polygon_eq;
7use crate::scalar::Polygon;
8use crate::util::OffsetBufferUtils;
9
10/// An Arrow equivalent of a MultiPolygon
11///
12/// This implements [MultiPolygonTrait], which you can use to extract data.
13#[derive(Debug, Clone)]
14pub struct MultiPolygon<'a> {
15    pub(crate) coords: &'a CoordBuffer,
16
17    /// Offsets into the polygon array where each geometry starts
18    pub(crate) geom_offsets: &'a OffsetBuffer<i32>,
19
20    /// Offsets into the ring array where each polygon starts
21    pub(crate) polygon_offsets: &'a OffsetBuffer<i32>,
22
23    /// Offsets into the coordinate array where each ring starts
24    pub(crate) ring_offsets: &'a OffsetBuffer<i32>,
25
26    pub(crate) geom_index: usize,
27
28    start_offset: usize,
29}
30
31impl<'a> MultiPolygon<'a> {
32    pub(crate) fn new(
33        coords: &'a CoordBuffer,
34        geom_offsets: &'a OffsetBuffer<i32>,
35        polygon_offsets: &'a OffsetBuffer<i32>,
36        ring_offsets: &'a OffsetBuffer<i32>,
37        geom_index: usize,
38    ) -> Self {
39        let (start_offset, _) = geom_offsets.start_end(geom_index);
40        Self {
41            coords,
42            geom_offsets,
43            polygon_offsets,
44            ring_offsets,
45            geom_index,
46            start_offset,
47        }
48    }
49
50    pub(crate) fn native_dim(&self) -> Dimension {
51        self.coords.dim()
52    }
53}
54
55impl<'a> MultiPolygonTrait for MultiPolygon<'a> {
56    type InnerPolygonType<'b>
57        = Polygon<'a>
58    where
59        Self: 'b;
60
61    fn num_polygons(&self) -> usize {
62        let (start, end) = self.geom_offsets.start_end(self.geom_index);
63        end - start
64    }
65
66    unsafe fn polygon_unchecked(&self, i: usize) -> Self::InnerPolygonType<'_> {
67        Polygon::new(
68            self.coords,
69            self.polygon_offsets,
70            self.ring_offsets,
71            self.start_offset + i,
72        )
73    }
74}
75
76impl<'a> MultiPolygonTrait for &'a MultiPolygon<'a> {
77    type InnerPolygonType<'b>
78        = Polygon<'a>
79    where
80        Self: 'b;
81
82    fn num_polygons(&self) -> usize {
83        let (start, end) = self.geom_offsets.start_end(self.geom_index);
84        end - start
85    }
86
87    unsafe fn polygon_unchecked(&self, i: usize) -> Self::InnerPolygonType<'_> {
88        Polygon::new(
89            self.coords,
90            self.polygon_offsets,
91            self.ring_offsets,
92            self.start_offset + i,
93        )
94    }
95}
96
97impl<G: MultiPolygonTrait<T = f64>> PartialEq<G> for MultiPolygon<'_> {
98    fn eq(&self, other: &G) -> bool {
99        multi_polygon_eq(self, other)
100    }
101}
102
103// #[cfg(test)]
104// mod test {
105//     use crate::array::MultiPolygonArray;
106//     use crate::test::multipolygon::{mp0, mp1};
107//     use crate::trait_::ArrayAccessor;
108//     use geoarrow_schema::Dimension;
109
110//     /// Test Eq where the current index is true but another index is false
111//     #[test]
112//     fn test_eq_other_index_false() {
113//         let arr1: MultiPolygonArray = (vec![mp0(), mp1()].as_slice(), Dimension::XY).into();
114//         let arr2: MultiPolygonArray = (vec![mp0(), mp0()].as_slice(), Dimension::XY).into();
115
116//         assert_eq!(arr1.value(0), arr2.value(0));
117//         assert_ne!(arr1.value(1), arr2.value(1));
118//     }
119// }