use std::collections::{btree_set, BTreeSet};
use fj_interop::mesh::Color;
use fj_math::Winding;
use crate::{
builder::FaceBuilder,
stores::{Handle, Stores},
};
use super::{Cycle, Surface};
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Face {
surface: Handle<Surface>,
exterior: Cycle,
interiors: Vec<Cycle>,
color: Color,
}
impl Face {
pub fn builder(stores: &Stores, surface: Handle<Surface>) -> FaceBuilder {
FaceBuilder {
stores,
surface,
exterior: None,
interiors: Vec::new(),
}
}
pub fn from_exterior(exterior: Cycle) -> Self {
Self {
surface: exterior.surface().clone(),
exterior,
interiors: Vec::new(),
color: Color::default(),
}
}
pub fn with_interiors(
mut self,
interiors: impl IntoIterator<Item = Cycle>,
) -> Self {
for interior in interiors.into_iter() {
assert_eq!(
self.surface().id(),
interior.surface().id(),
"Cycles that bound a face must be in face's surface"
);
assert_ne!(
self.exterior().winding(),
interior.winding(),
"Interior cycles must have opposite winding of exterior cycle"
);
self.interiors.push(interior);
}
self
}
pub fn with_color(mut self, color: Color) -> Self {
self.color = color;
self
}
pub fn surface(&self) -> &Handle<Surface> {
&self.surface
}
pub fn exterior(&self) -> &Cycle {
&self.exterior
}
pub fn interiors(&self) -> impl Iterator<Item = &Cycle> + '_ {
self.interiors.iter()
}
pub fn all_cycles(&self) -> impl Iterator<Item = &Cycle> + '_ {
[self.exterior()].into_iter().chain(self.interiors())
}
pub fn color(&self) -> Color {
self.color
}
pub fn coord_handedness(&self) -> Handedness {
match self.exterior().winding() {
Winding::Ccw => Handedness::RightHanded,
Winding::Cw => Handedness::LeftHanded,
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Faces {
inner: BTreeSet<Face>,
}
impl Faces {
pub fn new() -> Self {
Self::default()
}
pub fn find(&self, face: &Face) -> Option<Face> {
for f in self {
if f == face {
return Some(f.clone());
}
}
None
}
}
impl Extend<Face> for Faces {
fn extend<T: IntoIterator<Item = Face>>(&mut self, iter: T) {
self.inner.extend(iter)
}
}
impl IntoIterator for Faces {
type Item = Face;
type IntoIter = btree_set::IntoIter<Face>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a> IntoIterator for &'a Faces {
type Item = &'a Face;
type IntoIter = btree_set::Iter<'a, Face>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Handedness {
LeftHanded,
RightHanded,
}