use crate::geom::{vertex, Cuboid, Range, Rect, Scalar, Vertex, Vertex2d, Vertex3d};
use crate::math::num_traits::Zero;
use core::ops::Deref;
pub const NUM_VERTICES: u8 = 3;
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Tri<V = vertex::Default>(pub [V; NUM_VERTICES as usize]);
#[derive(Clone, Debug)]
pub struct Vertices<V = vertex::Default> {
tri: Tri<V>,
index: u8,
}
#[derive(Clone, Debug)]
pub struct IterFromVertices<I> {
vertices: I,
}
#[derive(Clone, Debug)]
pub struct VerticesFromIter<I, V = vertex::Default> {
tris: I,
tri: Option<Vertices<V>>,
}
#[derive(Clone, Debug)]
pub struct FlattenIndices<I> {
indices: I,
b: Option<usize>,
c: Option<usize>,
}
impl<V> Tri<V> {
pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Self
where
V: Clone,
{
from_index_tri(vertices, indices)
}
pub fn from_vertices<I>(vertices: I) -> Option<Self>
where
I: IntoIterator<Item = V>,
{
from_vertices(vertices)
}
pub fn vertices(self) -> Vertices<V> {
let tri = self;
let index = 0;
Vertices { tri, index }
}
pub fn centroid(self) -> V
where
V: vertex::Average,
{
crate::geom::centroid(self[..].iter().cloned()).unwrap()
}
pub fn map_vertices<F, V2>(self, mut map: F) -> Tri<V2>
where
F: FnMut(V) -> V2,
{
let Tri([a, b, c]) = self;
Tri([map(a), map(b), map(c)])
}
pub fn contains(&self, v: &V) -> bool
where
V: Vertex2d,
{
let (a, b, c) = (*self).into();
let (a, b, c) = (a.point2(), b.point2(), c.point2());
let v = (*v).point2();
fn sign<S>([ax, ay]: [S; 2], [bx, by]: [S; 2], [cx, cy]: [S; 2]) -> S
where
S: Scalar,
{
(ax - cx) * (by - cy) - (bx - cx) * (ay - cy)
}
let b1 = sign(v, a, b) < V::Scalar::zero();
let b2 = sign(v, b, c) < V::Scalar::zero();
let b3 = sign(v, c, a) < V::Scalar::zero();
(b1 == b2) && (b2 == b3)
}
pub fn bounding_rect(self) -> Rect<V::Scalar>
where
V: Vertex2d,
{
let (a, b, c) = self.into();
let ([ax, ay], b, c) = (a.point2(), b.point2(), c.point2());
let rect = Rect {
x: Range::new(ax, ax),
y: Range::new(ay, ay),
};
rect.stretch_to_point(b).stretch_to_point(c)
}
pub fn bounding_cuboid(self) -> Cuboid<V::Scalar>
where
V: Vertex3d,
{
let (a, b, c) = self.into();
let ([ax, ay, az], b, c) = (a.point3(), b.point3(), c.point3());
let cuboid = Cuboid {
x: Range::new(ax, ax),
y: Range::new(ay, ay),
z: Range::new(az, az),
};
cuboid.stretch_to_point(b).stretch_to_point(c)
}
}
pub fn iter_contains<I, V>(tris: I, v: &V) -> Option<I::Item>
where
I: IntoIterator,
I::Item: AsRef<Tri<V>>,
V: Vertex2d,
{
tris.into_iter().find(|tri| tri.as_ref().contains(v))
}
pub fn from_vertices<I>(vertices: I) -> Option<Tri<I::Item>>
where
I: IntoIterator,
{
let mut vertices = vertices.into_iter();
match (vertices.next(), vertices.next(), vertices.next()) {
(Some(a), Some(b), Some(c)) => Some(Tri([a, b, c])),
_ => None,
}
}
pub fn iter_from_vertices<I>(vertices: I) -> IterFromVertices<I::IntoIter>
where
I: IntoIterator,
{
let vertices = vertices.into_iter();
IterFromVertices { vertices }
}
pub fn from_index_tri<V>(vertices: &[V], indices: &[usize; 3]) -> Tri<V>
where
V: Clone,
{
let a = vertices[indices[0]].clone();
let b = vertices[indices[1]].clone();
let c = vertices[indices[2]].clone();
Tri([a, b, c])
}
pub fn vertices_from_iter<I, V>(tris: I) -> VerticesFromIter<I::IntoIter, V>
where
I: IntoIterator<Item = Tri<V>>,
{
let tris = tris.into_iter();
let tri = None;
VerticesFromIter { tris, tri }
}
pub fn flatten_index_tris<I>(index_tris: I) -> FlattenIndices<I::IntoIter>
where
I: IntoIterator<Item = [usize; 3]>,
{
FlattenIndices {
indices: index_tris.into_iter(),
b: None,
c: None,
}
}
impl<V> Deref for Tri<V> {
type Target = [V; 3];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> From<[V; 3]> for Tri<V> {
fn from(points: [V; 3]) -> Self {
Tri(points)
}
}
impl<V> From<(V, V, V)> for Tri<V> {
fn from((a, b, c): (V, V, V)) -> Self {
Tri([a, b, c])
}
}
impl<V> Into<[V; 3]> for Tri<V> {
fn into(self) -> [V; 3] {
self.0
}
}
impl<V> Into<(V, V, V)> for Tri<V> {
fn into(self) -> (V, V, V) {
let Tri([a, b, c]) = self;
(a, b, c)
}
}
impl<V> AsRef<Tri<V>> for Tri<V> {
fn as_ref(&self) -> &Tri<V> {
self
}
}
impl<V> AsRef<[V; 3]> for Tri<V> {
fn as_ref(&self) -> &[V; 3] {
&self.0
}
}
impl<V> Iterator for Vertices<V>
where
V: Clone,
{
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
if self.index < NUM_VERTICES {
let v = self.tri.0[self.index as usize].clone();
self.index += 1;
Some(v)
} else {
None
}
}
}
impl<V> ExactSizeIterator for Vertices<V>
where
V: Clone,
{
fn len(&self) -> usize {
NUM_VERTICES as usize - self.index as usize
}
}
impl<I> Iterator for IterFromVertices<I>
where
I: Iterator,
{
type Item = Tri<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
from_vertices(&mut self.vertices)
}
}
impl<I, V> Iterator for VerticesFromIter<I, V>
where
I: Iterator<Item = Tri<V>>,
V: Vertex,
{
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(v) = self.tri.as_mut().and_then(|vs| vs.next()) {
return Some(v);
}
match self.tris.next() {
Some(t) => self.tri = Some(t.vertices()),
None => return None,
}
}
}
}
impl<I, V> ExactSizeIterator for VerticesFromIter<I, V>
where
I: Iterator<Item = Tri<V>> + ExactSizeIterator,
V: Vertex,
{
fn len(&self) -> usize {
let current_tri_vs = self.tri.as_ref().map(|vs| vs.len()).unwrap_or(0);
let remaining_tri_vs = self.tris.len() * NUM_VERTICES as usize;
current_tri_vs + remaining_tri_vs
}
}
impl<I> Iterator for FlattenIndices<I>
where
I: Iterator<Item = [usize; 3]>,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.b.take() {
return Some(next);
}
if let Some(next) = self.c.take() {
return Some(next);
}
if let Some([next, b, c]) = self.indices.next() {
self.b = Some(b);
self.c = Some(c);
return Some(next);
}
None
}
}
impl<I> ExactSizeIterator for FlattenIndices<I>
where
I: Iterator<Item = [usize; 3]> + ExactSizeIterator,
{
fn len(&self) -> usize {
self.indices.len() * 3 + self.b.map(|_| 1).unwrap_or(0) + self.c.map(|_| 1).unwrap_or(0)
}
}