use crate::{CoordNum, Geometry};
use alloc::vec;
use alloc::vec::Vec;
use core::iter::FromIterator;
use core::ops::{Index, IndexMut};
use core::slice::SliceIndex;
#[derive(Eq, PartialEq, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GeometryCollection<T: CoordNum = f64>(pub Vec<Geometry<T>>);
impl<T: CoordNum> Default for GeometryCollection<T> {
fn default() -> Self {
Self(Vec::new())
}
}
impl<T: CoordNum> GeometryCollection<T> {
#[deprecated(
note = "Will be replaced with a parametrized version in upcoming version. Use GeometryCollection::empty() instead"
)]
pub fn new() -> Self {
GeometryCollection::default()
}
pub fn new_from(value: Vec<Geometry<T>>) -> Self {
Self(value)
}
pub fn empty() -> Self {
Self(Vec::new())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<T: CoordNum, IG: Into<Geometry<T>>> From<IG> for GeometryCollection<T> {
fn from(x: IG) -> Self {
Self(vec![x.into()])
}
}
impl<T: CoordNum, IG: Into<Geometry<T>>> From<Vec<IG>> for GeometryCollection<T> {
fn from(geoms: Vec<IG>) -> Self {
let geoms: Vec<Geometry<_>> = geoms.into_iter().map(Into::into).collect();
Self(geoms)
}
}
impl<T: CoordNum, IG: Into<Geometry<T>>> FromIterator<IG> for GeometryCollection<T> {
fn from_iter<I: IntoIterator<Item = IG>>(iter: I) -> Self {
Self(iter.into_iter().map(|g| g.into()).collect())
}
}
impl<T: CoordNum, I: SliceIndex<[Geometry<T>]>> Index<I> for GeometryCollection<T> {
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
self.0.index(index)
}
}
impl<T: CoordNum, I: SliceIndex<[Geometry<T>]>> IndexMut<I> for GeometryCollection<T> {
fn index_mut(&mut self, index: I) -> &mut I::Output {
self.0.index_mut(index)
}
}
#[derive(Debug)]
pub struct IntoIteratorHelper<T: CoordNum> {
iter: ::alloc::vec::IntoIter<Geometry<T>>,
}
impl<T: CoordNum> IntoIterator for GeometryCollection<T> {
type Item = Geometry<T>;
type IntoIter = IntoIteratorHelper<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIteratorHelper {
iter: self.0.into_iter(),
}
}
}
impl<T: CoordNum> Iterator for IntoIteratorHelper<T> {
type Item = Geometry<T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
#[derive(Debug)]
pub struct IterHelper<'a, T: CoordNum> {
iter: ::core::slice::Iter<'a, Geometry<T>>,
}
impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection<T> {
type Item = &'a Geometry<T>;
type IntoIter = IterHelper<'a, T>;
fn into_iter(self) -> Self::IntoIter {
IterHelper {
iter: self.0.iter(),
}
}
}
impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> {
type Item = &'a Geometry<T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
#[derive(Debug)]
pub struct IterMutHelper<'a, T: CoordNum> {
iter: ::core::slice::IterMut<'a, Geometry<T>>,
}
impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection<T> {
type Item = &'a mut Geometry<T>;
type IntoIter = IterMutHelper<'a, T>;
fn into_iter(self) -> Self::IntoIter {
IterMutHelper {
iter: self.0.iter_mut(),
}
}
}
impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> {
type Item = &'a mut Geometry<T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
impl<'a, T: CoordNum> GeometryCollection<T> {
pub fn iter(&'a self) -> IterHelper<'a, T> {
self.into_iter()
}
pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T> {
self.into_iter()
}
}
#[cfg(any(feature = "approx", test))]
mod approx_integration {
use super::*;
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
impl<T> RelativeEq for GeometryCollection<T>
where
T: CoordNum + RelativeEq<Epsilon = T>,
{
#[inline]
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
if self.0.len() != other.0.len() {
return false;
}
self.iter()
.zip(other.iter())
.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
}
}
impl<T> AbsDiffEq for GeometryCollection<T>
where
T: CoordNum + AbsDiffEq<Epsilon = T>,
{
type Epsilon = T;
#[inline]
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
if self.0.len() != other.0.len() {
return false;
}
self.into_iter()
.zip(other)
.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
}
}
impl<T> UlpsEq for GeometryCollection<T>
where
T: CoordNum + UlpsEq<Epsilon = T>,
{
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
if self.0.len() != other.0.len() {
return false;
}
self.into_iter()
.zip(other)
.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
}
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use crate::{point, wkt, GeometryCollection, Point};
#[test]
fn from_vec() {
let gc = GeometryCollection::from(vec![Point::new(1i32, 2)]);
let p = Point::try_from(gc[0].clone()).unwrap();
assert_eq!(p.y(), 2);
}
#[test]
fn empty() {
let empty = GeometryCollection::<f64>::empty();
let empty_2 = wkt! { GEOMETRYCOLLECTION EMPTY };
assert_eq!(empty, empty_2);
}
#[test]
fn test_indexing() {
let mut gc = wkt! { GEOMETRYCOLLECTION(POINT(0. 0.), POINT(1. 1.), POINT(2. 2.)) };
assert_eq!(gc[0], point! { x: 0., y: 0. }.into());
assert_eq!(gc[1], point! { x: 1., y: 1. }.into());
gc[1] = point! { x: 100., y: 100. }.into();
assert_eq!(gc[1], point! { x: 100., y: 100. }.into());
assert_eq!(
gc[0..2],
[
point! { x: 0., y: 0. }.into(),
point! { x: 100., y: 100. }.into()
]
);
}
#[test]
#[should_panic]
fn test_indexing_out_of_bounds() {
let gc = wkt! { GEOMETRYCOLLECTION(POINT(0. 0.), POINT(1. 1.)) };
let _ = gc[2];
}
}