geoarrow_array/capacity/
multipolygon.rs1use std::ops::{Add, AddAssign};
2
3use geo_traits::{GeometryTrait, GeometryType, LineStringTrait, MultiPolygonTrait, PolygonTrait};
4use geoarrow_schema::Dimension;
5use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
6
7use crate::capacity::PolygonCapacity;
8use crate::util::GeometryTypeName;
9
10#[derive(Debug, Clone, Copy)]
14pub struct MultiPolygonCapacity {
15 pub(crate) coord_capacity: usize,
16 pub(crate) ring_capacity: usize,
17 pub(crate) polygon_capacity: usize,
18 pub(crate) geom_capacity: usize,
19}
20
21impl MultiPolygonCapacity {
22 pub fn new(
24 coord_capacity: usize,
25 ring_capacity: usize,
26 polygon_capacity: usize,
27 geom_capacity: usize,
28 ) -> Self {
29 Self {
30 coord_capacity,
31 ring_capacity,
32 polygon_capacity,
33 geom_capacity,
34 }
35 }
36
37 pub fn new_empty() -> Self {
39 Self::new(0, 0, 0, 0)
40 }
41
42 pub fn is_empty(&self) -> bool {
44 self.coord_capacity == 0
45 && self.ring_capacity == 0
46 && self.polygon_capacity == 0
47 && self.geom_capacity == 0
48 }
49
50 pub fn coord_capacity(&self) -> usize {
52 self.coord_capacity
53 }
54
55 pub fn ring_capacity(&self) -> usize {
57 self.ring_capacity
58 }
59
60 pub fn polygon_capacity(&self) -> usize {
62 self.polygon_capacity
63 }
64
65 pub fn geom_capacity(&self) -> usize {
67 self.geom_capacity
68 }
69
70 #[inline]
72 pub fn add_polygon<'a>(&mut self, polygon: Option<&'a (impl PolygonTrait + 'a)>) {
73 self.geom_capacity += 1;
74 if let Some(polygon) = polygon {
75 self.polygon_capacity += 1;
77
78 let num_interiors = polygon.num_interiors();
80 self.ring_capacity += num_interiors + 1;
81
82 if let Some(exterior) = polygon.exterior() {
84 self.coord_capacity += exterior.num_coords();
85 }
86
87 for int_ring in polygon.interiors() {
88 self.coord_capacity += int_ring.num_coords();
89 }
90 }
91 }
92
93 #[inline]
95 pub fn add_multi_polygon<'a>(
96 &mut self,
97 multi_polygon: Option<&'a (impl MultiPolygonTrait + 'a)>,
98 ) {
99 self.geom_capacity += 1;
100
101 if let Some(multi_polygon) = multi_polygon {
102 let num_polygons = multi_polygon.num_polygons();
104 self.polygon_capacity += num_polygons;
105
106 for polygon in multi_polygon.polygons() {
107 self.ring_capacity += polygon.num_interiors() + 1;
109
110 if let Some(exterior) = polygon.exterior() {
112 self.coord_capacity += exterior.num_coords();
113 }
114
115 for int_ring in polygon.interiors() {
116 self.coord_capacity += int_ring.num_coords();
117 }
118 }
119 }
120 }
121
122 #[inline]
126 pub fn add_geometry(&mut self, value: Option<&impl GeometryTrait>) -> GeoArrowResult<()> {
127 if let Some(geom) = value {
128 match geom.as_type() {
129 GeometryType::Polygon(g) => self.add_polygon(Some(g)),
130 GeometryType::MultiPolygon(g) => self.add_multi_polygon(Some(g)),
131 gt => {
132 return Err(GeoArrowError::IncorrectGeometryType(format!(
133 "Expected MultiPolygon, got {}",
134 gt.name()
135 )));
136 }
137 }
138 } else {
139 self.geom_capacity += 1;
140 };
141 Ok(())
142 }
143
144 pub fn from_multi_polygons<'a>(
146 geoms: impl Iterator<Item = Option<&'a (impl MultiPolygonTrait + 'a)>>,
147 ) -> Self {
148 let mut counter = Self::new_empty();
149 for maybe_multi_polygon in geoms.into_iter() {
150 counter.add_multi_polygon(maybe_multi_polygon);
151 }
152 counter
153 }
154
155 pub fn from_geometries<'a>(
157 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait + 'a)>>,
158 ) -> GeoArrowResult<Self> {
159 let mut counter = Self::new_empty();
160 for g in geoms.into_iter() {
161 counter.add_geometry(g)?;
162 }
163 Ok(counter)
164 }
165
166 pub fn num_bytes(&self, dim: Dimension) -> usize {
168 let offsets_byte_width = 4;
169 let num_offsets = self.geom_capacity + self.polygon_capacity + self.ring_capacity;
170 (offsets_byte_width * num_offsets) + (self.coord_capacity * dim.size() * 8)
171 }
172}
173
174impl Default for MultiPolygonCapacity {
175 fn default() -> Self {
176 Self::new_empty()
177 }
178}
179
180impl Add for MultiPolygonCapacity {
181 type Output = Self;
182
183 fn add(self, rhs: Self) -> Self::Output {
184 let coord_capacity = self.coord_capacity + rhs.coord_capacity;
185 let ring_capacity = self.ring_capacity + rhs.ring_capacity;
186 let polygon_capacity = self.polygon_capacity + rhs.polygon_capacity;
187 let geom_capacity = self.geom_capacity + rhs.geom_capacity;
188 Self::new(
189 coord_capacity,
190 ring_capacity,
191 polygon_capacity,
192 geom_capacity,
193 )
194 }
195}
196
197impl AddAssign for MultiPolygonCapacity {
198 fn add_assign(&mut self, rhs: Self) {
199 self.coord_capacity += rhs.coord_capacity;
200 self.ring_capacity += rhs.ring_capacity;
201 self.polygon_capacity += rhs.polygon_capacity;
202 self.geom_capacity += rhs.geom_capacity;
203 }
204}
205
206impl AddAssign<PolygonCapacity> for MultiPolygonCapacity {
207 fn add_assign(&mut self, rhs: PolygonCapacity) {
208 self.coord_capacity += rhs.coord_capacity();
209 self.ring_capacity += rhs.ring_capacity();
210 self.polygon_capacity += rhs.geom_capacity();
211 self.geom_capacity += rhs.geom_capacity();
212 }
213}