use alloc::vec::Vec;
use geometry_tag::{MultiLinestringTag, MultiPointTag, MultiPolygonTag};
use geometry_trait::{
Geometry, Linestring as LinestringTrait, MultiLinestring as MultiLinestringTrait,
MultiPoint as MultiPointTrait, MultiPolygon as MultiPolygonTrait, Point as PointTrait,
Polygon as PolygonTrait,
};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct MultiPoint<P: PointTrait>(pub Vec<P>);
impl<P: PointTrait> MultiPoint<P> {
#[must_use]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
pub const fn from_vec(v: Vec<P>) -> Self {
Self(v)
}
pub fn push(&mut self, p: P) {
self.0.push(p);
}
}
impl<P: PointTrait> Default for MultiPoint<P> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<P: PointTrait> Geometry for MultiPoint<P> {
type Kind = MultiPointTag;
type Point = P;
}
impl<P: PointTrait> MultiPointTrait for MultiPoint<P> {
type ItemPoint = P;
fn points(&self) -> impl ExactSizeIterator<Item = &P> {
self.0.iter()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct MultiLinestring<L: LinestringTrait>(pub Vec<L>);
impl<L: LinestringTrait> MultiLinestring<L> {
#[must_use]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
pub const fn from_vec(v: Vec<L>) -> Self {
Self(v)
}
pub fn push(&mut self, ls: L) {
self.0.push(ls);
}
}
impl<L: LinestringTrait> Default for MultiLinestring<L> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<L: LinestringTrait> Geometry for MultiLinestring<L> {
type Kind = MultiLinestringTag;
type Point = L::Point;
}
impl<L: LinestringTrait> MultiLinestringTrait for MultiLinestring<L> {
type ItemLinestring = L;
fn linestrings(&self) -> impl ExactSizeIterator<Item = &L> {
self.0.iter()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct MultiPolygon<Pg: PolygonTrait>(pub Vec<Pg>);
impl<Pg: PolygonTrait> MultiPolygon<Pg> {
#[must_use]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
pub const fn from_vec(v: Vec<Pg>) -> Self {
Self(v)
}
pub fn push(&mut self, pg: Pg) {
self.0.push(pg);
}
}
impl<Pg: PolygonTrait> Default for MultiPolygon<Pg> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<Pg: PolygonTrait> Geometry for MultiPolygon<Pg> {
type Kind = MultiPolygonTag;
type Point = Pg::Point;
}
impl<Pg: PolygonTrait> MultiPolygonTrait for MultiPolygon<Pg> {
type ItemPolygon = Pg;
fn polygons(&self) -> impl ExactSizeIterator<Item = &Pg> {
self.0.iter()
}
}
#[cfg(test)]
mod tests {
use super::{MultiLinestring, MultiPoint, MultiPolygon};
use crate::linestring::Linestring;
use crate::point::Point2D;
use crate::polygon::Polygon;
use crate::ring::Ring;
use alloc::vec;
use alloc::vec::Vec;
use geometry_cs::Cartesian;
use geometry_tag::{MultiLinestringTag, MultiPointTag, MultiPolygonTag};
use geometry_trait::{
Geometry, MultiLinestring as MultiLinestringTrait, MultiPoint as MultiPointTrait,
MultiPolygon as MultiPolygonTrait, Point as _, check_multi_linestring, check_multi_point,
check_multi_polygon,
};
type P = Point2D<f64, Cartesian>;
#[test]
fn multipoint_iterates_in_declared_order() {
let mut mp = MultiPoint::<P>::new();
mp.push(Point2D::new(0.0, 0.0));
mp.push(Point2D::new(1.0, 2.0));
mp.push(Point2D::new(3.0, 4.0));
assert_eq!(mp.points().count(), 3);
let xs: Vec<u64> = mp.points().map(|p| p.get::<0>().to_bits()).collect();
assert_eq!(
xs,
vec![0.0_f64.to_bits(), 1.0_f64.to_bits(), 3.0_f64.to_bits()]
);
}
#[test]
fn multipoint_from_vec_reports_exact_size() {
let mp = MultiPoint::<P>::from_vec(vec![Point2D::new(0.0, 0.0), Point2D::new(1.0, 1.0)]);
assert_eq!(mp.points().len(), 2);
}
#[test]
fn multipoint_kind_is_multi_point_tag() {
fn k<T: Geometry<Kind = MultiPointTag>>() {}
k::<MultiPoint<P>>();
}
#[test]
fn multipoint_satisfies_concept() {
check_multi_point::<MultiPoint<P>>();
}
#[test]
fn multilinestring_iterates_in_declared_order() {
let mut mls = MultiLinestring::<Linestring<P>>::new();
mls.push(Linestring::from_vec(vec![
Point2D::new(0.0, 0.0),
Point2D::new(1.0, 1.0),
]));
mls.push(Linestring::from_vec(vec![
Point2D::new(2.0, 2.0),
Point2D::new(3.0, 3.0),
Point2D::new(4.0, 4.0),
]));
assert_eq!(mls.linestrings().count(), 2);
}
#[test]
fn multilinestring_kind_is_multi_linestring_tag() {
fn k<T: Geometry<Kind = MultiLinestringTag>>() {}
k::<MultiLinestring<Linestring<P>>>();
}
#[test]
fn multilinestring_satisfies_concept() {
check_multi_linestring::<MultiLinestring<Linestring<P>>>();
}
fn unit_square() -> Ring<P> {
Ring::from_vec(vec![
Point2D::new(0.0, 0.0),
Point2D::new(1.0, 0.0),
Point2D::new(1.0, 1.0),
Point2D::new(0.0, 1.0),
Point2D::new(0.0, 0.0),
])
}
#[test]
fn multipolygon_iterates_in_declared_order() {
let mut mpg = MultiPolygon::<Polygon<P>>::new();
mpg.push(Polygon::new(unit_square()));
mpg.push(Polygon::new(unit_square()));
assert_eq!(mpg.polygons().count(), 2);
}
#[test]
fn multipolygon_kind_is_multi_polygon_tag() {
fn k<T: Geometry<Kind = MultiPolygonTag>>() {}
k::<MultiPolygon<Polygon<P>>>();
}
#[test]
fn multipolygon_satisfies_concept() {
check_multi_polygon::<MultiPolygon<Polygon<P>>>();
}
}