use crate::geometry::Geometry;
use crate::polygon::Polygon;
use geometry_tag::PolyhedralSurfaceTag;
pub trait PolyhedralSurface: Geometry<Kind = PolyhedralSurfaceTag> {
type Face: Polygon<Point = Self::Point>;
fn faces(&self) -> impl ExactSizeIterator<Item = &Self::Face>;
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use crate::point::{Point, PointMut};
use crate::ring::Ring;
use alloc::vec;
use alloc::vec::Vec;
use geometry_cs::Cartesian;
use geometry_tag::{PointTag, PolygonTag, RingTag};
fn accepts_ps<P: PolyhedralSurface>() {}
#[derive(Clone)]
struct Xyz(f64, f64, f64);
impl Geometry for Xyz {
type Kind = PointTag;
type Point = Self;
}
impl Point for Xyz {
type Scalar = f64;
type Cs = Cartesian;
const DIM: usize = 3;
fn get<const D: usize>(&self) -> f64 {
match D {
0 => self.0,
1 => self.1,
_ => self.2,
}
}
}
impl PointMut for Xyz {
fn set<const D: usize>(&mut self, v: f64) {
match D {
0 => self.0 = v,
1 => self.1 = v,
_ => self.2 = v,
}
}
}
struct VRing(Vec<Xyz>);
impl Geometry for VRing {
type Kind = RingTag;
type Point = Xyz;
}
impl Ring for VRing {
fn points(&self) -> impl ExactSizeIterator<Item = &Xyz> + Clone {
self.0.iter()
}
}
struct VPoly {
outer: VRing,
inners: Vec<VRing>,
}
impl Geometry for VPoly {
type Kind = PolygonTag;
type Point = Xyz;
}
impl Polygon for VPoly {
type Ring = VRing;
fn exterior(&self) -> &VRing {
&self.outer
}
fn interiors(&self) -> impl ExactSizeIterator<Item = &VRing> {
self.inners.iter()
}
}
struct VPolyhedral(Vec<VPoly>);
impl Geometry for VPolyhedral {
type Kind = PolyhedralSurfaceTag;
type Point = Xyz;
}
impl PolyhedralSurface for VPolyhedral {
type Face = VPoly;
fn faces(&self) -> impl ExactSizeIterator<Item = &VPoly> {
self.0.iter()
}
}
#[test]
fn vec_backed_polyhedral_surface_satisfies_trait() {
fn quad(a: Xyz, b: Xyz, c: Xyz, d: Xyz) -> VPoly {
let a2 = a.clone();
VPoly {
outer: VRing(vec![a, b, c, d, a2]),
inners: vec![],
}
}
let ps = VPolyhedral(vec![
quad(
Xyz(0.0, 0.0, 0.0),
Xyz(1.0, 0.0, 0.0),
Xyz(1.0, 0.0, 1.0),
Xyz(0.0, 0.0, 1.0),
),
quad(
Xyz(1.0, 0.0, 0.0),
Xyz(1.0, 1.0, 0.0),
Xyz(1.0, 1.0, 1.0),
Xyz(1.0, 0.0, 1.0),
),
quad(
Xyz(1.0, 1.0, 0.0),
Xyz(0.0, 1.0, 0.0),
Xyz(0.0, 1.0, 1.0),
Xyz(1.0, 1.0, 1.0),
),
quad(
Xyz(0.0, 1.0, 0.0),
Xyz(0.0, 0.0, 0.0),
Xyz(0.0, 0.0, 1.0),
Xyz(0.0, 1.0, 1.0),
),
]);
accepts_ps::<VPolyhedral>();
assert_eq!(ps.faces().len(), 4);
let ring_lens: Vec<usize> = ps.faces().map(|f| f.exterior().points().count()).collect();
assert_eq!(ring_lens, vec![5, 5, 5, 5]);
let first_face = ps.faces().next().unwrap();
let v0 = first_face.exterior().points().next().unwrap();
assert_eq!(
(v0.get::<0>(), v0.get::<1>(), v0.get::<2>()),
(0.0, 0.0, 0.0)
);
for face in ps.faces() {
assert_eq!(face.interiors().count(), 0);
}
}
#[test]
fn xyz_point_get_set_round_trips_every_ordinate() {
let mut p = Xyz(0.0, 0.0, 0.0);
p.set::<0>(1.0);
p.set::<1>(2.0);
p.set::<2>(3.0);
assert_eq!((p.get::<0>(), p.get::<1>(), p.get::<2>()), (1.0, 2.0, 3.0));
}
}