use crate::{
VertexRef,
prelude::*,
map::{DenseMap, set::DenseSet},
util::{PrimitiveFloat, Pos3Like},
};
pub mod bounding;
pub mod subdivision;
#[inline(never)]
pub fn smooth_simple<MeshT, MapT>(
mesh: &MeshT,
vertex_positions: &MapT,
) -> DenseMap<VertexHandle, MapT::Target>
where
MeshT: FullAdj,
MapT: PropMap<VertexHandle>,
MapT::Target: Pos3Like,
{
let pos_of = |v: VertexRef<'_, MeshT>| {
*vertex_positions.get(v.handle()).expect("missing vertex position")
};
mesh.vertices().map(|v| {
let new_pos = if v.is_boundary() {
pos_of(v)
} else {
v.adjacent_vertices()
.map(|n| pos_of(n))
.centroid()
.unwrap() .convert()
};
(v.handle(), new_pos)
}).collect()
}
pub fn is_closed<MeshT>(mesh: &MeshT) -> bool
where
MeshT: FullAdj,
{
mesh.faces().all(|f| f.adjacent_faces().count() == f.adjacent_vertices().count())
}
#[derive(Debug, Clone, Copy)]
pub struct DijsktraVertexData<F> {
pub distance: F,
pub prev: VertexHandle,
}
pub fn dijkstra<MeshT, MapT, ScalarT>(
mesh: &MeshT,
vertex_positions: &MapT,
start_vertex: VertexHandle,
) -> DenseMap<VertexHandle, DijsktraVertexData<ScalarT>>
where
MeshT: FullAdj,
MapT: PropMap<VertexHandle>,
MapT::Target: Pos3Like<Scalar = ScalarT>,
ScalarT: PrimitiveFloat,
{
use std::{
cmp::Ordering,
collections::BinaryHeap,
};
struct HeapElem<ScalarT> {
distance: ScalarT,
handle: VertexHandle,
}
impl<ScalarT: PrimitiveFloat> Ord for HeapElem<ScalarT> {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).expect("NaN distance in Dijkstra")
}
}
impl<ScalarT: PrimitiveFloat> PartialOrd for HeapElem<ScalarT> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.distance.partial_cmp(&other.distance)
.map(|ord| ord.reverse())
}
}
impl<ScalarT: PrimitiveFloat> Eq for HeapElem<ScalarT> {}
impl<ScalarT: PrimitiveFloat> PartialEq for HeapElem<ScalarT> {
fn eq(&self, other: &Self) -> bool {
self.distance == other.distance
}
}
let mut vertex_data = DenseMap::with_capacity(mesh.num_vertices());
let mut visited = DenseSet::with_capacity(mesh.num_vertices());
let mut heap = BinaryHeap::with_capacity((mesh.num_vertices() as f64 * 1.5) as usize);
for vh in mesh.vertex_handles() {
let distance = if vh == start_vertex {
ScalarT::zero()
} else {
ScalarT::infinity()
};
vertex_data.insert(vh, DijsktraVertexData { distance, prev: vh });
heap.push(HeapElem { distance, handle: vh });
}
while let Some(current) = heap.pop() {
if visited.contains_handle(current.handle) {
continue;
}
visited.insert(current.handle);
for nh in mesh.vertices_around_vertex(current.handle) {
if visited.contains_handle(nh) {
continue;
}
let pos_of = |vh: VertexHandle| {
vertex_positions.get(vh)
.unwrap_or_else(|| panic!("vertex position for {:?} missing in Dijkstra", vh))
.to_point3()
};
let distance_to_neighbor = pos_of(current.handle).distance_from(pos_of(nh));
let new_distance = current.distance + distance_to_neighbor;
if new_distance < vertex_data[nh].distance {
vertex_data[nh].distance = new_distance;
vertex_data[nh].prev = current.handle;
heap.push(HeapElem {
distance: new_distance,
handle: nh,
});
}
}
if visited.num_elements() == mesh.num_vertices() {
break;
}
}
vertex_data
}