#[cfg(test)]
mod tests;
use std::fmt::Debug;
use glam::IVec3;
use itertools::Itertools;
use crate::denominator::ImplicitDenominator;
use crate::subdivision::triangle::Triangle;
const fn compute_vertex_index_unchecked(n: u32, v: IVec3) -> usize {
let x_offset = (v.x * (2 * (n + 1) as i32 + 1 - v.x) / 2) as usize;
let y_offset = v.y as usize;
x_offset + y_offset
}
pub const fn n_triangles(n: u32) -> usize {
(n * n) as usize
}
pub const fn n_vertices(n: u32) -> usize {
((n + 1) * (n + 2) / 2) as usize
}
pub const fn n_triangles_up(n: u32) -> usize {
(n * (n + 1) / 2) as usize
}
pub const fn n_triangles_down(n: u32) -> usize {
(n * (n - 1) / 2) as usize
}
pub const fn n_edges(n: u32) -> usize {
n_triangles_up(n) * 3
}
#[derive(Clone, Debug)]
pub struct SubdividedTriangle<const N: u32> {
pub vertices: Vec<ImplicitDenominator<IVec3, N>>,
pub triangles: Vec<Triangle<usize>>,
}
impl<const N: u32> SubdividedTriangle<N> {
pub const TRIANGLES: usize = n_triangles(N);
pub const VERTICES: usize = n_vertices(N);
pub const EDGES: usize = n_edges(N);
const TRIANGLES_UP: usize = n_triangles_up(N);
const TRIANGLES_DOWN: usize = n_triangles_down(N);
pub fn new() -> Self {
assert_ne!(N, 0, "Number of subdivisions must be nonzero.");
let mut vertices = vec![ImplicitDenominator::new(IVec3::ZERO); Self::VERTICES];
let axis = 0..(N + 1);
axis.clone()
.cartesian_product(axis.clone())
.cartesian_product(axis.clone())
.filter(|((x, y), z)| x + y + z == N)
.map(|((x, y), z)| ImplicitDenominator::wrap(IVec3::new(x as i32, y as i32, z as i32)))
.enumerate()
.for_each(|(i, v)| vertices[i] = v);
let du = ImplicitDenominator::<_, N>::wrap(IVec3::new(-1, 1, 0));
let dv = ImplicitDenominator::<_, N>::wrap(IVec3::new(-1, 0, 1));
let triangles_up = vertices.iter()
.filter(|v| v.x > 0 && v.y < N as i32 && v.z < N as i32)
.map(|v| Triangle::new(
Self::compute_vertex_index_unchecked(v.inner()),
Self::compute_vertex_index_unchecked((v + du).inner()),
Self::compute_vertex_index_unchecked((v + dv).inner())
));
let triangles_down = vertices.iter()
.filter(|v| v.x < N as i32 && v.y > 0 && v.z > 0)
.map(|v| Triangle::new(
Self::compute_vertex_index_unchecked(v.inner()),
Self::compute_vertex_index_unchecked((v - du).inner()),
Self::compute_vertex_index_unchecked((v - dv).inner()),
));
let mut triangles = vec![Triangle::new(0, 0, 0); Self::TRIANGLES];
triangles_up
.chain(triangles_down)
.enumerate()
.for_each(|(i, t)| triangles[i] = t);
Self {
vertices,
triangles,
}
}
const fn upward_row(&self, i: usize) -> impl Iterator<Item = usize> {
if i >= N as usize {
0..0
} else {
let k = N as usize - i;
let start = Self::TRIANGLES_UP - k * (k + 1) / 2;
let end = start + k;
start..end
}
}
const fn downward_row(&self, i: usize) -> impl Iterator<Item = usize> {
if i >= N as usize - 1 {
0..0
} else {
let k = N as usize - 1 - i;
let start = Self::TRIANGLES_UP + Self::TRIANGLES_DOWN - k * (k + 1) / 2;
let end = start + k;
start..end
}
}
pub fn row(&self, i: usize) -> impl Iterator<Item = usize> {
self.upward_row(i)
.interleave(self.downward_row(i))
}
pub fn triangles(&self) -> impl Iterator<Item = Triangle<ImplicitDenominator<IVec3, N>>> {
self.triangles.iter()
.map(|t| Triangle::new(
self.vertices[t.u],
self.vertices[t.v],
self.vertices[t.w]
))
}
pub fn vertex_denominator(&self, i: usize) -> IVec3 {
self.vertices[i].inner()
}
pub const fn u(&self) -> usize {
Self::TRIANGLES_UP - 1
}
pub const fn v(&self) -> usize {
N as usize - 1
}
pub const fn w(&self) -> usize {
0
}
pub fn uv(&self) -> Vec<usize> {
let mut edge = vec![0; 2 * N as usize - 1];
for i in 0..N as usize {
edge[2 * i] = Self::TRIANGLES_UP - i * (i + 1) / 2 - 1;
}
for i in 0..(N as usize - 1) {
edge[2 * i + 1] = Self::TRIANGLES - i * (i + 1) / 2 - 1;
}
edge
}
pub fn vw(&self) -> Vec<usize> {
let mut edge = vec![0; 2 * N as usize - 1];
for i in 0..N as usize {
edge[2 * i] = (N as usize - 1) - i;
}
for i in 0..(N as usize - 1) {
edge[2 * i + 1] = Self::TRIANGLES_UP + N as usize - 2 - i;
}
edge
}
pub fn wu(&self) -> Vec<usize> {
let mut edge = vec![0; 2 * N as usize - 1];
for i in 0..N as usize {
let k = N as usize - 1 - i;
edge[2 * i] = Self::TRIANGLES_UP - (k + 1) * (k + 2) / 2;
}
for i in 1..N as usize {
let k = N as usize - 1 - i;
edge[2 * i - 1] = Self::TRIANGLES - (k + 1) * (k + 2) / 2;
}
edge
}
pub fn vertex_adjacency(&self) -> impl Iterator<Item = (usize, usize)> {
(0..N as usize)
.flat_map(|x| {
let l = N as usize + 1 - x;
let start = Self::VERTICES - l * (l + 1) / 2;
let end = start + l;
(start..end)
.tuple_windows::<(_, _)>()
.chain(
(start..(end - 1))
.zip((start + l)..(end + l - 1))
)
.chain(
((start + 1)..end)
.zip((start + l)..(end + l - 1))
)
})
}
pub const fn compute_vertex_interior_index(v: IVec3) -> Option<usize> {
if v.x == 0 || v.y == 0 || v.z == 0 {
None
} else {
Some(Self::compute_vertex_interior_index_unchecked(v))
}
}
pub const fn compute_vertex_interior_index_unchecked(v: IVec3) -> usize {
compute_vertex_index_unchecked(N - 3, IVec3::new(v.x - 1, v.y - 1, v.z - 1))
}
pub const fn compute_vertex_index(v: IVec3) -> Option<usize> {
if v.x < 0 || v.y < 0 || v.z < 0 || v.x + v.y + v.z != N as i32 {
None
} else {
Some(Self::compute_vertex_index_unchecked(v))
}
}
pub const fn compute_vertex_index_unchecked(v: IVec3) -> usize {
compute_vertex_index_unchecked(N, v)
}
pub const fn vertex_index(&self, v: IVec3) -> Option<usize> {
Self::compute_vertex_index(v)
}
pub const fn vertex_index_unchecked(&self, v: IVec3) -> usize {
compute_vertex_index_unchecked(N, v)
}
pub const fn vertex_interior_index(&self, v: IVec3) -> Option<usize> {
Self::compute_vertex_interior_index(v)
}
pub const fn vertex_interior_index_unchecked(&self, v: IVec3) -> usize {
Self::compute_vertex_interior_index_unchecked(v)
}
}