aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlotte Pabst <charlotte.pabst@stud.tu-darmstadt.de>2024-03-11 22:47:36 +0100
committerCharlotte Pabst <charlotte.pabst@stud.tu-darmstadt.de>2024-03-24 17:20:03 +0100
commitc7be7ca0188e8edd19afd880f393d5622451fef5 (patch)
treeca737d8dfd55aec8878e2ef093f933da67877c40
parentd54c146ef57c28e5db8631fc48e59a64c826f86f (diff)
downloaddcel-c7be7ca0188e8edd19afd880f393d5622451fef5.tar.xz
-rw-r--r--src/depth_search_iterator.rs83
-rw-r--r--src/entity.rs3
-rw-r--r--src/main.rs35
-rw-r--r--src/mpkh.rs226
-rw-r--r--src/tests.rs144
5 files changed, 463 insertions, 28 deletions
diff --git a/src/depth_search_iterator.rs b/src/depth_search_iterator.rs
new file mode 100644
index 0000000..cc10df8
--- /dev/null
+++ b/src/depth_search_iterator.rs
@@ -0,0 +1,83 @@
+use crate::*;
+
+pub(crate) struct DepthSearchIterator<'tok, 'brand, 'arena, V> {
+ token: &'tok GhostToken<'brand>,
+ seen_vertices: Option<HashMap<usize, ptr!(Vertex)>>,
+ seen_edges: HashMap<usize, ptr!(Edge)>,
+ seen_faces: HashMap<usize, ptr!(Face)>,
+ edge_stack: Vec<ptr!(Edge)>,
+ face_stack: Vec<ptr!(Face)>,
+}
+
+impl<'tok, 'brand, 'arena, V> DepthSearchIterator<'tok, 'brand, 'arena, V> {
+ pub(crate) fn new(
+ edge: ptr!(Edge),
+ collect_vertices: bool,
+ token: &'tok impl ReflAsRef<GhostToken<'brand>>,
+ ) -> Self {
+ Self {
+ token: token.as_ref(),
+ seen_vertices: collect_vertices.then(|| HashMap::new()),
+ seen_edges: HashMap::from([(edge.id(token), edge)]),
+ seen_faces: HashMap::new(),
+ edge_stack: Vec::from([edge]),
+ face_stack: Vec::new(),
+ }
+ }
+
+ fn add_edge(&mut self, edge: ptr!(Edge)) {
+ if self.seen_edges.insert(edge.id(self.token), edge).is_none() {
+ self.edge_stack.push(edge);
+ }
+ }
+
+ pub(crate) fn collect_seen(
+ edge: ptr!(Edge),
+ token: &'tok impl ReflAsRef<GhostToken<'brand>>,
+ ) -> (
+ HashMap<usize, ptr!(Vertex)>,
+ HashMap<usize, ptr!(Edge)>,
+ HashMap<usize, ptr!(Face)>,
+ )
+ where
+ 'brand: 'tok,
+ {
+ let mut x = Self::new(edge, true, token);
+ for _ in &mut x {}
+ (x.seen_vertices.unwrap(), x.seen_edges, x.seen_faces)
+ }
+}
+
+impl<'tok, 'brand, 'arena, V> Iterator for DepthSearchIterator<'tok, 'brand, 'arena, V> {
+ type Item = ptr!(Edge);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let Some(edge) = self.edge_stack.pop() else {
+ let face = self.face_stack.pop()?;
+
+ for loop_ in std::iter::once(face.lens(self.token).outer_loop())
+ .chain(face.iter_inner_loops(self.token))
+ {
+ self.add_edge(loop_.half_edges().edge().item);
+ }
+
+ return self.next();
+ };
+
+ for h in edge.half_edges(self.token) {
+ let face = h.loop_(self.token).face(self.token);
+ if self.seen_faces.insert(face.id(self.token), face).is_none() {
+ self.face_stack.push(face);
+ }
+
+ let origin = h.origin(self.token);
+ if let Some(seen_vertices) = self.seen_vertices.as_mut() {
+ seen_vertices.insert(origin.id(self.token), origin);
+ }
+
+ self.add_edge(h.next(self.token).edge(self.token));
+ }
+
+ Some(edge)
+ }
+}
diff --git a/src/entity.rs b/src/entity.rs
index 7cce82d..b3e3359 100644
--- a/src/entity.rs
+++ b/src/entity.rs
@@ -174,8 +174,9 @@ macro_rules! entity {
let last = item;
while {
+ let next_item = item.next(token);
f(item, token);
- item = item.next(token);
+ item = next_item;
!item.eq(last, token)
} {}
}
diff --git a/src/main.rs b/src/main.rs
index ba345f8..2fcde6e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,7 @@ use core::ops::Deref;
pub use ghost_cell::{GhostBorrow, GhostCell, GhostToken};
use paste::paste;
use std::{
+ collections::HashMap,
convert::Infallible,
fmt::{self, Debug, Display, Formatter},
hash::{Hash, Hasher},
@@ -36,12 +37,24 @@ mod tests;
mod mevvlfs;
pub use mevvlfs::*;
+// mod mev;
+// pub use mev::*;
+
+// mod mve;
+// pub use mve::*;
+
+// mod melf;
+// pub use melf::*;
+
mod mekh;
pub use mekh::*;
mod msev;
pub use msev::*;
+mod mpkh;
+pub use mpkh::*;
+
pub trait ReflAsRef<T> {
fn as_ref(&self) -> &T;
}
@@ -273,6 +286,12 @@ impl<'tok, 'brand, 'arena, T: PartialEq> PartialEq for lens_t!(T) {
}
impl<'tok, 'brand, 'arena, T: PartialEq> Eq for lens_t!(T) {}
+impl<'tok, 'brand, 'arena, T: Hash> Hash for lens_t!(T) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.item.borrow(self.token).hash(state);
+ }
+}
+
impl<'tok, 'brand, 'arena, T> ReflAsRef<GhostToken<'brand>> for lens_t!(T) {
fn as_ref(&self) -> &GhostToken<'brand> {
&self.token
@@ -992,6 +1011,22 @@ impl<'brand, 'arena, V> Dcel<'brand, 'arena, V> {
) -> Result<Msev<'brand, 'arena, V>, OperatorErr<Ksev<'brand, 'arena, V>, KsevError>> {
Ksev::new(shell, loops, old_vertex, new_vertex, edge).apply(self)
}
+
+ pub fn mpkh(
+ &mut self,
+ loop_: ptr!(Loop),
+ ) -> Result<Kpmh<'brand, 'arena, V>, OperatorErr<Mpkh<'brand, 'arena, V>, MpkhError>> {
+ Mpkh::new(loop_).apply(self)
+ }
+
+ pub fn kpmh(
+ &mut self,
+ new_shell: Option<own!(Shell)>,
+ old_face: ptr!(Face),
+ new_face: own!(Face),
+ ) -> Result<Mpkh<'brand, 'arena, V>, OperatorErr<Kpmh<'brand, 'arena, V>, KpmhError>> {
+ Kpmh::new(new_shell, old_face, new_face).apply(self)
+ }
}
use std::io::Write;
diff --git a/src/mpkh.rs b/src/mpkh.rs
new file mode 100644
index 0000000..e19bd42
--- /dev/null
+++ b/src/mpkh.rs
@@ -0,0 +1,226 @@
+use crate::*;
+
+fn maybe_split<'brand, 'arena, V>(
+ dcel: &mut Dcel<'brand, 'arena, V>,
+ old_shell: ptr!(Shell),
+ inside_edge: ptr!(Edge),
+ outside_edge: ptr!(Edge),
+) -> Option<own!(Shell)> {
+ let mut seen_vertices = HashMap::new();
+ let mut seen_edges = HashMap::new();
+ let mut seen_faces = HashMap::new();
+ let mut edge_stack = Vec::new();
+ let mut face_stack = Vec::<ptr!(Face)>::new();
+
+ let mut add_edge = |edge: ptr!(Edge), edge_stack: &mut Vec<ptr!(Edge)>| {
+ if edge.eq(inside_edge, dcel) {
+ return None;
+ }
+
+ if seen_edges.insert(edge.id(dcel), edge).is_none() {
+ edge_stack.push(edge);
+ }
+
+ Some(())
+ };
+
+ add_edge(outside_edge, &mut edge_stack)?;
+
+ loop {
+ let Some(edge) = edge_stack.pop() else {
+ let Some(face) = face_stack.pop() else {
+ break;
+ };
+
+ for loop_ in
+ std::iter::once(face.lens(dcel).outer_loop()).chain(face.iter_inner_loops(dcel))
+ {
+ add_edge(loop_.half_edges().edge().item, &mut edge_stack)?;
+ }
+
+ continue;
+ };
+
+ for h in edge.half_edges(dcel) {
+ let face = h.loop_(dcel).face(dcel);
+ if seen_faces.insert(face.id(dcel), face).is_none() {
+ face_stack.push(face);
+ }
+
+ let origin = h.origin(dcel);
+ seen_vertices.insert(origin.id(dcel), origin);
+
+ add_edge(h.next(dcel).edge(dcel), &mut edge_stack)?;
+ }
+ }
+
+ let new_shell = old_shell.body(dcel).add_new_shell(dcel);
+
+ for &v in seen_vertices.values() {
+ old_shell.remove_vertex(v, dcel);
+ new_shell.add_vertex(v, dcel);
+ }
+ for &e in seen_edges.values() {
+ old_shell.remove_edge(e, dcel);
+ new_shell.add_edge(e, dcel);
+ }
+ for &f in seen_faces.values() {
+ old_shell.remove_face(f, dcel);
+ new_shell.add_face(f, dcel);
+ }
+
+ Some(new_shell)
+}
+
+pub struct Mpkh<'brand, 'arena, V> {
+ pub loop_: ptr!(Loop),
+}
+
+impl<'brand, 'arena, V> Mpkh<'brand, 'arena, V> {
+ pub fn new(loop_: ptr!(Loop)) -> Self {
+ Self { loop_ }
+ }
+}
+
+#[derive(Debug, Error)]
+pub enum MpkhError {
+ #[error("loop is not an inner loop")]
+ LoopIsOuter,
+}
+
+impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Mpkh<'brand, 'arena, V> {
+ type Inverse = Kpmh<'brand, 'arena, V>;
+ type Error = MpkhError;
+ type Check = ();
+
+ fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result<Self::Check, Self::Error> {
+ use MpkhError::*;
+
+ or_err(!self.loop_.is_outer(dcel), LoopIsOuter)?;
+
+ Ok(())
+ }
+
+ fn apply(
+ self,
+ dcel: &mut Dcel<'brand, 'arena, V>,
+ ) -> Result<Self::Inverse, OperatorErr<Self, Self::Error>> {
+ try_check!(self, dcel);
+
+ let old_face = self.loop_.face(dcel);
+ let old_shell = old_face.shell(dcel);
+
+ let new_face = old_shell.add_new_face(dcel);
+
+ old_face.remove_inner_loop(self.loop_, dcel);
+ new_face.set_outer_loop(self.loop_, dcel);
+ self.loop_.set_face(*new_face, dcel);
+
+ let new_shell = maybe_split(
+ dcel,
+ old_shell,
+ old_face.outer_loop(dcel).half_edges(dcel).edge(dcel),
+ self.loop_.half_edges(dcel).edge(dcel),
+ );
+
+ Ok(Kpmh {
+ new_shell,
+ old_face,
+ new_face,
+ })
+ }
+}
+
+pub struct Kpmh<'brand, 'arena, V> {
+ pub new_shell: Option<own!(Shell)>,
+ pub old_face: ptr!(Face),
+ pub new_face: own!(Face),
+}
+
+#[derive(Error, Debug)]
+pub enum KpmhError {
+ #[error("face does not match shell")]
+ FaceShellMismatch,
+ #[error("shell passed in, but faces are already part of same shell")]
+ CannotMerge,
+ #[error("no shell passed in but faces are part of different shells")]
+ ShouldMerge,
+ #[error("face has inner loops")]
+ HasInnerLoops,
+ #[error("shells are part of different body")]
+ BodyMismatch,
+}
+
+impl<'brand, 'arena, V> Kpmh<'brand, 'arena, V> {
+ pub fn new(new_shell: Option<own!(Shell)>, old_face: ptr!(Face), new_face: own!(Face)) -> Self {
+ Self {
+ new_shell,
+ old_face,
+ new_face,
+ }
+ }
+}
+
+impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Kpmh<'brand, 'arena, V> {
+ type Inverse = Mpkh<'brand, 'arena, V>;
+ type Error = KpmhError;
+ type Check = ();
+
+ fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result<Self::Check, Self::Error> {
+ use KpmhError::*;
+
+ let Kpmh {
+ new_shell,
+ old_face,
+ new_face,
+ } = self;
+
+ let old_shell = old_face.shell(dcel);
+ let needs_merge = !new_face.shell(dcel).eq(old_shell, dcel);
+
+ if let Some(new_shell) = new_shell {
+ or_err(
+ new_face.shell(dcel).eq(**new_shell, dcel),
+ FaceShellMismatch,
+ )?;
+ or_err(needs_merge, CannotMerge)?;
+ } else {
+ or_err(!needs_merge, ShouldMerge)?;
+ }
+
+ or_err(new_face.maybe_inner_loops(dcel).is_none(), HasInnerLoops)?;
+
+ Ok(())
+ }
+
+ fn apply(
+ self,
+ dcel: &mut Dcel<'brand, 'arena, V>,
+ ) -> Result<Self::Inverse, OperatorErr<Self, Self::Error>> {
+ try_check!(self, dcel);
+
+ let Kpmh {
+ new_shell,
+ old_face,
+ new_face,
+ } = self;
+
+ let loop_ = new_face.outer_loop(dcel);
+ old_face.add_inner_loop(loop_, dcel);
+
+ new_face.shell(dcel).remove_face(*new_face, dcel);
+ new_face.free(dcel);
+
+ if let Some(new_shell) = new_shell {
+ let old_shell = old_face.shell(dcel);
+ new_shell.iter_mut_vertices(dcel, |x, dcel| old_shell.add_vertex(x, dcel));
+ new_shell.iter_mut_edges(dcel, |x, dcel| old_shell.add_edge(x, dcel));
+ new_shell.iter_mut_faces(dcel, |x, dcel| old_shell.add_face(x, dcel));
+
+ new_shell.body(dcel).remove_shell(*new_shell, dcel);
+ new_shell.free(dcel);
+ }
+
+ Ok(Mpkh { loop_ })
+ }
+}
diff --git a/src/tests.rs b/src/tests.rs
index a1ad5a4..52ec2cd 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -23,6 +23,60 @@ fn mev_cycle() {
})
}
+/*
+
+makes this shape:
+
+ O O
+ |\ /|
+ | \__/ |
+ | O__O |
+ | / \ |
+ |/ \|
+ O O
+
+*/
+fn make_hourglass<'brand, 'arena, V>(
+ dcel: &mut Dcel<'brand, 'arena, V>,
+ data: [V; 6],
+) -> (own!(Shell), [own!(Loop); 3], own!(Edge), [own!(Vertex); 6]) {
+ let [d0, d1, d2, d3, d4, d5] = data;
+
+ let body = dcel.new_body();
+ let Kevvlfs {
+ shell,
+ loop_: loop_0,
+ vertices: [inner_0, inner_1],
+ ..
+ } = dcel.mevvlfs(*body, [d0, d1]).unwrap();
+
+ let inner_2 = dcel.mev(*shell, *loop_0, *inner_1, d2).new_vertex;
+ let mut outer_loop = dcel.melf(*shell, [*inner_0, *inner_2], *loop_0).new_loop;
+
+ let Mev {
+ new_vertex: outer_0,
+ edge,
+ ..
+ } = dcel.mev(*shell, *outer_loop, *inner_0, d3);
+
+ let outer_1 = dcel.mev(*shell, *outer_loop, *outer_0, d4).new_vertex;
+ let outer_2 = dcel.mev(*shell, *outer_loop, *outer_1, d5).new_vertex;
+
+ let mut loop_2 = dcel
+ .melf(*shell, [*outer_0, *outer_2], *outer_loop)
+ .new_loop;
+ if edge.lens(dcel).half_edges()[0].loop_().eq(*loop_2) {
+ [outer_loop, loop_2] = [loop_2, outer_loop];
+ }
+
+ (
+ shell,
+ [outer_loop, loop_0, loop_2],
+ edge,
+ [inner_0, inner_1, inner_2, outer_0, outer_1, outer_2],
+ )
+}
+
#[test]
fn kemh_mekh() {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -56,33 +110,10 @@ fn kemh_mekh() {
}
Dcel::<Vert>::new(|mut dcel| {
- let body = dcel.new_body();
- let Kevvlfs {
- shell,
- loop_: loop_0,
- vertices: [inner_0, inner_1],
- ..
- } = dcel.mevvlfs(*body, [Inner(0), Inner(1)]).unwrap();
-
- let inner_2 = dcel.mev(*shell, *loop_0, *inner_1, Inner(2)).new_vertex;
- let mut outer_loop = dcel.melf(*shell, [*inner_0, *inner_2], *loop_0).new_loop;
-
- let Mev {
- new_vertex: outer_0,
- edge,
- ..
- } = dcel.mev(*shell, *outer_loop, *inner_0, Outer(0));
-
- let outer_1 = dcel.mev(*shell, *outer_loop, *outer_0, Outer(1)).new_vertex;
- let outer_2 = dcel.mev(*shell, *outer_loop, *outer_1, Outer(2)).new_vertex;
-
- let loop_2 = dcel
- .melf(*shell, [*outer_0, *outer_2], *outer_loop)
- .new_loop;
- if edge.lens(&dcel).half_edges()[0].loop_().eq(*loop_2) {
- outer_loop = loop_2;
- }
-
+ let (shell, [outer_loop, ..], edge, [inner_0, ..]) = make_hourglass(
+ &mut dcel,
+ [Inner(0), Inner(1), Inner(2), Outer(0), Outer(1), Outer(2)],
+ );
let mut kemh = Kemh::new(*shell, edge, *outer_loop, *inner_0);
for _ in 0..3 {
@@ -234,3 +265,62 @@ fn msev_ksev() {
}
})
}
+
+#[test]
+fn mpkh_kpmh() {
+ Dcel::<()>::new(|mut dcel| {
+ let (shell, [outer_0, inner_1, outer_1], edge, [vert, ..]) =
+ make_hourglass(&mut dcel, [(); 6]);
+ let inner_0 = dcel.kemh(*shell, edge, *outer_0, *vert).unwrap().hole_loop;
+
+ let mut mpkh = Mpkh::new(*inner_0);
+
+ for _ in 0..4 {
+ use std::collections::HashSet;
+
+ {
+ mklens!(&dcel, shell, outer_0, outer_1, inner_0, inner_1);
+
+ assert_eq!(
+ shell.iter_faces().collect::<HashSet<_>>(),
+ HashSet::from([outer_0, outer_1, inner_0, inner_1].map(Lens::face))
+ );
+
+ assert_eq!(outer_0.face(), inner_0.face());
+ assert_eq!(outer_0.face().outer_loop(), outer_0);
+ assert_eq!(outer_0.face().inner_loops(), inner_0);
+ assert_eq!(inner_0.next(), inner_0);
+ }
+
+ let kpmh = mpkh.apply(&mut dcel).unwrap();
+
+ {
+ let new_face = &kpmh.new_face;
+ let new_shell = kpmh.new_shell.as_ref().unwrap();
+
+ mklens!(&dcel, shell, new_shell, new_face, outer_0, outer_1, inner_0, inner_1);
+
+ assert_eq!(new_face, inner_0.face());
+ assert_eq!(new_face.outer_loop(), inner_0);
+ assert!(new_face.iter_inner_loops().next().is_none());
+
+ assert_eq!(
+ shell.body().iter_shells().collect::<HashSet<_>>(),
+ HashSet::from([new_shell, shell])
+ );
+
+ assert_eq!(
+ shell.iter_faces().collect::<HashSet<_>>(),
+ HashSet::from([outer_0.face(), outer_1.face()])
+ );
+
+ assert_eq!(
+ new_shell.iter_faces().collect::<HashSet<_>>(),
+ HashSet::from([inner_0.face(), inner_1.face()])
+ );
+ }
+
+ mpkh = kpmh.apply(&mut dcel).unwrap();
+ }
+ })
+}