use crate::geometry::Geometry;
use crate::ring::Ring;
use geometry_tag::PolygonTag;
pub trait Polygon: Geometry<Kind = PolygonTag> {
type Ring: Ring<Point = Self::Point>;
fn exterior(&self) -> &Self::Ring;
fn interiors(&self) -> impl ExactSizeIterator<Item = &Self::Ring>;
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use crate::point::Point;
use alloc::vec;
use alloc::vec::Vec;
use geometry_cs::Cartesian;
use geometry_tag::{PointTag, RingTag};
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 }
}
}
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()
}
}
#[test]
fn polygon_with_two_inner_rings() {
let poly = VPoly {
outer: VRing(vec![
Xy(0.0, 0.0),
Xy(10.0, 0.0),
Xy(10.0, 10.0),
Xy(0.0, 10.0),
Xy(0.0, 0.0),
]),
inners: vec![
VRing(vec![
Xy(1.0, 1.0),
Xy(2.0, 1.0),
Xy(2.0, 2.0),
Xy(1.0, 2.0),
Xy(1.0, 1.0),
]),
VRing(vec![
Xy(5.0, 5.0),
Xy(6.0, 5.0),
Xy(6.0, 6.0),
Xy(5.0, 6.0),
Xy(5.0, 5.0),
]),
],
};
assert_eq!(poly.exterior().points().count(), 5);
assert_eq!(poly.interiors().count(), 2);
let first = poly.exterior().points().next().unwrap();
assert_eq!(first.get::<0>().to_bits(), 0.0_f64.to_bits());
assert_eq!(first.get::<1>().to_bits(), 0.0_f64.to_bits());
let inner_counts: Vec<usize> = poly.interiors().map(|r| r.points().count()).collect();
assert_eq!(inner_counts, vec![5, 5]);
}
}