1use std::sync::Arc;
2
3use crate::algorithm::geo::{AffineOps, Center, Centroid};
4use crate::array::MultiPointArray;
5use crate::array::*;
6use crate::datatypes::{Dimension, GeoDataType};
7use crate::error::Result;
8use crate::trait_::GeometryArrayAccessor;
9use crate::GeometryArrayTrait;
10use arrow_array::{Float64Array, OffsetSizeTrait};
11use geo::AffineTransform;
12
13pub trait Rotate<DegreesT> {
25 type Output;
26
27 #[must_use]
55 fn rotate_around_centroid(&self, degrees: &DegreesT) -> Self::Output;
56
57 #[must_use]
63 fn rotate_around_center(&self, degrees: &DegreesT) -> Self::Output;
64
65 #[must_use]
93 fn rotate_around_point(&self, degrees: &DegreesT, point: geo::Point) -> Self::Output;
94}
95
96impl Rotate<Float64Array> for PointArray<2> {
102 type Output = Self;
103
104 fn rotate_around_centroid(&self, degrees: &Float64Array) -> Self {
105 let centroids = self.centroid();
106 let transforms: Vec<AffineTransform> = centroids
107 .iter_geo_values()
108 .zip(degrees.values().iter())
109 .map(|(point, angle)| AffineTransform::rotate(*angle, point))
110 .collect();
111 self.affine_transform(transforms.as_slice())
112 }
113
114 fn rotate_around_center(&self, degrees: &Float64Array) -> Self {
115 let centers = self.center();
116 let transforms: Vec<AffineTransform> = centers
117 .iter_geo_values()
118 .zip(degrees.values().iter())
119 .map(|(point, angle)| AffineTransform::rotate(*angle, point))
120 .collect();
121 self.affine_transform(transforms.as_slice())
122 }
123
124 fn rotate_around_point(&self, degrees: &Float64Array, point: geo::Point) -> Self {
125 let transforms: Vec<AffineTransform> = degrees
126 .values()
127 .iter()
128 .map(|degrees| AffineTransform::rotate(*degrees, point))
129 .collect();
130 self.affine_transform(transforms.as_slice())
131 }
132}
133
134macro_rules! iter_geo_impl {
136 ($type:ty) => {
137 impl<O: OffsetSizeTrait> Rotate<Float64Array> for $type {
138 type Output = Self;
139
140 fn rotate_around_centroid(&self, degrees: &Float64Array) -> $type {
141 let centroids = self.centroid();
142 let transforms: Vec<AffineTransform> = centroids
143 .iter_geo_values()
144 .zip(degrees.values().iter())
145 .map(|(point, angle)| AffineTransform::rotate(*angle, point))
146 .collect();
147 self.affine_transform(transforms.as_slice())
148 }
149
150 fn rotate_around_center(&self, degrees: &Float64Array) -> Self {
151 let centers = self.center();
152 let transforms: Vec<AffineTransform> = centers
153 .iter_geo_values()
154 .zip(degrees.values().iter())
155 .map(|(point, angle)| AffineTransform::rotate(*angle, point))
156 .collect();
157 self.affine_transform(transforms.as_slice())
158 }
159
160 fn rotate_around_point(&self, degrees: &Float64Array, point: geo::Point) -> Self {
161 let transforms: Vec<AffineTransform> = degrees
162 .values()
163 .iter()
164 .map(|degrees| AffineTransform::rotate(*degrees, point))
165 .collect();
166 self.affine_transform(transforms.as_slice())
167 }
168 }
169 };
170}
171
172iter_geo_impl!(LineStringArray<O, 2>);
173iter_geo_impl!(PolygonArray<O, 2>);
174iter_geo_impl!(MultiPointArray<O, 2>);
175iter_geo_impl!(MultiLineStringArray<O, 2>);
176iter_geo_impl!(MultiPolygonArray<O, 2>);
177
178impl Rotate<f64> for PointArray<2> {
184 type Output = Self;
185
186 fn rotate_around_centroid(&self, degrees: &f64) -> Self {
187 let centroids = self.centroid();
188 let transforms: Vec<AffineTransform> = centroids
189 .iter_geo_values()
190 .map(|point| AffineTransform::rotate(*degrees, point))
191 .collect();
192 self.affine_transform(transforms.as_slice())
193 }
194
195 fn rotate_around_center(&self, degrees: &f64) -> Self {
196 let centers = self.center();
197 let transforms: Vec<AffineTransform> = centers
198 .iter_geo_values()
199 .map(|point| AffineTransform::rotate(*degrees, point))
200 .collect();
201 self.affine_transform(transforms.as_slice())
202 }
203
204 fn rotate_around_point(&self, degrees: &f64, point: geo::Point) -> Self {
205 let transform = AffineTransform::rotate(*degrees, point);
206 self.affine_transform(&transform)
207 }
208}
209
210macro_rules! iter_geo_impl_scalar {
212 ($type:ty) => {
213 impl<O: OffsetSizeTrait> Rotate<f64> for $type {
214 type Output = Self;
215
216 fn rotate_around_centroid(&self, degrees: &f64) -> $type {
217 let centroids = self.centroid();
218 let transforms: Vec<AffineTransform> = centroids
219 .iter_geo_values()
220 .map(|point| AffineTransform::rotate(*degrees, point))
221 .collect();
222 self.affine_transform(transforms.as_slice())
223 }
224
225 fn rotate_around_center(&self, degrees: &f64) -> Self {
226 let centers = self.center();
227 let transforms: Vec<AffineTransform> = centers
228 .iter_geo_values()
229 .map(|point| AffineTransform::rotate(*degrees, point))
230 .collect();
231 self.affine_transform(transforms.as_slice())
232 }
233
234 fn rotate_around_point(&self, degrees: &f64, point: geo::Point) -> Self {
235 let transform = AffineTransform::rotate(*degrees, point);
236 self.affine_transform(&transform)
237 }
238 }
239 };
240}
241
242iter_geo_impl_scalar!(LineStringArray<O, 2>);
243iter_geo_impl_scalar!(PolygonArray<O, 2>);
244iter_geo_impl_scalar!(MultiPointArray<O, 2>);
245iter_geo_impl_scalar!(MultiLineStringArray<O, 2>);
246iter_geo_impl_scalar!(MultiPolygonArray<O, 2>);
247
248impl Rotate<f64> for &dyn GeometryArrayTrait {
249 type Output = Result<Arc<dyn GeometryArrayTrait>>;
250
251 fn rotate_around_centroid(&self, degrees: &f64) -> Self::Output {
252 macro_rules! impl_method {
253 ($method:ident) => {{
254 Arc::new(self.$method().rotate_around_centroid(degrees))
255 }};
256 }
257
258 use Dimension::*;
259 use GeoDataType::*;
260
261 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
262 Point(_, XY) => impl_method!(as_point),
263 LineString(_, XY) => impl_method!(as_line_string),
264 LargeLineString(_, XY) => impl_method!(as_large_line_string),
265 Polygon(_, XY) => impl_method!(as_polygon),
266 LargePolygon(_, XY) => impl_method!(as_large_polygon),
267 MultiPoint(_, XY) => impl_method!(as_multi_point),
268 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
269 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
270 LargeMultiLineString(_, XY) => {
271 impl_method!(as_large_multi_line_string)
272 }
273 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
274 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
275 _ => todo!("unsupported data type"),
285 };
286
287 Ok(result)
288 }
289
290 fn rotate_around_center(&self, degrees: &f64) -> Self::Output {
291 macro_rules! impl_method {
292 ($method:ident) => {{
293 Arc::new(self.$method().rotate_around_center(degrees))
294 }};
295 }
296
297 use Dimension::*;
298 use GeoDataType::*;
299
300 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
301 Point(_, XY) => impl_method!(as_point),
302 LineString(_, XY) => impl_method!(as_line_string),
303 LargeLineString(_, XY) => impl_method!(as_large_line_string),
304 Polygon(_, XY) => impl_method!(as_polygon),
305 LargePolygon(_, XY) => impl_method!(as_large_polygon),
306 MultiPoint(_, XY) => impl_method!(as_multi_point),
307 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
308 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
309 LargeMultiLineString(_, XY) => {
310 impl_method!(as_large_multi_line_string)
311 }
312 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
313 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
314 _ => todo!("unsupported data type"),
324 };
325
326 Ok(result)
327 }
328
329 fn rotate_around_point(&self, degrees: &f64, point: geo::Point) -> Self::Output {
330 macro_rules! impl_method {
331 ($method:ident) => {{
332 Arc::new(self.$method().rotate_around_point(degrees, point))
333 }};
334 }
335
336 use Dimension::*;
337 use GeoDataType::*;
338
339 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
340 Point(_, XY) => impl_method!(as_point),
341 LineString(_, XY) => impl_method!(as_line_string),
342 LargeLineString(_, XY) => impl_method!(as_large_line_string),
343 Polygon(_, XY) => impl_method!(as_polygon),
344 LargePolygon(_, XY) => impl_method!(as_large_polygon),
345 MultiPoint(_, XY) => impl_method!(as_multi_point),
346 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
347 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
348 LargeMultiLineString(_, XY) => {
349 impl_method!(as_large_multi_line_string)
350 }
351 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
352 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
353 _ => todo!("unsupported data type"),
363 };
364
365 Ok(result)
366 }
367}
368
369impl Rotate<Float64Array> for &dyn GeometryArrayTrait {
370 type Output = Result<Arc<dyn GeometryArrayTrait>>;
371
372 fn rotate_around_centroid(&self, degrees: &Float64Array) -> Self::Output {
373 macro_rules! impl_method {
374 ($method:ident) => {{
375 Arc::new(self.$method().rotate_around_centroid(degrees))
376 }};
377 }
378
379 use Dimension::*;
380 use GeoDataType::*;
381
382 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
383 Point(_, XY) => impl_method!(as_point),
384 LineString(_, XY) => impl_method!(as_line_string),
385 LargeLineString(_, XY) => impl_method!(as_large_line_string),
386 Polygon(_, XY) => impl_method!(as_polygon),
387 LargePolygon(_, XY) => impl_method!(as_large_polygon),
388 MultiPoint(_, XY) => impl_method!(as_multi_point),
389 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
390 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
391 LargeMultiLineString(_, XY) => {
392 impl_method!(as_large_multi_line_string)
393 }
394 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
395 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
396 _ => todo!("unsupported data type"),
406 };
407
408 Ok(result)
409 }
410
411 fn rotate_around_center(&self, degrees: &Float64Array) -> Self::Output {
412 macro_rules! impl_method {
413 ($method:ident) => {{
414 Arc::new(self.$method().rotate_around_center(degrees))
415 }};
416 }
417
418 use Dimension::*;
419 use GeoDataType::*;
420
421 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
422 Point(_, XY) => impl_method!(as_point),
423 LineString(_, XY) => impl_method!(as_line_string),
424 LargeLineString(_, XY) => impl_method!(as_large_line_string),
425 Polygon(_, XY) => impl_method!(as_polygon),
426 LargePolygon(_, XY) => impl_method!(as_large_polygon),
427 MultiPoint(_, XY) => impl_method!(as_multi_point),
428 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
429 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
430 LargeMultiLineString(_, XY) => {
431 impl_method!(as_large_multi_line_string)
432 }
433 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
434 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
435 _ => todo!("unsupported data type"),
445 };
446
447 Ok(result)
448 }
449
450 fn rotate_around_point(&self, degrees: &Float64Array, point: geo::Point) -> Self::Output {
451 macro_rules! impl_method {
452 ($method:ident) => {{
453 Arc::new(self.$method().rotate_around_point(degrees, point))
454 }};
455 }
456
457 use Dimension::*;
458 use GeoDataType::*;
459
460 let result: Arc<dyn GeometryArrayTrait> = match self.data_type() {
461 Point(_, XY) => impl_method!(as_point),
462 LineString(_, XY) => impl_method!(as_line_string),
463 LargeLineString(_, XY) => impl_method!(as_large_line_string),
464 Polygon(_, XY) => impl_method!(as_polygon),
465 LargePolygon(_, XY) => impl_method!(as_large_polygon),
466 MultiPoint(_, XY) => impl_method!(as_multi_point),
467 LargeMultiPoint(_, XY) => impl_method!(as_large_multi_point),
468 MultiLineString(_, XY) => impl_method!(as_multi_line_string),
469 LargeMultiLineString(_, XY) => {
470 impl_method!(as_large_multi_line_string)
471 }
472 MultiPolygon(_, XY) => impl_method!(as_multi_polygon),
473 LargeMultiPolygon(_, XY) => impl_method!(as_large_multi_polygon),
474 _ => todo!("unsupported data type"),
484 };
485
486 Ok(result)
487 }
488}