use crate::geometry::Geometry;
use crate::linestring::Linestring;
use crate::point::Point;
use crate::polygon::Polygon;
use geometry_tag::{MultiLinestringTag, MultiPointTag, MultiPolygonTag};
pub trait MultiPoint: Geometry<Kind = MultiPointTag> {
type ItemPoint: Point;
fn points(&self) -> impl ExactSizeIterator<Item = &Self::ItemPoint>;
}
pub trait MultiLinestring: Geometry<Kind = MultiLinestringTag> {
type ItemLinestring: Linestring<Point = Self::Point>;
fn linestrings(&self) -> impl ExactSizeIterator<Item = &Self::ItemLinestring>;
}
pub trait MultiPolygon: Geometry<Kind = MultiPolygonTag> {
type ItemPolygon: Polygon<Point = Self::Point>;
fn polygons(&self) -> impl ExactSizeIterator<Item = &Self::ItemPolygon>;
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use crate::point::PointMut;
use crate::ring::Ring;
use alloc::vec;
use alloc::vec::Vec;
use geometry_cs::Cartesian;
use geometry_tag::{LinestringTag, PointTag, PolygonTag, RingTag};
fn accepts_mp<M: MultiPoint>() {}
fn accepts_mls<M: MultiLinestring>() {}
fn accepts_mpg<M: MultiPolygon>() {}
#[derive(Clone)]
struct Xy(f64, f64);
impl Geometry for Xy {
type Kind = PointTag;
type Point = Self;
}
impl Point for Xy {
type Scalar = f64;
type Cs = Cartesian;
const DIM: usize = 2;
fn get<const D: usize>(&self) -> f64 {
if D == 0 { self.0 } else { self.1 }
}
}
impl PointMut for Xy {
fn set<const D: usize>(&mut self, v: f64) {
if D == 0 {
self.0 = v;
} else {
self.1 = v;
}
}
}
struct VMp(Vec<Xy>);
impl Geometry for VMp {
type Kind = MultiPointTag;
type Point = Xy;
}
impl MultiPoint for VMp {
type ItemPoint = Xy;
fn points(&self) -> impl ExactSizeIterator<Item = &Xy> {
self.0.iter()
}
}
#[test]
fn vec_backed_multipoint_satisfies_trait() {
let mp = VMp(vec![Xy(0.0, 0.0), Xy(1.0, 2.0), Xy(3.0, 4.0)]);
accepts_mp::<VMp>();
assert_eq!(mp.points().len(), 3);
let xs: Vec<f64> = mp.points().map(Xy::get::<0>).collect();
assert_eq!(xs, vec![0.0, 1.0, 3.0]);
}
struct VLs(Vec<Xy>);
impl Geometry for VLs {
type Kind = LinestringTag;
type Point = Xy;
}
impl Linestring for VLs {
fn points(&self) -> impl ExactSizeIterator<Item = &Xy> + Clone {
self.0.iter()
}
}
struct VMls(Vec<VLs>);
impl Geometry for VMls {
type Kind = MultiLinestringTag;
type Point = Xy;
}
impl MultiLinestring for VMls {
type ItemLinestring = VLs;
fn linestrings(&self) -> impl ExactSizeIterator<Item = &VLs> {
self.0.iter()
}
}
#[test]
fn vec_backed_multilinestring_satisfies_trait() {
let mls = VMls(vec![
VLs(vec![Xy(0.0, 0.0), Xy(1.0, 1.0)]),
VLs(vec![Xy(2.0, 2.0), Xy(3.0, 3.0), Xy(4.0, 4.0)]),
]);
accepts_mls::<VMls>();
assert_eq!(mls.linestrings().len(), 2);
let counts: Vec<usize> = mls.linestrings().map(|ls| ls.points().count()).collect();
assert_eq!(counts, vec![2, 3]);
}
struct VRing(Vec<Xy>);
impl Geometry for VRing {
type Kind = RingTag;
type Point = Xy;
}
impl Ring for VRing {
fn points(&self) -> impl ExactSizeIterator<Item = &Xy> + Clone {
self.0.iter()
}
}
struct VPoly {
outer: VRing,
inners: Vec<VRing>,
}
impl Geometry for VPoly {
type Kind = PolygonTag;
type Point = Xy;
}
impl Polygon for VPoly {
type Ring = VRing;
fn exterior(&self) -> &VRing {
&self.outer
}
fn interiors(&self) -> impl ExactSizeIterator<Item = &VRing> {
self.inners.iter()
}
}
struct VMpg(Vec<VPoly>);
impl Geometry for VMpg {
type Kind = MultiPolygonTag;
type Point = Xy;
}
impl MultiPolygon for VMpg {
type ItemPolygon = VPoly;
fn polygons(&self) -> impl ExactSizeIterator<Item = &VPoly> {
self.0.iter()
}
}
#[test]
fn vec_backed_multipolygon_satisfies_trait() {
let mpg = VMpg(vec![
VPoly {
outer: VRing(vec![
Xy(0.0, 0.0),
Xy(1.0, 0.0),
Xy(1.0, 1.0),
Xy(0.0, 1.0),
Xy(0.0, 0.0),
]),
inners: vec![],
},
VPoly {
outer: VRing(vec![
Xy(2.0, 2.0),
Xy(3.0, 2.0),
Xy(3.0, 3.0),
Xy(2.0, 3.0),
Xy(2.0, 2.0),
]),
inners: vec![VRing(vec![
Xy(2.25, 2.25),
Xy(2.75, 2.25),
Xy(2.75, 2.75),
Xy(2.25, 2.75),
Xy(2.25, 2.25),
])],
},
]);
accepts_mpg::<VMpg>();
assert_eq!(mpg.polygons().len(), 2);
let inner_counts: Vec<usize> = mpg.polygons().map(|p| p.interiors().count()).collect();
assert_eq!(inner_counts, vec![0, 1]);
}
}