use bevy::{prelude::{default, Deref, DerefMut}};
use super::{selection::Selection, FaceId, HalfEdgeId, HalfEdgeMesh, MeshPosition, StackVec, VertexId};
const TRAVERSAL_LOOP_LIMIT:usize = 32;
#[derive(Clone, Copy, Deref, DerefMut)]
pub struct Traversal<'m> {
#[deref]
position: HalfEdgeId,
pub(crate) mesh:&'m HalfEdgeMesh,
}
#[derive(Copy, Clone, Debug)]
enum EdgeIteratorKind{
Incoming,
Outgoing,
Loop,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct VertexFlow{
pub incoming:HalfEdgeId,
pub vertex:VertexId,
pub outgoing:HalfEdgeId,
}
impl VertexFlow {
pub fn new(vertex:VertexId) -> Self {
VertexFlow { incoming: default(), vertex, outgoing: default() }
}
}
impl std::fmt::Debug for VertexFlow {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut output = f.debug_struct("");
if self.incoming != default() {
output.field("incoming", &self.incoming);
}
output.field("vertex", &self.vertex);
if self.outgoing != default() {
output.field("outgoing", &self.outgoing);
}
output.finish()
}
}
#[derive(Clone, Copy)]
pub struct EdgeIterator<'m> {
traversal:Option<Traversal<'m>>,
kind:EdgeIteratorKind,
start: HalfEdgeId, count:usize,
}
impl<'m> EdgeIterator<'m> {
pub fn contains(mut self, pos:impl Into<MeshPosition>+Copy) -> bool {
use MeshPosition::*;
self.any( |edge|
match pos.into() {
Vertex(v) => edge.vertex() == v || edge.mesh[v].halfedge == *edge,
HalfEdge(e2) => *edge == e2,
Face(f) => edge.face() == Some(f),
}
)
}
}
impl<'m> Iterator for EdgeIterator<'m> {
type Item = Traversal<'m>;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count > TRAVERSAL_LOOP_LIMIT {
panic!("Traversal::Iter_{:?} Iterated {TRAVERSAL_LOOP_LIMIT} times starting from {:?}. Assuming vertices can't have that many edges, therefore the mesh is broken.", self.kind, self.start);
}
let item = match self.kind {
EdgeIteratorKind::Loop | EdgeIteratorKind::Outgoing => self.traversal,
EdgeIteratorKind::Incoming => self.traversal.map(|t| t.twin()),
};
self.traversal = match self.kind {
EdgeIteratorKind::Loop => self.traversal.and_then(|t| t.try_next()),
EdgeIteratorKind::Outgoing | EdgeIteratorKind::Incoming => self.traversal.and_then(|t| t.try_twin()).and_then(|t| t.try_next()),
}.and_then(|t| if t.position == self.start { None } else { Some(t) });
item
}
}
impl<'m> PartialEq for Traversal<'m> {
fn eq(&self, other: &Self) -> bool {
self.position == other.position
}
}
impl<'m> Eq for Traversal<'m> { }
impl<'m> From<Traversal<'m>> for HalfEdgeId {
fn from(value: Traversal<'m>) -> Self {
value.position
}
}
impl<'m> Traversal<'m> {
pub fn new(mesh:&'m HalfEdgeMesh, position: HalfEdgeId) -> Self {
if !mesh.halfedges.contains_key(position) {
panic!("Created Traversal with invalid position");
};
Self{mesh, position}
}
pub fn select_vertex(self) -> Selection<'m> {
let selection = MeshPosition::Vertex(self.vertex());
Selection::new(self.mesh, selection)
}
pub fn select_edge(self) -> Selection<'m> {
let selection = MeshPosition::HalfEdge(self.position);
Selection::new(self.mesh, selection)
}
pub fn select_face(self) -> Selection<'m> {
let selection = MeshPosition::Face(self.face().unwrap());
Selection::new(self.mesh, selection)
}
pub fn halfedge_to(self, vertex:VertexId) -> Self {
match self.find_halfedge_to(vertex) {
Some(e) => e,
None => panic!("{:?} has no edge to {vertex:?}", self.position)
}
}
pub fn find_halfedge_to(self, vertex:VertexId) -> Option<Self> {
self.iter_outgoing().find(|e| e.twin().vertex() == vertex)
}
pub fn iter_loop(self) -> EdgeIterator<'m> {
EdgeIterator{traversal:Some(self), kind:EdgeIteratorKind::Loop, start:self.position, count:0}
}
pub fn iter_outgoing(self) -> EdgeIterator<'m> {
EdgeIterator{traversal:Some(self), kind:EdgeIteratorKind::Outgoing, start:self.position, count:0}
}
pub fn iter_incoming(self) -> EdgeIterator<'m> {
EdgeIterator{traversal:Some(self), kind:EdgeIteratorKind::Incoming, start:self.position, count:0}
}
pub fn adjacent_faces(self) -> impl Iterator<Item = Traversal<'m>> {
self.iter_outgoing().filter(|p| p.face().is_some())
}
#[inline]
pub fn halfedge(&self) -> HalfEdgeId {
self.position
}
#[inline]
pub fn vertex(&self) -> VertexId {
self.mesh[self.position].vertex
}
#[inline]
pub fn face(&self) -> Option<FaceId> {
self.mesh[self.position].face
}
pub fn get_flow(self, face:Option<FaceId>) -> StackVec<VertexFlow> {
let mut result:StackVec<_> = self.iter_incoming().filter_map(|incoming| if incoming.face() == face {
let outgoing = incoming.try_next().map(|t| if t.face() == face { *t } else {
self.mesh.print_mesh();
panic!("Outgoing edge {t:?} has different face {:?} from incoming edge {incoming:?} face {:?}. Mesh is malformed", t.face(), incoming.face());
}).unwrap_or_else(|| if face.is_none() { *incoming.twin() } else { default()});
let vertex = incoming.twin().vertex();
Some(VertexFlow { incoming: *incoming, vertex, outgoing })
} else {
None
}
).collect();
if result.is_empty() {
result = self.iter_outgoing().filter_map(|outgoing| if outgoing.face() == face {
Some(VertexFlow{incoming:default(), vertex:outgoing.vertex(), outgoing:*outgoing})
} else {
None
}).collect();
}
result
}
pub fn next(self) -> Self {
match self.try_next() {
Some(t) => t,
None => {
#[cfg(test)]
self.mesh.print_mesh();
panic!("{:?}.next is invalid", self.position)
}
}
}
pub fn next_or_twin(mut self) -> Self {
let next = self.mesh[self.position].next;
self.position = if next != default() { next } else { self.mesh[self.position].twin };
self
}
pub fn previous(self) -> Self {
match self.iter_incoming().find(|t| t.next().position == self.position) {
Some(t) => t,
None => {
#[cfg(test)]
self.mesh.print_mesh();
panic!("Can't find previous of {:?}", self.position);
}
}
}
pub fn previous_or_twin(self) -> Self {
self.iter_incoming()
.find(|t| t.try_next().map(|n| n.position == self.position).unwrap_or(false))
.unwrap_or(self.twin())
}
pub fn twin(self) -> Self {
match self.try_twin() {
Some(t) => t,
None => {
#[cfg(test)]
self.mesh.print_mesh();
panic!("{:?}.twin is invalid", self.position)
}
}
}
pub fn try_next(mut self) -> Option<Self> {
let next= self.mesh[self.position].next;
if next != default() {
self.position = next;
Some(self)
} else {
None
}
}
pub fn try_twin(mut self) -> Option<Self> {
let twin= self.mesh[self.position].twin;
if twin != default() {
self.position = twin;
Some(self)
} else {
None
}
}
}
impl<'m> std::fmt::Debug for Traversal<'m> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{:?}", self.position))
}
}
#[cfg(test)]
mod tests {
use bevy::prelude::default;
use slotmap::KeyData;
use crate::mesh::{traversal::{Traversal, VertexFlow}, HalfEdge, HalfEdgeId, HalfEdgeMesh, VertexId};
fn straight_line(count:usize, is_face:bool) -> HalfEdgeMesh {
let mut mesh = HalfEdgeMesh::new();
let mut last_vertex = mesh.vertices.insert(default());
let mut last_edge = default();
let mut last_twin = default();
let face = if is_face { Some(mesh.faces.insert(default())) } else { None };
for _ in 0..count {
let next_vertex = mesh.vertices.insert(default());
let edge = mesh.halfedges.insert(HalfEdge { twin: default(), next: default(), vertex:last_vertex, face});
let twin = mesh.halfedges.insert(HalfEdge { twin: edge, next: last_twin, vertex:next_vertex, face:None});
mesh[edge].twin = twin;
mesh[last_vertex].halfedge = edge;
mesh[next_vertex].halfedge = twin;
if let Some(last_edge) = mesh.halfedges.get_mut(last_edge) {
last_edge.next = edge;
}
last_edge = edge;
last_twin = twin;
last_vertex = next_vertex;
}
mesh
}
#[test]
fn test_tries() {
let mesh = straight_line(1, false);
let t = mesh.goto(mesh.vertex_keys().next().unwrap());
assert_eq!(t.try_next(), None);
assert_eq!(t.try_twin(), Some(Traversal{mesh:&mesh, position:HalfEdgeId(KeyData::from_ffi(2))}));
assert_eq!(t.iter_loop().count(), 1);
assert_eq!(t.iter_incoming().count(), 1);
assert_eq!(t.iter_outgoing().count(), 1);
}
#[test]
fn test_flow_with_face() {
let mesh = straight_line(2, true);
let t = mesh.goto(VertexId(KeyData::from_ffi(2))).get_flow(None);
assert_eq!(t.len(), 1);
assert_eq!(t[0], VertexFlow{
incoming: HalfEdgeId(KeyData::from_ffi(4)),
vertex:VertexId(KeyData::from_ffi(2)),
outgoing:HalfEdgeId(KeyData::from_ffi(2))
});
let t = mesh.goto(VertexId(KeyData::from_ffi(3))).get_flow(None);
assert_eq!(t.len(), 1);
assert_eq!(t[0], VertexFlow{
incoming: default(),
vertex: VertexId(KeyData::from_ffi(3)),
outgoing:HalfEdgeId(KeyData::from_ffi(4))
});
let t = mesh.goto(VertexId(KeyData::from_ffi(1))).get_flow(None);
assert_eq!(t.len(), 1);
assert_eq!(t[0], VertexFlow{
incoming: HalfEdgeId(KeyData::from_ffi(2)),
vertex: VertexId(KeyData::from_ffi(1)),
outgoing:HalfEdgeId(KeyData::from_ffi(1))
});
}
#[test]
fn test_flow_without_face() {
let mesh = straight_line(1, false);
let t = mesh.goto(VertexId(KeyData::from_ffi(1))).get_flow(None);
assert_eq!(t.len(), 1);
assert_eq!(t[0], VertexFlow{
incoming:HalfEdgeId(KeyData::from_ffi(2)),
vertex:VertexId(KeyData::from_ffi(1)),
outgoing:HalfEdgeId(KeyData::from_ffi(1))});
let t = mesh.goto(VertexId(KeyData::from_ffi(2))).get_flow(None);
assert_eq!(t.len(), 1);
assert_eq!(t[0], VertexFlow{
incoming:HalfEdgeId(KeyData::from_ffi(1)),
vertex:VertexId(KeyData::from_ffi(2)),
outgoing:HalfEdgeId(KeyData::from_ffi(2))});
}
}