#[cfg(test)]
mod tests;
mod trait_impl;
use crate::{HronnError, prelude::ConvertTo};
use spade::{
DelaunayTriangulation, HasPosition, Point2, Triangulation, handles::FixedVertexHandle,
};
use vector_traits::{
num_traits::AsPrimitive,
prelude::{Aabb2, GenericScalar, GenericVector2, GenericVector3, HasXY, HasXYZ},
};
pub struct DelaunayPos<T: HasXYZ>(T);
impl<T: HasXYZ> HasPosition for DelaunayPos<T> {
type Scalar = T::Scalar;
fn position(&self) -> Point2<Self::Scalar> {
Point2::new(self.0.x(), self.0.y())
}
}
pub(super) struct DelaunayContainer<T: HasXYZ> {
pub(super) delaunay: DelaunayTriangulation<DelaunayPos<T>>,
pub(super) vertices: Vec<T>,
pub(super) indices: Vec<u32>,
}
impl<T: HasXYZ> DelaunayContainer<T> {
pub(super) fn insert_vertex(&mut self, vertex: T) -> Result<FixedVertexHandle, HronnError> {
let inserted_vertex = self.delaunay.insert(DelaunayPos(vertex))?;
if inserted_vertex.index() > 2 && inserted_vertex.index() - 3 == self.vertices.len() {
self.vertices.push(vertex);
}
Ok(inserted_vertex)
}
pub(super) fn insert_vertex_with_hint(
&mut self,
vertex: T,
hint: FixedVertexHandle,
) -> Result<FixedVertexHandle, HronnError> {
let inserted_vertex = self.delaunay.insert_with_hint(DelaunayPos(vertex), hint)?;
if inserted_vertex.index() > 2 && inserted_vertex.index() - 3 == self.vertices.len() {
self.vertices.push(vertex);
}
Ok(inserted_vertex)
}
}
pub fn triangulate_vertices<T, MESH: HasXYZ>(
aabb2: <<T as GenericVector3>::Vector2 as GenericVector2>::Aabb,
convex_hull: &[T::Vector2],
vertices: &[MESH],
) -> Result<(Vec<MESH>, Vec<u32>), HronnError>
where
T: GenericVector3,
T: ConvertTo<MESH>,
T::Scalar: AsPrimitive<MESH::Scalar>,
{
if !aabb2.is_empty() {
let (min, max, delta) = aabb2.extents();
let min = min.to_3d(T::Scalar::ZERO).to();
let max = max.to_3d(T::Scalar::ZERO).to();
let width: MESH::Scalar = delta.x().as_();
let width = width * 10.0.into();
let height: MESH::Scalar = delta.y().as_();
let height = height * 10.0.into();
let big_triangle_a = MESH::new_3d(min.x() - width, min.y() - height, MESH::Scalar::ZERO);
let big_triangle_b = MESH::new_3d(max.x() + width, min.y() - height, MESH::Scalar::ZERO);
let big_triangle_c = MESH::new_3d(
min.x() + width / MESH::Scalar::TWO,
max.y() - height,
MESH::Scalar::ZERO,
);
let mut tris = DelaunayContainer {
delaunay: DelaunayTriangulation::<DelaunayPos<MESH>>::new(),
vertices: Vec::<MESH>::with_capacity(4 + convex_hull.len() + vertices.len()),
indices: Vec::<u32>::with_capacity((4 + convex_hull.len() + vertices.len()) * 3),
};
let mut last_vertex = tris.insert_vertex(big_triangle_a)?;
last_vertex = tris.insert_vertex_with_hint(big_triangle_b, last_vertex)?;
let _ = tris.insert_vertex_with_hint(big_triangle_c, last_vertex)?;
last_vertex =
tris.insert_vertex(convex_hull.first().unwrap().to_3d(T::Scalar::ZERO).to())?;
for v in convex_hull.iter().skip(1) {
last_vertex =
tris.insert_vertex_with_hint(v.to_3d(T::Scalar::ZERO).to(), last_vertex)?;
}
let mut last_vertex = tris.insert_vertex(*vertices.first().unwrap())?;
for v in vertices.iter().skip(1) {
last_vertex = tris.insert_vertex_with_hint(*v, last_vertex)?;
}
for face in tris.delaunay.inner_faces() {
let vertices = face.vertices();
let id0 = vertices[0].fix().index() as u32;
let id1 = vertices[1].fix().index() as u32;
let id2 = vertices[2].fix().index() as u32;
if id0 > 2 && id1 > 2 && id2 > 2 {
let id0 = id0 - 3;
let id1 = id1 - 3;
let id2 = id2 - 3;
tris.indices.push(id0);
tris.indices.push(id1);
tris.indices.push(id2);
} else {
}
}
Ok((tris.vertices, tris.indices))
} else {
Ok((vec![], vec![]))
}
}