1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
use crate::array::*;
use crate::GeometryArrayTrait;
use arrow_array::OffsetSizeTrait;
use geo::MinimumRotatedRect as _MinimumRotatedRect;
/// Return the minimum bounding rectangle(MBR) of geometry
/// reference: <https://en.wikipedia.org/wiki/Minimum_bounding_box>
/// minimum rotated rect is the rectangle that can enclose all points given
/// and have smallest area of all enclosing rectangles
/// the rect can be any-oriented, not only axis-aligned.
///
/// # Examples
///
/// ```
/// use geo::{line_string, polygon, LineString, Polygon};
/// use geo::MinimumRotatedRect;
/// let poly: Polygon<f64> = polygon![(x: 3.3, y: 30.4), (x: 1.7, y: 24.6), (x: 13.4, y: 25.1), (x: 14.4, y: 31.0),(x:3.3,y:30.4)];
/// let mbr = MinimumRotatedRect::minimum_rotated_rect(&poly).unwrap();
/// assert_eq!(
/// mbr.exterior(),
/// &LineString::from(vec![
/// (1.7000000000000006, 24.6),
/// (1.4501458363715918, 30.446587428904767),
/// (14.4, 31.0),
/// (14.649854163628408, 25.153412571095235),
/// (1.7000000000000006, 24.6),
/// ])
/// );
/// ```
pub trait MinimumRotatedRect<O: OffsetSizeTrait> {
fn minimum_rotated_rect(&self) -> PolygonArray<O>;
}
// Note: this can't (easily) be parameterized in the macro because PointArray is not generic over O
impl MinimumRotatedRect<i32> for PointArray {
fn minimum_rotated_rect(&self) -> PolygonArray<i32> {
// The number of output geoms is the same as the input
let geom_capacity = self.len();
// Each output polygon is a simple polygon with only one ring
let ring_capacity = geom_capacity;
// Each output polygon has exactly 5 coordinates
let coord_capacity = ring_capacity * 5;
let mut output_array =
MutablePolygonArray::with_capacities(coord_capacity, ring_capacity, geom_capacity);
self.iter_geo().for_each(|maybe_g| {
output_array
.push_polygon(maybe_g.and_then(|g| g.minimum_rotated_rect()).as_ref())
.unwrap()
});
output_array.into()
}
}
impl MinimumRotatedRect<i64> for PointArray {
fn minimum_rotated_rect(&self) -> PolygonArray<i64> {
// The number of output geoms is the same as the input
let geom_capacity = self.len();
// Each output polygon is a simple polygon with only one ring
let ring_capacity = geom_capacity;
// Each output polygon has exactly 5 coordinates
let coord_capacity = ring_capacity * 5;
let mut output_array =
MutablePolygonArray::with_capacities(coord_capacity, ring_capacity, geom_capacity);
self.iter_geo().for_each(|maybe_g| {
output_array
.push_polygon(maybe_g.and_then(|g| g.minimum_rotated_rect()).as_ref())
.unwrap()
});
output_array.into()
}
}
/// Implementation that iterates over geo objects
macro_rules! iter_geo_impl {
($type:ty, $offset_type:ty) => {
impl<O: OffsetSizeTrait> MinimumRotatedRect<$offset_type> for $type {
fn minimum_rotated_rect(&self) -> PolygonArray<$offset_type> {
// The number of output geoms is the same as the input
let geom_capacity = self.len();
// Each output polygon is a simple polygon with only one ring
let ring_capacity = geom_capacity;
// Each output polygon has exactly 5 coordinates
let coord_capacity = ring_capacity * 5;
let mut output_array = MutablePolygonArray::with_capacities(
coord_capacity,
ring_capacity,
geom_capacity,
);
self.iter_geo().for_each(|maybe_g| {
output_array
.push_polygon(maybe_g.and_then(|g| g.minimum_rotated_rect()).as_ref())
.unwrap()
});
output_array.into()
}
}
};
}
iter_geo_impl!(LineStringArray<O>, i32);
iter_geo_impl!(LineStringArray<O>, i64);
iter_geo_impl!(PolygonArray<O>, i32);
iter_geo_impl!(PolygonArray<O>, i64);
iter_geo_impl!(MultiPointArray<O>, i32);
iter_geo_impl!(MultiPointArray<O>, i64);
iter_geo_impl!(MultiLineStringArray<O>, i32);
iter_geo_impl!(MultiLineStringArray<O>, i64);
iter_geo_impl!(MultiPolygonArray<O>, i32);
iter_geo_impl!(MultiPolygonArray<O>, i64);
impl<O: OffsetSizeTrait> MinimumRotatedRect<i32> for GeometryArray<O> {
crate::geometry_array_delegate_impl! {
fn minimum_rotated_rect(&self) -> PolygonArray<i32>;
}
}
// impl<O: OffsetSizeTrait> MinimumRotatedRect<i64> for GeometryArray<O> {
// crate::geometry_array_delegate_impl! {
// fn minimum_rotated_rect(&self) -> PolygonArray<i64>;
// }
// }