use crate::geom::triangle::IntTriangle;
use alloc::vec::Vec;
use i_overlay::i_float::int::point::IntPoint;
use i_overlay::i_float::triangle::Triangle;
use i_overlay::i_shape::util::reserve::Reserve;
pub trait IndexType: Copy + Clone + TryFrom<usize> + Default {
const MAX: usize;
const ZERO: Self;
fn add(self, other: Self) -> Self;
fn into_usize(self) -> usize;
}
impl IndexType for u8 {
const MAX: usize = u8::MAX as usize;
const ZERO: Self = 0;
#[inline]
fn add(self, other: Self) -> Self {
self + other
}
#[inline]
fn into_usize(self) -> usize {
self as usize
}
}
impl IndexType for u16 {
const MAX: usize = u16::MAX as usize;
const ZERO: Self = 0;
#[inline]
fn add(self, other: Self) -> Self {
self + other
}
#[inline]
fn into_usize(self) -> usize {
self as usize
}
}
impl IndexType for u32 {
const MAX: usize = u32::MAX as usize;
const ZERO: Self = 0;
#[inline]
fn add(self, other: Self) -> Self {
self + other
}
#[inline]
fn into_usize(self) -> usize {
self as usize
}
}
impl IndexType for u64 {
const MAX: usize = u64::MAX as usize;
const ZERO: Self = 0;
#[inline]
fn add(self, other: Self) -> Self {
self + other
}
#[inline]
fn into_usize(self) -> usize {
self as usize
}
}
impl IndexType for usize {
const MAX: usize = usize::MAX;
const ZERO: Self = 0;
#[inline]
fn add(self, other: Self) -> Self {
self + other
}
#[inline]
fn into_usize(self) -> usize {
self
}
}
#[derive(Debug, Clone, Default)]
pub struct IntTriangulation<I = u16> {
pub points: Vec<IntPoint>,
pub indices: Vec<I>,
}
#[derive(Debug, Default)]
pub struct RawIntTriangulation {
pub(crate) triangles: Vec<IntTriangle>,
pub(crate) points: Vec<IntPoint>,
}
impl RawIntTriangulation {
#[inline]
pub(super) fn new(triangles: Vec<IntTriangle>, points: Vec<IntPoint>) -> Self {
Self { triangles, points }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.triangles.is_empty()
}
#[inline]
pub fn points(&self) -> &Vec<IntPoint> {
&self.points
}
#[inline]
pub fn triangle_indices<I: IndexType>(&self) -> Vec<I> {
let mut indices = Vec::new();
self.triangles.feed_indices(self.points.len(), &mut indices);
indices
}
#[inline]
pub fn into_triangulation<I: IndexType>(self) -> IntTriangulation<I> {
IntTriangulation {
indices: self.triangle_indices(),
points: self.points,
}
}
#[inline]
pub fn to_triangulation<I: IndexType>(&self) -> IntTriangulation<I> {
IntTriangulation {
indices: self.triangle_indices(),
points: self.points.as_slice().to_vec(),
}
}
#[inline]
pub(crate) fn shift(&mut self, points_offset: usize, triangle_offset: usize) {
for t in self.triangles.iter_mut() {
t.vertices[0].index += points_offset;
t.vertices[1].index += points_offset;
t.vertices[2].index += points_offset;
t.neighbors[0] = t.neighbors[0].saturating_add(triangle_offset);
t.neighbors[1] = t.neighbors[1].saturating_add(triangle_offset);
t.neighbors[2] = t.neighbors[2].saturating_add(triangle_offset);
}
}
}
impl<I: IndexType> IntTriangulation<I> {
#[inline]
pub fn empty() -> Self {
Self {
points: Vec::new(),
indices: Vec::new(),
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
points: Vec::with_capacity(capacity),
indices: Vec::with_capacity(3 * capacity),
}
}
#[inline]
pub fn join(&mut self, other: &Self) {
let points_offset = I::try_from(self.points.len()).unwrap_or(I::ZERO);
for &i in other.indices.iter() {
self.indices.push(i.add(points_offset));
}
self.points.extend_from_slice(&other.points)
}
#[inline]
pub fn reserve_and_clear(&mut self, new_len: usize) {
self.points.reserve_capacity(new_len);
self.points.clear();
self.indices.reserve_capacity(3 * new_len);
self.indices.clear();
}
#[inline]
pub fn fill_with_raw(&mut self, triangulation: &RawIntTriangulation) {
self.points.clear();
self.points.extend_from_slice(&triangulation.points);
triangulation
.triangles
.feed_indices(triangulation.points.len(), &mut self.indices);
}
}
pub(crate) trait IndicesBuilder {
fn feed_indices<I: IndexType>(&self, max_count: usize, indices: &mut Vec<I>);
}
impl IndicesBuilder for [IntTriangle] {
#[inline]
fn feed_indices<I: IndexType>(&self, max_count: usize, indices: &mut Vec<I>) {
if max_count > I::MAX {
panic!(
"Index type `{}` cannot hold {} points",
core::any::type_name::<I>(),
max_count
);
}
let count = 3 * self.len();
indices.reserve_capacity(count);
indices.clear();
for t in self.iter() {
let i0 = unsafe { I::try_from(t.vertices[0].index).unwrap_unchecked() };
let i1 = unsafe { I::try_from(t.vertices[1].index).unwrap_unchecked() };
let i2 = unsafe { I::try_from(t.vertices[2].index).unwrap_unchecked() };
indices.push(i0);
indices.push(i1);
indices.push(i2);
}
}
}
impl RawIntTriangulation {
pub fn validate(&self) {
for (i, t) in self.triangles.iter().enumerate() {
let a = t.vertices[0].point;
let b = t.vertices[1].point;
let c = t.vertices[2].point;
let area = Triangle::area_two_point(a, b, c);
assert!(area <= 0);
let n0 = t.neighbors[0];
let n1 = t.neighbors[1];
let n2 = t.neighbors[2];
if n0 != usize::MAX {
assert!(self.triangles[n0].neighbors.contains(&i));
}
if n1 != usize::MAX {
assert!(self.triangles[n1].neighbors.contains(&i));
}
if n2 != usize::MAX {
assert!(self.triangles[n2].neighbors.contains(&i));
}
}
}
pub fn area_two(&self) -> i64 {
let mut s = 0;
for t in self.triangles.iter() {
let a = t.vertices[0].point;
let b = t.vertices[1].point;
let c = t.vertices[2].point;
s += Triangle::area_two_point(a, b, c);
}
s
}
}
#[cfg(test)]
impl<I: IndexType> IntTriangulation<I> {
pub fn validate(&self, shape_x2_area: i64) {
let mut s = 0;
let mut i = 0;
while i < self.indices.len() {
let ai = self.indices[i];
i += 1;
let bi = self.indices[i];
i += 1;
let ci = self.indices[i];
i += 1;
let a = self.points[ai.into_usize()];
let b = self.points[bi.into_usize()];
let c = self.points[ci.into_usize()];
let abc = Triangle::area_two_point(a, b, c);
assert!(abc < 0);
s = s + abc;
}
assert!(s == shape_x2_area);
}
}