use super::{TriMesh, QuadMesh};
use crate::mesh::attrib::*;
use crate::mesh::topology::*;
use crate::mesh::vertex_positions::VertexPositions;
use crate::prim::Triangle;
use crate::Real;
use reinterpret::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::slice::{Iter, IterMut};
impl_index_for!(Vec<usize> by FaceEdgeIndex, FaceVertexIndex, VertexCellIndex, VertexFaceIndex);
macro_rules! impl_uniform_surface_mesh {
($mesh_type:ident, $base_type:ident, $verts_per_face:expr) => {
impl<T: Real> $mesh_type<T> {
pub fn new(verts: Vec<[T; 3]>, indices: Vec<usize>) -> $mesh_type<T> {
assert_eq!(indices.len() % $verts_per_face, 0);
let (face_indices, face_offsets) =
Self::compute_dual_topology(verts.len(), &indices);
$mesh_type {
base_mesh: $base_type::new(verts, indices),
face_indices,
face_offsets,
}
}
pub(crate) fn compute_dual_topology(
num_verts: usize,
indices: &[usize],
) -> (Vec<usize>, Vec<usize>) {
let mut face_indices = Vec::new();
face_indices.resize(num_verts, Vec::new());
for (fidx, face) in indices.chunks($verts_per_face).enumerate() {
for &vidx in face {
face_indices[vidx].push(fidx);
}
}
let mut face_offsets = Vec::with_capacity(indices.len() / $verts_per_face);
face_offsets.push(0);
for neighbours in face_indices.iter() {
let last = *face_offsets.last().unwrap();
face_offsets.push(last + neighbours.len());
}
(
face_indices
.iter()
.flat_map(|x| x.iter().cloned())
.collect(),
face_offsets,
)
}
pub fn face_iter(&self) -> Iter<[usize; $verts_per_face]> {
self.base_mesh.face_iter()
}
pub fn face_iter_mut(&mut self) -> IterMut<[usize; $verts_per_face]> {
self.base_mesh.face_iter_mut()
}
#[inline]
pub fn face(&self, fidx: FaceIndex) -> &[usize; $verts_per_face] {
self.base_mesh.face(fidx)
}
#[inline]
pub fn faces(&self) -> &[[usize; $verts_per_face]] {
self.base_mesh.faces()
}
#[inline]
pub fn reverse(&mut self) {
self.base_mesh.reverse()
}
#[inline]
pub fn reversed(mut self) -> Self {
self.reverse();
self
}
pub fn sort_vertices_by_key<K, F>(&mut self, f: F)
where
F: FnMut(usize) -> K,
K: Ord,
{
if self.num_vertices() == 0 {
return;
}
let $mesh_type {
ref mut base_mesh,
ref mut face_indices,
ref mut face_offsets,
..
} = *self;
let order = base_mesh.sort_vertices_by_key_impl(f);
let orig_face_indices = face_indices.clone();
let orig_face_offsets = face_offsets.clone();
let mut prev_off = 0;
for (idx, off) in face_offsets.iter_mut().skip(1).enumerate() {
let orig_idx = order[idx];
let prev_orig_off = orig_face_offsets[orig_idx];
let orig_off = orig_face_offsets[orig_idx + 1];
for (idx, &orig_idx) in face_indices[prev_off..]
.iter_mut()
.zip(orig_face_indices[prev_orig_off..orig_off].iter())
{
*idx = orig_idx;
}
*off = prev_off + orig_off - prev_orig_off;
prev_off = *off;
}
}
}
impl<T: Real> NumVertices for $mesh_type<T> {
fn num_vertices(&self) -> usize {
self.base_mesh.num_vertices()
}
}
impl<T: Real> NumFaces for $mesh_type<T> {
fn num_faces(&self) -> usize {
self.base_mesh.num_faces()
}
}
impl<T: Real> FaceVertex for $mesh_type<T> {
#[inline]
fn face_to_vertex<FI>(&self, fidx: FI, which: usize) -> Option<VertexIndex>
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.face_to_vertex(fidx.into(), which)
}
#[inline]
fn face_vertex<FI>(&self, fidx: FI, which: usize) -> Option<FaceVertexIndex>
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.face_vertex(fidx.into(), which)
}
#[inline]
fn num_face_vertices(&self) -> usize {
self.base_mesh.num_face_vertices()
}
#[inline]
fn num_vertices_at_face<FI>(&self, fidx: FI) -> usize
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.num_vertices_at_face(fidx.into())
}
}
impl<T: Real> FaceEdge for $mesh_type<T> {
#[inline]
fn face_to_edge<FI>(&self, fidx: FI, which: usize) -> Option<EdgeIndex>
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.face_to_edge(fidx.into(), which)
}
#[inline]
fn face_edge<FI>(&self, fidx: FI, which: usize) -> Option<FaceEdgeIndex>
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.face_edge(fidx.into(), which)
}
#[inline]
fn num_face_edges(&self) -> usize {
self.base_mesh.num_face_edges()
}
#[inline]
fn num_edges_at_face<FI>(&self, fidx: FI) -> usize
where
FI: Copy + Into<FaceIndex>,
{
self.base_mesh.num_edges_at_face(fidx.into())
}
}
impl<T: Real> VertexFace for $mesh_type<T> {
#[inline]
fn vertex_to_face<VI>(&self, vidx: VI, which: usize) -> Option<FaceIndex>
where
VI: Copy + Into<VertexIndex>,
{
self.vertex_face(vidx, which)
.map(|vf_idx| self.face_indices[vf_idx].into())
}
#[inline]
fn vertex_face<VI>(&self, vidx: VI, which: usize) -> Option<VertexFaceIndex>
where
VI: Copy + Into<VertexIndex>,
{
if which >= self.num_faces_at_vertex(vidx) {
return None;
}
let vidx = usize::from(vidx.into());
debug_assert!(vidx < self.num_vertices());
Some((self.face_offsets[vidx] + which).into())
}
#[inline]
fn num_vertex_faces(&self) -> usize {
self.face_offsets.len()
}
#[inline]
fn num_faces_at_vertex<VI>(&self, vidx: VI) -> usize
where
VI: Copy + Into<VertexIndex>,
{
let vidx = usize::from(vidx.into());
self.face_offsets[vidx + 1] - self.face_offsets[vidx]
}
}
impl<T: Real> Default for $mesh_type<T> {
fn default() -> Self {
$mesh_type::new(vec![], vec![])
}
}
};
}
#[derive(Clone, Debug, PartialEq, Attrib, Intrinsic)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TriMeshExt<T: Real> {
#[attributes(Vertex, Face, FaceVertex, FaceEdge)]
#[intrinsics(VertexPositions::vertex_positions)]
pub base_mesh: TriMesh<T>,
pub face_indices: Vec<usize>,
pub face_offsets: Vec<usize>,
}
#[derive(Clone, Debug, PartialEq, Attrib, Intrinsic)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct QuadMeshExt<T: Real> {
#[attributes(Vertex, Face, FaceVertex, FaceEdge)]
#[intrinsics(VertexPositions::vertex_positions)]
pub base_mesh: QuadMesh<T>,
pub face_indices: Vec<usize>,
pub face_offsets: Vec<usize>,
}
impl_uniform_surface_mesh!(TriMeshExt, TriMesh, 3);
impl_uniform_surface_mesh!(QuadMeshExt, QuadMesh, 4);
impl<T: Real> TriMeshExt<T> {
#[inline]
pub fn tri_iter<'a>(&'a self) -> impl Iterator<Item = Triangle<T>> + 'a {
self.base_mesh.tri_iter()
}
#[inline]
pub fn tri_from_indices(&self, indices: &[usize; 3]) -> Triangle<T> {
self.base_mesh.tri_from_indices(indices)
}
}
impl<T: Real> From<super::PolyMesh<T>> for TriMeshExt<T> {
fn from(mesh: super::PolyMesh<T>) -> TriMeshExt<T> {
let base_mesh = TriMesh::from(mesh);
let (face_indices, face_offsets) = TriMeshExt::<T>::compute_dual_topology(
base_mesh.vertex_positions.len(),
crate::into_flat_slice3(base_mesh.indices.as_slice()),
);
TriMeshExt {
base_mesh,
face_indices,
face_offsets,
}
}
}
macro_rules! impl_mesh_convert {
($ext_mesh:ident <-> $base_mesh:ident) => {
impl<T: Real> From<$base_mesh<T>> for $ext_mesh<T> {
fn from(base_mesh: $base_mesh<T>) -> $ext_mesh<T> {
let flat_indices = unsafe { reinterpret_slice(base_mesh.indices.as_slice()) };
let (face_indices, face_offsets) = Self::compute_dual_topology(base_mesh.vertex_positions.len(), flat_indices);
$ext_mesh {
base_mesh,
face_indices,
face_offsets,
}
}
}
impl<T: Real> From<$ext_mesh<T>> for $base_mesh<T> {
fn from(ext: $ext_mesh<T>) -> $base_mesh<T> {
ext.base_mesh
}
}
}
}
impl_mesh_convert!(TriMeshExt <-> TriMesh);
impl_mesh_convert!(QuadMeshExt <-> QuadMesh);
#[cfg(test)]
mod tests {
use super::*;
use crate::index::Index;
#[test]
fn mesh_sort() {
let pts = vec![
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[1.0, 1.0, 0.0],
[1.0, 1.0, 1.0],
];
let indices = vec![0, 1, 2, 1, 3, 2, 0, 2, 4];
let mut trimesh = TriMeshExt::new(pts, indices);
let orig_trimesh = trimesh.clone();
let values = [3, 2, 1, 4, 0];
trimesh.sort_vertices_by_key(|k| values[k]);
assert_ne!(trimesh, orig_trimesh);
let rev_values = [4, 2, 1, 0, 3];
trimesh.sort_vertices_by_key(|k| rev_values[k]);
assert_eq!(trimesh, orig_trimesh);
trimesh
.add_attrib_data::<usize, VertexIndex>("i", vec![0, 1, 2, 3, 4])
.unwrap();
trimesh.sort_vertices_by_key(|k| values[k]);
assert_eq!(
trimesh.vertex_positions(),
&[
[1.0, 1.0, 1.0],
[0.0, 1.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
]
);
assert_eq!(
trimesh.attrib_as_slice::<usize, VertexIndex>("i").unwrap(),
&rev_values[..]
);
assert_eq!(
trimesh.base_mesh.indices.as_slice(),
&[[3, 2, 1], [2, 4, 1], [3, 1, 0]]
);
}
#[test]
fn two_triangles_test() {
let pts = vec![
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[1.0, 1.0, 0.0],
];
let indices = vec![0, 1, 2, 1, 3, 2];
let trimesh = TriMeshExt::new(pts, indices);
assert_eq!(trimesh.num_vertices(), 4);
assert_eq!(trimesh.num_faces(), 2);
assert_eq!(trimesh.num_face_vertices(), 6);
assert_eq!(trimesh.num_face_edges(), 6);
assert_eq!(Index::from(trimesh.face_to_vertex(1, 1)), 3);
assert_eq!(Index::from(trimesh.face_to_vertex(0, 2)), 2);
assert_eq!(Index::from(trimesh.face_edge(1, 0)), 3);
let mut face_iter = trimesh.face_iter();
assert_eq!(face_iter.next(), Some(&[0usize, 1, 2]));
assert_eq!(face_iter.next(), Some(&[1usize, 3, 2]));
let vertex_faces = vec![vec![0], vec![0, 1], vec![0, 1], vec![1]];
for i in 0..vertex_faces.len() {
assert_eq!(trimesh.num_faces_at_vertex(i), vertex_faces[i].len());
let mut local_faces: Vec<usize> = (0..trimesh.num_faces_at_vertex(i))
.map(|j| trimesh.vertex_to_face(i, j).unwrap().into())
.collect();
local_faces.sort();
assert_eq!(local_faces, vertex_faces[i]);
}
}
#[test]
fn from_polymesh_test() {
let points = vec![
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
];
let faces = vec![
3, 0, 1, 2,
4, 0, 1, 5, 4,
3, 1, 3, 2,
];
let polymesh = crate::mesh::PolyMesh::new(points.clone(), &faces);
let trimesh = TriMeshExt::new(points.clone(), vec![0, 1, 2, 0, 1, 5, 0, 5, 4, 1, 3, 2]);
assert_eq!(trimesh, TriMeshExt::from(polymesh));
}
}