use crate::closure::Closure;
use crate::geometry::Geometry;
use crate::point_order::PointOrder;
use geometry_tag::RingTag;
pub trait Ring: Geometry<Kind = RingTag> {
fn points(&self) -> impl ExactSizeIterator<Item = &Self::Point> + Clone;
fn closure(&self) -> Closure {
Closure::Closed
}
fn point_order(&self) -> PointOrder {
PointOrder::Clockwise
}
}
#[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;
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()
}
}
#[test]
fn ring_defaults_are_closed_clockwise() {
let r = 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),
]);
assert_eq!(r.closure(), Closure::Closed);
assert_eq!(r.point_order(), PointOrder::Clockwise);
assert_eq!(r.points().count(), 5);
}
#[test]
fn ring_iterates_in_declared_order() {
let r = VRing(vec![Xy(0.0, 0.0), Xy(1.0, 0.0), Xy(0.0, 1.0), Xy(0.0, 0.0)]);
let xs: Vec<f64> = r.points().map(Xy::get::<0>).collect();
assert_eq!(xs, vec![0.0, 1.0, 0.0, 0.0]);
}
struct OpenCcw(Vec<Xy>);
impl Geometry for OpenCcw {
type Kind = RingTag;
type Point = Xy;
}
impl Ring for OpenCcw {
fn points(&self) -> impl ExactSizeIterator<Item = &Xy> + Clone {
self.0.iter()
}
fn closure(&self) -> Closure {
Closure::Open
}
fn point_order(&self) -> PointOrder {
PointOrder::CounterClockwise
}
}
#[test]
fn ring_defaults_can_be_overridden() {
let r = OpenCcw(vec![Xy(0.0, 0.0), Xy(1.0, 0.0), Xy(0.0, 1.0)]);
assert_eq!(r.closure(), Closure::Open);
assert_eq!(r.point_order(), PointOrder::CounterClockwise);
assert_eq!(r.points().count(), 3);
}
}