From 219261b7042fba1a54ecd478b56e902d9ca8787b Mon Sep 17 00:00:00 2001 From: Charlotte Pabst Date: Thu, 7 Mar 2024 21:52:30 +0100 Subject: --- src/dot.rs | 121 +++++++ src/entity.rs | 288 ++++++++++++++++ src/entity_iterator.rs | 59 ++++ src/main.rs | 892 ++++++++++++------------------------------------- src/mekh.rs | 212 ++++++++++++ src/mevvlfs.rs | 184 ++++++++++ src/tests.rs | 147 ++++++++ 7 files changed, 1230 insertions(+), 673 deletions(-) create mode 100644 src/dot.rs create mode 100644 src/entity.rs create mode 100644 src/entity_iterator.rs create mode 100644 src/mekh.rs create mode 100644 src/mevvlfs.rs create mode 100644 src/tests.rs diff --git a/src/dot.rs b/src/dot.rs new file mode 100644 index 0000000..97f4ab1 --- /dev/null +++ b/src/dot.rs @@ -0,0 +1,121 @@ +use crate::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DcelDotOptions { + pub twin: bool, + pub next: bool, + pub prev: bool, +} + +impl DcelDotOptions { + pub fn none() -> Self { + Self { + twin: false, + next: false, + prev: false, + } + } + + pub fn all() -> Self { + Self { + twin: true, + next: true, + prev: true, + } + } +} + +pub fn dcel_write_dot( + dcel: &Dcel, + pos: impl Fn(&V) -> [f64; 2], + name: impl Fn(&V, &mut Formatter) -> fmt::Result, + f: &mut Formatter, + opt: DcelDotOptions, +) -> fmt::Result { + writeln!(f, "digraph DCEL {{")?; + writeln!(f, "node [shape = circle]")?; + //writeln!(f, "nodesep = 1")?; + + for shell in dcel.iter_bodies().flat_map(Lens::iter_shells) { + for vertex in shell.iter_vertices() { + let p = pos(vertex.data()); + + writeln!( + f, + "vertex_{} [label=\"{}\", pos=\"{},{}!\"]", + vertex.id(), + DisplayFn(|f| name(vertex.data(), f)), + p[0], + p[1] + )?; + } + + for hedges in shell + .iter_edges() + .map(|x| x.half_edges()) + .flat_map(|[he1, he2]| [[he1, he2], [he2, he1]]) + { + let ids = hedges.map(Lens::id); + let vertices = hedges.map(|h| h.origin()); + let points = vertices.map(|v| pos(v.data())); + + let mut diff = [points[1][1] - points[0][1], points[1][0] - points[0][0]]; + + // let len = (diff[0] * diff[0] + diff[1] * diff[1]).sqrt(); + diff[0] *= -0.075; + diff[1] *= 0.075; + + let mid = [ + (points[1][0] + points[0][0]) / 2.0 + diff[0], + (points[1][1] + points[0][1]) / 2.0 + diff[1], + ]; + + writeln!( + f, + "half_edge_{} [pos=\"{},{}!\", shape=point, width=0.01, height=0.01]", + ids[0], mid[0], mid[1] + )?; + writeln!( + f, + "vertex_{} -> half_edge_{} [arrowhead=none]", + vertices[0].id(), + ids[0] + )?; + writeln!( + f, + "half_edge_{} -> vertex_{} [label=\"{}\"]", + ids[0], + vertices[1].id(), + ids[0] + )?; + + if opt.twin { + writeln!( + f, + "half_edge_{} -> half_edge_{} [color=\"red\"]", + ids[0], ids[1] + )?; + } + + if opt.next { + writeln!( + f, + "half_edge_{} -> half_edge_{} [color=\"green\"]", + ids[0], + hedges[0].next().id(), + )?; + } + + if opt.prev { + writeln!( + f, + "half_edge_{} -> half_edge_{} [color=\"blue\"]", + ids[0], + hedges[0].prev().id(), + )?; + } + } + } + + writeln!(f, "}}") +} diff --git a/src/entity.rs b/src/entity.rs new file mode 100644 index 0000000..7cce82d --- /dev/null +++ b/src/entity.rs @@ -0,0 +1,288 @@ +use crate::*; + +// trait for a kind of topological element (i.e. Vertex, HalfEdge, Face) +pub(crate) trait Entity<'brand, 'arena>: Eq + Sized { + fn clear(&mut self); + + fn type_name() -> &'static str; + + fn maybe_id(&self) -> Option; + fn id(&self) -> usize { + self.maybe_id().unwrap() + } + fn alive(&self) -> bool { + self.maybe_id().is_some() + } + + fn maybe_next(&self) -> Option; + fn next(&self) -> ptr_t!(Self) { + self.maybe_next().unwrap() + } + fn set_next(&mut self, x: ptr_t!(Self)) { + self.set_next_opt(Some(x)); + } + fn set_next_opt(&mut self, x: Option); + + fn maybe_prev(&self) -> Option; + fn prev(&self) -> ptr_t!(Self) { + self.maybe_prev().unwrap() + } + fn set_prev(&mut self, x: ptr_t!(Self)) { + self.set_prev_opt(Some(x)); + } + fn set_prev_opt(&mut self, x: Option); + + fn list_add( + this: ptr_t!(Self), + list: Option, + token: &mut impl ReflAsMut>, + ) -> ptr_t!(Self) { + let (next, prev) = if let Some(first) = list { + (first, first.prev(token)) + } else { + (this, this) + }; + + this.set_next(next, token); + this.set_prev(prev, token); + prev.set_next(this, token); + next.set_prev(this, token); + + next + } + + fn list_remove( + this: ptr_t!(Self), + token: &mut impl ReflAsMut>, + ) -> Option { + let next = this.next(token); + let prev = this.prev(token); + + if this.eq(next, token) { + return None; + } + + prev.set_next(next, token); + next.set_prev(prev, token); + + Some(next) + } +} + +macro_rules! entity { + ($name:ident : $T:ident $(($init_name:ident : $init_ty:ty))? + $(, $($custom_field:ident : $custom_ty:ty = $custom_expr:expr),* )? + $(; + $( $field_vis:vis $field:ident + $([ $list_singular:ident : $list_name:ident $(($list_init:ty))? $($list_back:ident)? ])? + : $field_ty:ident ),* + )? + ) => { paste! { + pub struct $T<'brand, 'arena, V> { + id: Option, + next: Option, + prev: Option, + $($($custom_field: $custom_ty,)*)? + $($($field: Option,)*)? + } + + impl<'brand, 'arena, V> $T<'brand, 'arena, V> { + fn new($($init_name: $init_ty,)? dcel: &mut Dcel<'brand, 'arena, V>) -> own_t!(Self) { + let id = Some(dcel.$name.next_id()); + dcel.$name.alloc(Self { + id, + prev: None, + next: None, + $($($custom_field: $custom_expr,)*)? + $($($field: None,)*)? + }, &mut dcel.token) + } + } + + impl<'brand, 'arena, V> Entity<'brand, 'arena> for $T<'brand, 'arena, V> { + fn clear(&mut self) { + self.id = None; + #[cfg(debug_assertions)] + { + self.prev = None; + self.next = None; + $($(self.$field = None;)*)? + } + } + + fn type_name() -> &'static str { + stringify!($T) + } + + fn maybe_id(&self) -> Option { + self.id + } + + fn maybe_next(&self) -> Option { + self.next + } + + fn set_next_opt(&mut self, x: Option) { + self.next = x; + } + + fn maybe_prev(&self) -> Option { + self.prev + } + + fn set_prev_opt(&mut self, x: Option) { + self.prev = x; + } + } + + #[allow(unused)] + impl<'brand, 'arena, V> ptr!($T) { + $($( + $field_vis fn $field(self, token: &impl ReflAsRef>) -> ptr!($field_ty) { + self.[](token).unwrap() + } + + fn [](self, token: &impl ReflAsRef>) -> Option { + self.borrow(token).$field + } + + fn [](self, x: ptr!($field_ty), token: &mut impl ReflAsMut>) { + self.[](Some(x), token); + } + + fn [](self, x: Option, token: &mut impl ReflAsMut>,) { + self.borrow_mut(token).$field = x; + } + + $( + pub fn []<'tok>( + self, + token: &'tok impl ReflAsRef>, + ) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> + { + EntityIterator::new(self.[](token), token) + } + + pub fn []>>( + self, + token: &mut T, + mut f: impl FnMut(ptr!($field_ty), &mut T), + ) { + let Some(mut item) = self.[](token) else { + return; + }; + + let last = item; + while { + f(item, token); + item = item.next(token); + !item.eq(last, token) + } {} + } + + fn []( + self, + x: ptr!($field_ty), + token: &mut impl ReflAsMut>, + ) { + let list = Entity::list_add(x, self.[](token), token); + self.[](list, token); + + $( + let [<_ $list_back>] = (); + x.[](self, token); + )? + } + + fn []( + self, + $(init: $list_init,)? + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> own!($field_ty) { + let x = $field_ty::new($(init as $list_init,)? dcel); + self.[](*x, dcel); + x + } + + fn []( + self, + x: ptr!($field_ty), + token: &mut impl ReflAsMut>, + ) { + let list = Entity::list_remove(x, token); + self.[](list, token); + } + )? + )*)? + } + + #[allow(unused)] + impl<'tok, 'brand, 'arena, V> lens!($T) { + $($( + $field_vis fn $field(self) -> lens!($field_ty) { + self.item.$field(&self).lens(self.token) + } + + fn [](self) -> Option { + self.item.[](&self).map(|x| x.lens(self.token)) + } + + $( + pub fn [](self) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> { + let [<_ $list_singular>] = (); + self.item.[](self.token) + } + )? + + fn [](self, f: &mut Formatter) -> fmt::Result + where V: Debug + { + $({ + let [<_ $list_singular>] = (); + if true { + // return short_debug_list(self.[](), f); + return f.debug_list().entries(self.[]()).finish(); + } + })? + short_debug(self.$field(), f) + } + )*)? + } + + impl<'tok, 'brand, 'arena, V: Debug> Debug for lens!($T) { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct(stringify!($T)) + .field("id", &self.id()) + .field("prev", &short_debug_fn(self.prev())) + .field("next", &short_debug_fn(self.next())) + $($( + .field(stringify!($field), &DisplayFn(|f| self.[](f))) + )*)? + $($( + .field(stringify!($custom_field), &DisplayFn(|f| self.[](f))) + )*)? + .finish() + } + } + + #[allow(unused)] + impl<'brand, 'arena, V> Own<'brand, 'arena, $T<'brand, 'arena, V>> { + fn free(self, dcel: &mut Dcel<'brand, 'arena, V>) { + dcel.$name.free(&mut dcel.token, self) + } + } + + impl<'brand, 'arena, V> Hash for $T<'brand, 'arena, V> { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } + } + + impl<'brand, 'arena, V> PartialEq for $T<'brand, 'arena, V> { + fn eq(&self, other: &Self) -> bool { + self.id() == other.id() + } + } + impl<'brand, 'arena, V> Eq for $T<'brand, 'arena, V> {} + }}; +} diff --git a/src/entity_iterator.rs b/src/entity_iterator.rs new file mode 100644 index 0000000..58cd2a9 --- /dev/null +++ b/src/entity_iterator.rs @@ -0,0 +1,59 @@ +use crate::*; + +pub struct EntityIterator<'tok, 'brand, 'arena, T>(Option<(lens_t!(T), lens_t!(T))>); + +impl<'tok, 'brand, 'arena, T> Clone for EntityIterator<'tok, 'brand, 'arena, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} + +impl<'tok, 'brand, 'arena, T> Copy for EntityIterator<'tok, 'brand, 'arena, T> {} + +impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> EntityIterator<'tok, 'brand, 'arena, T> { + pub(crate) fn new( + start: Option, + token: &'tok impl ReflAsRef>, + ) -> Self { + Self(start.map(|s| { + let l = Lens::new(s, token); + (l, l.prev()) + })) + } +} + +impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> Iterator + for EntityIterator<'tok, 'brand, 'arena, T> +{ + type Item = lens_t!(T); + + fn next(&mut self) -> Option { + let range = self.0.as_mut()?; + let ret = range.0; + + if range.0 == range.1 { + self.0 = None; + } else { + range.0 = range.0.next(); + } + + Some(ret) + } +} + +impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> DoubleEndedIterator + for EntityIterator<'tok, 'brand, 'arena, T> +{ + fn next_back(&mut self) -> Option { + let range = self.0.as_mut()?; + let ret = range.1; + + if range.0 == range.1 { + self.0 = None; + } else { + range.1 = range.1.prev(); + } + + Some(ret) + } +} diff --git a/src/main.rs b/src/main.rs index eabbe34..a1f968b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,41 @@ use core::ops::Deref; pub use ghost_cell::{GhostBorrow, GhostCell, GhostToken}; use paste::paste; use std::{ + convert::Infallible, fmt::{self, Debug, Display, Formatter}, hash::{Hash, Hasher}, }; use thiserror::Error; pub use typed_arena::Arena; +macro_rules! try_check { + ($this:ident, $dcel:ident) => { + match $this.check($dcel) { + Ok(x) => x, + Err(e) => return Err(OperatorErr::new($this, e)), + } + }; +} + +#[macro_use] +mod entity; +use entity::*; + +mod entity_iterator; +pub use entity_iterator::*; + +mod dot; +pub use dot::*; + +#[cfg(test)] +mod tests; + +mod mevvlfs; +pub use mevvlfs::*; + +mod mekh; +pub use mekh::*; + pub trait ReflAsRef { fn as_ref(&self) -> &T; } @@ -293,341 +322,8 @@ impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> lens_t!(T) { } } -pub struct EntityIterator<'tok, 'brand, 'arena, T>(Option<(lens_t!(T), lens_t!(T))>); - -impl<'tok, 'brand, 'arena, T> Clone for EntityIterator<'tok, 'brand, 'arena, T> { - fn clone(&self) -> Self { - Self(self.0) - } -} - -impl<'tok, 'brand, 'arena, T> Copy for EntityIterator<'tok, 'brand, 'arena, T> {} - -impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> EntityIterator<'tok, 'brand, 'arena, T> { - fn new(start: Option, token: &'tok impl ReflAsRef>) -> Self { - Self(start.map(|s| { - let l = Lens::new(s, token); - (l, l.prev()) - })) - } -} - -impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> Iterator - for EntityIterator<'tok, 'brand, 'arena, T> -{ - type Item = lens_t!(T); - - fn next(&mut self) -> Option { - let range = self.0.as_mut()?; - let ret = range.0; - - if range.0 == range.1 { - self.0 = None; - } else { - range.0 = range.0.next(); - } - - Some(ret) - } -} - -impl<'tok, 'brand, 'arena, T: Entity<'brand, 'arena>> DoubleEndedIterator - for EntityIterator<'tok, 'brand, 'arena, T> -{ - fn next_back(&mut self) -> Option { - let range = self.0.as_mut()?; - let ret = range.1; - - if range.0 == range.1 { - self.0 = None; - } else { - range.1 = range.1.prev(); - } - - Some(ret) - } -} - -// trait for a kind of topological element (i.e. Vertex, HalfEdge, Face) -trait Entity<'brand, 'arena>: Eq + Sized { - fn clear(&mut self); - - fn type_name() -> &'static str; - - fn maybe_id(&self) -> Option; - fn id(&self) -> usize { - self.maybe_id().unwrap() - } - fn alive(&self) -> bool { - self.maybe_id().is_some() - } - - fn maybe_next(&self) -> Option; - fn next(&self) -> ptr_t!(Self) { - self.maybe_next().unwrap() - } - fn set_next(&mut self, x: ptr_t!(Self)) { - self.set_next_opt(Some(x)); - } - fn set_next_opt(&mut self, x: Option); - - fn maybe_prev(&self) -> Option; - fn prev(&self) -> ptr_t!(Self) { - self.maybe_prev().unwrap() - } - fn set_prev(&mut self, x: ptr_t!(Self)) { - self.set_prev_opt(Some(x)); - } - fn set_prev_opt(&mut self, x: Option); - - fn list_add( - this: ptr_t!(Self), - list: Option, - token: &mut impl ReflAsMut>, - ) -> ptr_t!(Self) { - let (next, prev) = if let Some(first) = list { - (first, first.prev(token)) - } else { - (this, this) - }; - - this.set_next(next, token); - this.set_prev(prev, token); - prev.set_next(this, token); - next.set_prev(this, token); - - next - } - - fn list_remove( - this: ptr_t!(Self), - token: &mut impl ReflAsMut>, - ) -> Option { - let next = this.next(token); - let prev = this.prev(token); - - if this.eq(next, token) { - return None; - } - - prev.set_next(next, token); - next.set_prev(prev, token); - - Some(next) - } -} - -macro_rules! entity { - ($name:ident : $T:ident $(($init_name:ident : $init_ty:ty))? - $(, $($custom_field:ident : $custom_ty:ty = $custom_expr:expr),* )? - $(; - $( $field_vis:vis $field:ident - $([ $list_singular:ident : $list_name:ident $(($list_init:ty))? $($list_back:ident)? ])? - : $field_ty:ident ),* - )? - ) => { paste! { - pub struct $T<'brand, 'arena, V> { - id: Option, - next: Option, - prev: Option, - $($($custom_field: $custom_ty,)*)? - $($($field: Option,)*)? - } - - impl<'brand, 'arena, V> $T<'brand, 'arena, V> { - fn new($($init_name: $init_ty,)? dcel: &mut Dcel<'brand, 'arena, V>) -> own_t!(Self) { - let id = Some(dcel.$name.next_id()); - dcel.$name.alloc(Self { - id, - prev: None, - next: None, - $($($custom_field: $custom_expr,)*)? - $($($field: None,)*)? - }, &mut dcel.token) - } - } - - impl<'brand, 'arena, V> Entity<'brand, 'arena> for $T<'brand, 'arena, V> { - fn clear(&mut self) { - self.id = None; - #[cfg(debug_assertions)] - { - self.prev = None; - self.next = None; - $($(self.$field = None;)*)? - } - } - - fn type_name() -> &'static str { - stringify!($T) - } - - fn maybe_id(&self) -> Option { - self.id - } - - fn maybe_next(&self) -> Option { - self.next - } - - fn set_next_opt(&mut self, x: Option) { - self.next = x; - } - - fn maybe_prev(&self) -> Option { - self.prev - } - - fn set_prev_opt(&mut self, x: Option) { - self.prev = x; - } - } - - #[allow(unused)] - impl<'brand, 'arena, V> ptr!($T) { - $($( - $field_vis fn $field(self, token: &impl ReflAsRef>) -> ptr!($field_ty) { - self.[](token).unwrap() - } - - fn [](self, token: &impl ReflAsRef>) -> Option { - self.borrow(token).$field - } - - fn [](self, x: ptr!($field_ty), token: &mut impl ReflAsMut>) { - self.[](Some(x), token); - } - - fn [](self, x: Option, token: &mut impl ReflAsMut>,) { - self.borrow_mut(token).$field = x; - } - - $( - pub fn []<'tok>( - self, - token: &'tok impl ReflAsRef>, - ) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> - { - EntityIterator::new(self.[](token), token) - } - - pub fn []>>( - self, - token: &mut T, - mut f: impl FnMut(ptr!($field_ty), &mut T), - ) { - let Some(mut item) = self.[](token) else { - return; - }; - - let last = item.prev(token); - while { - f(item, token); - item = item.next(token); - !item.eq(last, token) - } {} - } - - fn []( - self, - x: ptr!($field_ty), - token: &mut impl ReflAsMut>, - ) { - let list = Entity::list_add(x, self.[](token), token); - self.[](list, token); - - $( - let [<_ $list_back>] = (); - x.[](self, token); - )? - } - - fn []( - self, - $(init: $list_init,)? - dcel: &mut Dcel<'brand, 'arena, V>, - ) -> own!($field_ty) { - let x = $field_ty::new($(init as $list_init,)? dcel); - self.[](*x, dcel); - x - } - )? - )*)? - } - - #[allow(unused)] - impl<'tok, 'brand, 'arena, V> lens!($T) { - $($( - $field_vis fn $field(self) -> lens!($field_ty) { - self.item.$field(&self).lens(self.token) - } - - fn [](self) -> Option { - self.item.[](&self).map(|x| x.lens(self.token)) - } - - $( - pub fn [](self) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> { - let [<_ $list_singular>] = (); - self.item.[](self.token) - } - )? - - fn [](self, f: &mut Formatter) -> fmt::Result - where V: Debug - { - $({ - let [<_ $list_singular>] = (); - if true { - // return short_debug_list(self.[](), f); - return f.debug_list().entries(self.[]()).finish(); - } - })? - short_debug(self.$field(), f) - } - )*)? - } - - impl<'tok, 'brand, 'arena, V: Debug> Debug for lens!($T) { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct(stringify!($T)) - .field("id", &self.id()) - .field("prev", &short_debug_fn(self.prev())) - .field("next", &short_debug_fn(self.next())) - $($( - .field(stringify!($field), &DisplayFn(|f| self.[](f))) - )*)? - $($( - .field(stringify!($custom_field), &DisplayFn(|f| self.[](f))) - )*)? - .finish() - } - } - - #[allow(unused)] - impl<'brand, 'arena, V> Own<'brand, 'arena, $T<'brand, 'arena, V>> { - fn free(self, dcel: &mut Dcel<'brand, 'arena, V>) { - dcel.$name.free(&mut dcel.token, self) - } - } - - impl<'brand, 'arena, V> Hash for $T<'brand, 'arena, V> { - fn hash(&self, state: &mut H) { - self.id.hash(state); - } - } - - impl<'brand, 'arena, V> PartialEq for $T<'brand, 'arena, V> { - fn eq(&self, other: &Self) -> bool { - self.id() == other.id() - } - } - impl<'brand, 'arena, V> Eq for $T<'brand, 'arena, V> {} - }}; -} - entity!(vertex: Vertex (init: V), - data: V = init; + data: Option = Some(init); outgoing: HalfEdge ); @@ -666,13 +362,21 @@ impl<'tok, 'brand, 'arena, V> Iterator for OutgoingIterator<'tok, 'brand, 'arena } } -impl<'brand, 'arena, V: Debug> ptr!(Vertex) { +impl<'brand, 'arena, V> own!(Vertex) { + fn destroy(self, dcel: &mut Dcel<'brand, 'arena, V>) -> V { + let data = self.borrow_mut(dcel).data.take().unwrap(); + self.free(dcel); + data + } +} + +impl<'brand, 'arena, V> ptr!(Vertex) { pub fn data<'tok, 'out>(self, token: &'tok impl ReflAsRef>) -> &'out V where 'arena: 'out, 'tok: 'out, { - &self.borrow(token).data + self.borrow(token).data.as_ref().unwrap() } pub fn mut_data<'tok, 'out>( @@ -683,7 +387,7 @@ impl<'brand, 'arena, V: Debug> ptr!(Vertex) { 'arena: 'out, 'tok: 'out, { - &mut self.borrow_mut(token).data + self.borrow_mut(token).data.as_mut().unwrap() } pub fn iter_outgoing<'tok>( @@ -704,7 +408,7 @@ impl<'brand, 'arena, V: Debug> ptr!(Vertex) { } } -impl<'tok, 'brand, 'arena, V: Debug> lens!(Vertex) { +impl<'tok, 'brand, 'arena, V> lens!(Vertex) { pub fn data(&self) -> &V { self.item.data(self) } @@ -717,7 +421,10 @@ impl<'tok, 'brand, 'arena, V: Debug> lens!(Vertex) { self.iter_outgoing().find(|x| x.loop_().eq(loop_)) } - fn debug_data(self, f: &mut Formatter) -> fmt::Result { + fn debug_data(self, f: &mut Formatter) -> fmt::Result + where + V: Debug, + { self.data().fmt(f) } } @@ -734,6 +441,11 @@ impl<'brand, 'arena, V> ptr!(HalfEdge) { pub fn target(self, token: &impl ReflAsRef>) -> ptr!(Vertex) { self.twin(token).origin(token) } + + fn update_origin(self, v: ptr!(Vertex), token: &mut impl ReflAsMut>) { + self.set_origin(v, token); + v.set_outgoing(self, token); + } } impl<'tok, 'brand, 'arena, V> lens!(HalfEdge) { @@ -747,10 +459,60 @@ entity!(loop_: Loop; pub face: Face ); +impl<'brand, 'arena, V> ptr!(Loop) { + pub fn is_outer(self, token: &impl ReflAsRef>) -> bool { + self.lens(token).is_outer() + } + + fn update_connectivity(self, token: &mut impl ReflAsMut>) { + self.iter_mut_half_edges(token, |x, token| x.set_loop_(self, token)); + } +} + +impl<'tok, 'brand, 'arena, V> lens!(Loop) { + pub fn is_outer(self) -> bool { + self.face().outer_loop() == self + } +} + entity!(edge: Edge, half_edges: Option<[own!(HalfEdge); 2]> = None ); +impl<'brand, 'arena, V> Edge<'brand, 'arena, V> { + fn create( + shell: ptr!(Shell), + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> (own!(Edge), [ptr!(HalfEdge); 2]) { + let edge = shell.add_new_edge(dcel); + + let he1_own = HalfEdge::new(dcel); + let he2_own = HalfEdge::new(dcel); + + let he1 = *he1_own; + let he2 = *he2_own; + + edge.borrow_mut(dcel).half_edges = Some([he1_own, he2_own]); + // edge.set_half_edges([he1_own, he2_own], dcel); + + he1.set_twin(he2, dcel); + he2.set_twin(he1, dcel); + he1.set_edge(*edge, dcel); + he2.set_edge(*edge, dcel); + + (edge, [he1, he2]) + } +} + +impl<'brand, 'arena, V> own!(Edge) { + fn destroy(self, dcel: &mut Dcel<'brand, 'arena, V>) { + let [a, b] = self.borrow_mut(dcel).half_edges.take().unwrap(); + self.free(dcel); + a.free(dcel); + b.free(dcel); + } +} + impl<'brand, 'arena, V> ptr!(Edge) { pub fn half_edges(self, token: &impl ReflAsRef>) -> [ptr!(HalfEdge); 2] { let he = self.borrow(token).half_edges.as_ref().unwrap(); @@ -761,20 +523,14 @@ impl<'brand, 'arena, V> ptr!(Edge) { self.half_edges(token).map(|x| x.origin(token)) } + /* fn set_half_edges( self, x: [own!(HalfEdge); 2], token: &mut impl ReflAsMut>, ) { self.borrow_mut(token).half_edges = Some(x); - } - - fn take_half_edges( - self, - token: &mut impl ReflAsMut>, - ) -> [own!(HalfEdge); 2] { - self.borrow_mut(token).half_edges.take().unwrap() - } + }*/ } impl<'tok, 'brand, 'arena, V> lens!(Edge) { @@ -795,7 +551,7 @@ impl<'tok, 'brand, 'arena, V> lens!(Edge) { } entity!(face: Face; - outer_loops[outer_loop: loop_ back]: Loop, + pub outer_loop: Loop, inner_loops[inner_loop: loop_ back]: Loop, pub shell: Shell ); @@ -848,15 +604,6 @@ impl<'brand, 'arena, T: Entity<'brand, 'arena>> Allocator<'brand, 'arena, T> { } } -pub struct Mevvlfs<'brand, 'arena, V> { - pub body: ptr!(Body), - pub edge: own!(Edge), - pub vertices: [own!(Vertex); 2], - pub loop_: own!(Loop), - pub face: own!(Face), - pub shell: own!(Shell), -} - pub struct Melf<'brand, 'arena, V> { pub shell: ptr!(Shell), pub vertices: [ptr!(Vertex); 2], @@ -881,46 +628,40 @@ pub struct Mve<'brand, 'arena, V> { pub vertex: own!(Vertex), } -pub enum EulerOp<'brand, 'arena, V> { - Mevvlfs(Mevvlfs<'brand, 'arena, V>), - Melf(Melf<'brand, 'arena, V>), - Mev(Mev<'brand, 'arena, V>), - Mve(Mve<'brand, 'arena, V>), +pub struct OperatorErr { + pub op: T, + pub err: E, } -macro_rules! euler_op { - ($x:ident) => { - impl<'brand, 'arena, V> From<$x<'brand, 'arena, V>> for EulerOp<'brand, 'arena, V> { - fn from(op: $x<'brand, 'arena, V>) -> Self { - Self::$x(op) - } - } - }; +impl OperatorErr { + pub fn new(op: T, err: E) -> Self { + Self { op, err } + } +} + +impl std::error::Error for OperatorErr {} +impl Debug for OperatorErr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.err.fmt(f) + } +} +impl Display for OperatorErr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.err.fmt(f) + } } -euler_op!(Mevvlfs); -euler_op!(Melf); -euler_op!(Mev); -euler_op!(Mve); - -#[derive(Debug, Error)] -pub enum KevvlfsError { - #[error("edge vertices do not equal vertices")] - EdgeVerticesMismatch, - #[error("half_edge loop does not equal loop")] - HalfEdgeLoopMismatch, - #[error("loop is not cycle between half edges")] - InvalidLoop, - #[error("face outer loop does not match loop")] - FaceOuterLoopMismatch, - #[error("face has inner loops")] - FaceHasInnerLoops, - #[error("shell has more than one face")] - ShellHasMoreThanOneFace, - #[error("shell face does not match face")] - ShellFaceMismatch, - #[error("shell body does not match body")] - ShellBodyMismatch, +pub trait Operator<'brand, 'arena, V>: Sized { + type Inverse; //: Operator<'brand, 'arena, V>; + type Error: std::error::Error; + type Check; + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result; + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result>; } pub struct DcelArena<'brand, 'arena, V> { @@ -971,7 +712,7 @@ impl<'brand, 'arena, V> ReflAsMut> for Dcel<'brand, 'arena, V } } -impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { +impl<'brand, 'arena, V> Dcel<'brand, 'arena, V> { pub fn from_token(token: GhostToken<'brand>, ar: &'arena DcelArena<'brand, 'arena, V>) -> Self { Self { token, @@ -986,7 +727,7 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { } } - pub fn new(fun: F) -> R + pub fn new(fun: F) -> R where for<'new_brand, 'new_arena> F: FnOnce(Dcel<'new_brand, 'new_arena, W>) -> R, { @@ -1015,147 +756,33 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { EntityIterator::new(self.bodies, self) } - fn new_edge(&mut self, shell: ptr!(Shell)) -> (own!(Edge), [ptr!(HalfEdge); 2]) { - let edge = shell.add_new_edge(self); - - let he1_own = HalfEdge::new(self); - let he2_own = HalfEdge::new(self); - - let he1 = *he1_own; - let he2 = *he2_own; - - edge.set_half_edges([he1_own, he2_own], self); - - he1.set_twin(he2, self); - he2.set_twin(he1, self); - he1.set_edge(*edge, self); - he2.set_edge(*edge, self); - - (edge, [he1, he2]) - } - - #[inline(always)] - fn origin(&mut self, v: ptr!(Vertex), h: ptr!(HalfEdge)) { - v.set_outgoing(h, self); - h.set_origin(v, self) - } + // fn new_edge(&mut self, shell: ptr!(Shell)) -> (own!(Edge), [ptr!(HalfEdge); 2]) {} - #[inline(always)] fn follow(&mut self, prev: ptr!(HalfEdge), next: ptr!(HalfEdge)) { next.set_prev(prev, self); prev.set_next(next, self); } - pub fn undo(&mut self, op: impl Into>) { - match op.into() { - EulerOp::Mevvlfs(x) => self.kevvlfs(x), - _ => todo!(), - } - } - - // Make Edge-Vertex-Vertex-Loop-Face-Shell - - pub fn mevvlfs(&mut self, body: ptr!(Body), data: [V; 2]) -> Mevvlfs<'brand, 'arena, V> { - let [d1, d2] = data; - - let shell = body.add_new_shell(self); - let face = shell.add_new_face(self); - let (edge, [a, b]) = self.new_edge(*shell); - let loop_ = face.add_new_outer_loop(self); - let v1 = shell.add_new_vertex(d1, self); - let v2 = shell.add_new_vertex(d2, self); - - self.origin(*v1, a); - self.origin(*v2, b); - - loop_.add_half_edge(a, self); - loop_.add_half_edge(b, self); - - Mevvlfs { - body, - edge, - vertices: [v1, v2], - loop_, - face, - shell, - } - } - - pub fn check_kevvlfs(&self, op: &Mevvlfs<'brand, 'arena, V>) -> Result<(), KevvlfsError> { - let Mevvlfs { - body, - edge, - vertices: [v1, v2], - loop_, - face, - shell, - } = op; - - mklens!(self, edge, loop_, face, shell, body, v1, v2); - - let [a, b] = edge.half_edges(); - let edge_verts = edge.vertices(); - - or_err( - edge_verts == [v1, v2] || edge_verts == [v2, v1], - KevvlfsError::EdgeVerticesMismatch, - )?; - - or_err(a.loop_() == loop_, KevvlfsError::HalfEdgeLoopMismatch)?; - or_err(a.next() == b, KevvlfsError::InvalidLoop)?; - or_err(b.next() == a, KevvlfsError::InvalidLoop)?; - - or_err( - face.outer_loops() == loop_, - KevvlfsError::FaceOuterLoopMismatch, - )?; - or_err( - face.maybe_inner_loops().is_none(), - KevvlfsError::FaceHasInnerLoops, - )?; - - or_err(face.next() == face, KevvlfsError::ShellHasMoreThanOneFace)?; - or_err(shell.faces() == face, KevvlfsError::ShellFaceMismatch)?; - or_err(shell.body() == body, KevvlfsError::ShellBodyMismatch)?; - - Ok(()) - } - - pub fn try_kevvlfs( + pub fn mevvlfs( &mut self, - op: Mevvlfs<'brand, 'arena, V>, - ) -> Result<(), (Mevvlfs<'brand, 'arena, V>, KevvlfsError)> { - if let Err(err) = self.check_kevvlfs(&op) { - return Err((op, err)); - } - - let Mevvlfs { - body, - edge, - vertices: [v1, v2], - loop_, - face, - shell, - } = op; - - let [a, b] = edge.take_half_edges(self); - let shells = Entity::list_remove(*shell, self); - body.set_opt_shells(shells, self); - - edge.free(self); - a.free(self); - b.free(self); - loop_.free(self); - face.free(self); - shell.free(self); - v1.free(self); - v2.free(self); - - Ok(()) + body: ptr!(Body), + data: [V; 2], + ) -> Result, OperatorErr, Infallible>> + { + Mevvlfs::new(body, data).apply(self) } - pub fn kevvlfs(&mut self, op: Mevvlfs<'brand, 'arena, V>) { - self.try_kevvlfs(op).map_err(|(_, e)| e).unwrap() + pub fn kevvlfs( + &mut self, + body: ptr!(Body), + edge: own!(Edge), + vertices: [own!(Vertex); 2], + loop_: own!(Loop), + face: own!(Face), + shell: own!(Shell), + ) -> Result, OperatorErr, KevvlfsError>> + { + Kevvlfs::new(body, edge, vertices, loop_, face, shell).apply(self) } pub fn mev( @@ -1177,7 +804,7 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { // a / \ d // < < - let (edge, [b, c]) = self.new_edge(shell); + let (edge, [b, c]) = Edge::create(shell, self); let new_vertex = shell.add_new_vertex(data, self); let a = old_vertex.find_outgoing(loop_, self).unwrap(); @@ -1190,8 +817,8 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { b.set_loop_(loop_, self); c.set_loop_(loop_, self); - self.origin(*new_vertex, b); - self.origin(old_vertex, c); + b.update_origin(*new_vertex, self); + c.update_origin(old_vertex, self); Mev { shell, @@ -1223,9 +850,9 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { // < < // - let (edge, [a1, b1]) = self.new_edge(shell); + let (edge, [a1, b1]) = Edge::create(shell, self); let face = shell.add_new_face(self); - let new_loop = face.add_new_outer_loop(self); + let new_loop = Loop::new(self); // face.add_new_outer_loop(self); let [v1, v2] = vertices; let [b0, a2] = vertices.map(|v| v.find_outgoing(old_loop, self).unwrap()); @@ -1233,17 +860,21 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { let a0 = b0.prev(self); let b2 = a2.prev(self); - self.origin(v1, a1); + new_loop.set_face(*face, self); + face.set_outer_loop(*new_loop, self); + + a1.update_origin(v1, self); self.follow(a0, a1); self.follow(a1, a2); old_loop.set_half_edges(a1, self); a1.set_loop_(old_loop, self); - self.origin(v2, b1); + b1.update_origin(v2, self); self.follow(b2, b1); self.follow(b1, b0); new_loop.set_half_edges(b1, self); - new_loop.iter_mut_half_edges(self, |x, dcel| x.set_loop_(*new_loop, dcel)); + new_loop.update_connectivity(self); + // new_loop.iter_mut_half_edges(self, |x, dcel| x.set_loop_(*new_loop, dcel)); Melf { shell, @@ -1281,7 +912,7 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { // \ b3 // < - let (new_edge, [a2, b2]) = self.new_edge(shell); + let (new_edge, [a2, b2]) = Edge::create(shell, self); let v = shell.add_new_vertex(data, self); let [a1, b1] = old_edge.half_edges(self); @@ -1297,9 +928,9 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { b3 = a2; } - self.origin(*v, a2); - self.origin(*v, b1); - self.origin(v2, b2); + a2.update_origin(*v, self); + b1.update_origin(*v, self); + b2.update_origin(v2, self); self.follow(a1, a2); self.follow(a2, a3); @@ -1313,153 +944,66 @@ impl<'brand, 'arena, V: Debug> Dcel<'brand, 'arena, V> { vertex: v, } } -} -#[cfg(test)] -mod tests { - use crate::Dcel; - - #[test] - fn mev_cycle() { - Dcel::::new(|mut dcel| { - let body = dcel.new_body(); - let op = dcel.mevvlfs(*body, [0, 1]); - let op2 = dcel.mev(*op.shell, *op.loop_, *op.vertices[1], 2); - let op3 = dcel.mev(*op.shell, *op.loop_, *op2.new_vertex, 3); - dcel.melf(*op.shell, [*op3.new_vertex, *op.vertices[0]], *op.loop_); - - let mut vertices = op - .loop_ - .iter_half_edges(&dcel) - .map(|x| *x.origin().data()) - .peekable(); - assert!((0..4) - .cycle() - .skip(*vertices.peek().unwrap() as _) - .take(4) - .eq(vertices)); - }) + pub fn mekh( + &mut self, + shell: ptr!(Shell), + into_loop: ptr!(Loop), + into_vertex: ptr!(Vertex), + hole_loop: own!(Loop), + hole_vertex: ptr!(Vertex), + ) -> Result, OperatorErr, MekhError>> { + Mekh::new(shell, into_loop, into_vertex, hole_loop, hole_vertex).apply(self) } -} -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DcelDotOptions { - pub twin: bool, - pub next: bool, - pub prev: bool, -} - -impl DcelDotOptions { - pub fn none() -> Self { - Self { - twin: false, - next: false, - prev: false, - } + pub fn kemh( + &mut self, + shell: ptr!(Shell), + edge: own!(Edge), + loop_: ptr!(Loop), + hole_vertex: ptr!(Vertex), + ) -> Result, OperatorErr, KemhError>> { + Kemh::new(shell, edge, loop_, hole_vertex).apply(self) } - pub fn all() -> Self { - Self { - twin: true, - next: true, - prev: true, - } - } -} + /* pub fn mekh( + &mut self, + ) -> Result, MekhError> { + let face = loops[0].0.face(self); + assert!(loops[1].0.lens(self).face().eq(face)); -pub fn dcel_write_dot( - dcel: &Dcel, - pos: impl Fn(&V) -> [f64; 2], - name: impl Fn(&V, &mut Formatter) -> fmt::Result, - f: &mut Formatter, - opt: DcelDotOptions, -) -> fmt::Result { - writeln!(f, "digraph DCEL {{")?; - writeln!(f, "node [shape = circle]")?; - //writeln!(f, "nodesep = 1")?; + let outer = loops.map(|(l, _)| face.lens(self).outer_loop().eq(l)); + if outer[0] && outer[1] { + panic!("cannot connect outer loops"); + } + if outer[1] { + loops = [loops[1], loops[0]]; + } - for shell in dcel.iter_bodies().flat_map(Lens::iter_shells) { - for vertex in shell.iter_vertices() { - let p = pos(vertex.data()); + let [b0, a2] = loops.map(|(l, v)| v.find_outgoing(l, self).unwrap()); - writeln!( - f, - "vertex_{} [label=\"{}\", pos=\"{},{}!\"]", - vertex.id(), - DisplayFn(|f| name(vertex.data(), f)), - p[0], - p[1] - )?; - } + let (edge, [a1, b1]) = self.new_edge(shell); - for hedges in shell - .iter_edges() - .map(|x| x.half_edges()) - .flat_map(|[he1, he2]| [[he1, he2], [he2, he1]]) - { - let ids = hedges.map(Lens::id); - let vertices = hedges.map(|h| h.origin()); - let points = vertices.map(|v| pos(v.data())); + let a0 = b0.prev(self); + let b2 = a2.prev(self); - let mut diff = [points[1][1] - points[0][1], points[1][0] - points[0][0]]; + self.origin(loops[0].1, a1); + self.follow(a0, a1); + self.follow(a1, a2); - let len = (diff[0] * diff[0] + diff[1] * diff[1]).sqrt(); - diff[0] *= -0.075; - diff[1] *= 0.075; + self.origin(loops[1].1, b1); + self.follow(b2, b1); + self.follow(b1, b0); - let mid = [ - (points[1][0] + points[0][0]) / 2.0 + diff[0], - (points[1][1] + points[0][1]) / 2.0 + diff[1], - ]; + loops[0] + .0 + .iter_mut_half_edges(self, |x, dcel| x.set_loop_(loops[0].0, dcel)); - writeln!( - f, - "half_edge_{} [pos=\"{},{}!\", shape=point, width=0.01, height=0.01]", - ids[0], mid[0], mid[1] - )?; - writeln!( - f, - "vertex_{} -> half_edge_{} [arrowhead=none]", - vertices[0].id(), - ids[0] - )?; - writeln!( - f, - "half_edge_{} -> vertex_{} [label=\"{}\"]", - ids[0], - vertices[1].id(), - ids[0] - )?; - - if opt.twin { - writeln!( - f, - "half_edge_{} -> half_edge_{} [color=\"red\"]", - ids[0], ids[1] - )?; - } - - if opt.next { - writeln!( - f, - "half_edge_{} -> half_edge_{} [color=\"green\"]", - ids[0], - hedges[0].next().id(), - )?; - } - - if opt.prev { - writeln!( - f, - "half_edge_{} -> half_edge_{} [color=\"blue\"]", - ids[0], - hedges[0].prev().id(), - )?; - } - } - } + face.remove_inner_loop(loops[1].0, self); + from_loop.free(self); - writeln!(f, "}}") + Ok(Mekh { shell }) + } */ } use std::io::Write; @@ -1492,7 +1036,9 @@ fn main() { // Mevvlfs(a, [w, n], l, f, s) //let op = dcel.mevvlfs(*body, [("W", [-4, 0]), ("N", [0, 4])]); - let op = dcel.mevvlfs(*body, [("W", [-4, 0]), ("N", [0, 4])]); + let op = dcel + .mevvlfs(*body, [("W", [-4, 0]), ("N", [0, 4])]) + .unwrap(); let op2 = dcel.mev(*op.shell, *op.loop_, *op.vertices[1], ("E", [4, 0])); let op3 = dcel.mev(*op.shell, *op.loop_, *op2.new_vertex, ("S", [0, -4])); diff --git a/src/mekh.rs b/src/mekh.rs new file mode 100644 index 0000000..9b23115 --- /dev/null +++ b/src/mekh.rs @@ -0,0 +1,212 @@ +use crate::*; + +pub struct Mekh<'brand, 'arena, V> { + pub shell: ptr!(Shell), + pub into_loop: ptr!(Loop), + pub into_vertex: ptr!(Vertex), + pub hole_loop: own!(Loop), + pub hole_vertex: ptr!(Vertex), +} + +impl<'brand, 'arena, V> Mekh<'brand, 'arena, V> { + pub fn new( + shell: ptr!(Shell), + into_loop: ptr!(Loop), + into_vertex: ptr!(Vertex), + hole_loop: own!(Loop), + hole_vertex: ptr!(Vertex), + ) -> Self { + Self { + shell, + into_loop, + into_vertex, + hole_loop, + hole_vertex, + } + } +} + +#[derive(Debug, Error)] +pub enum MekhError { + #[error("cannot join loop with itself")] + SameLoop, + #[error("loops do not share the same face")] + LoopFaceMismatch, + #[error("hole loop is an outer loop")] + HoleIsOuter, + #[error("vertex is not part of loop")] + VertexLoopMismatch, +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Mekh<'brand, 'arena, V> { + type Inverse = Kemh<'brand, 'arena, V>; + type Error = MekhError; + type Check = [ptr!(HalfEdge); 2]; + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result { + use MekhError::*; + + let into_loop = self.into_loop.lens(dcel); + or_err(!into_loop.eq(*self.hole_loop), SameLoop)?; + or_err( + into_loop.face().eq(self.hole_loop.face(dcel)), + LoopFaceMismatch, + )?; + or_err(!self.hole_loop.is_outer(dcel), HoleIsOuter)?; + + let into_he = self + .into_vertex + .find_outgoing(self.into_loop, dcel) + .ok_or(VertexLoopMismatch)?; + let hole_he = self + .hole_vertex + .find_outgoing(*self.hole_loop, dcel) + .ok_or(VertexLoopMismatch)?; + + Ok([into_he, hole_he]) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result> { + let [b0, a2] = try_check!(self, dcel); + + let Mekh { + shell, + into_loop, + into_vertex, + hole_loop, + hole_vertex, + } = self; + + let (edge, [a1, b1]) = Edge::create(shell, dcel); + + let a0 = b0.prev(dcel); + let b2 = a2.prev(dcel); + + a1.update_origin(into_vertex, dcel); + dcel.follow(a0, a1); + dcel.follow(a1, a2); + + b1.update_origin(hole_vertex, dcel); + dcel.follow(b2, b1); + dcel.follow(b1, b0); + + into_loop.update_connectivity(dcel); + + hole_loop.face(dcel).remove_inner_loop(*hole_loop, dcel); + hole_loop.free(dcel); + + Ok(Kemh { + shell, + edge, + loop_: into_loop, + hole_vertex, + }) + } +} + +pub struct Kemh<'brand, 'arena, V> { + pub shell: ptr!(Shell), + pub edge: own!(Edge), + pub loop_: ptr!(Loop), + pub hole_vertex: ptr!(Vertex), +} + +#[derive(Error, Debug)] +pub enum KemhError { + #[error("vertex is not part of edge")] + HalfEdgeVertexMismatch, + #[error("both half edges need to be part of loop")] + HalfEdgeLoopMismatch, +} + +impl<'brand, 'arena, V> Kemh<'brand, 'arena, V> { + pub fn new( + shell: ptr!(Shell), + edge: own!(Edge), + loop_: ptr!(Loop), + hole_vertex: ptr!(Vertex), + ) -> Self { + Self { + shell, + edge, + loop_, + hole_vertex, + } + } +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Kemh<'brand, 'arena, V> { + type Inverse = Mekh<'brand, 'arena, V>; + type Error = KemhError; + type Check = [ptr!(HalfEdge); 2]; + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result { + use KemhError::*; + let Kemh { + edge, + loop_, + hole_vertex, + .. + } = self; + + let [mut a, mut b] = edge.lens(dcel).half_edges(); + + if a.origin().eq(*hole_vertex) { + [b, a] = [a, b]; + } else { + or_err(b.origin().eq(*hole_vertex), HalfEdgeVertexMismatch)?; + } + + or_err( + a.loop_().eq(*loop_) && b.loop_().eq(*loop_), + HalfEdgeLoopMismatch, + )?; + + Ok([a.item, b.item]) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result> { + let [a1, b1] = try_check!(self, dcel); + let Kemh { + shell, + edge, + loop_: into_loop, + hole_vertex, + } = self; + + let hole_loop = into_loop.face(dcel).add_new_inner_loop(dcel); + let into_vertex = a1.origin(dcel); + + let a0 = a1.prev(dcel); + let a2 = a1.next(dcel); + + let b0 = b1.next(dcel); + let b2 = b1.prev(dcel); + + dcel.follow(a0, b0); + dcel.follow(b2, a2); + + b0.update_origin(into_vertex, dcel); + a2.update_origin(hole_vertex, dcel); + + hole_loop.set_half_edges(a2, dcel); + hole_loop.update_connectivity(dcel); + + shell.remove_edge(*edge, dcel); + edge.destroy(dcel); + + Ok(Mekh { + shell, + into_loop, + into_vertex, + hole_loop, + hole_vertex, + }) + } +} diff --git a/src/mevvlfs.rs b/src/mevvlfs.rs new file mode 100644 index 0000000..370ad96 --- /dev/null +++ b/src/mevvlfs.rs @@ -0,0 +1,184 @@ +use crate::*; + +// Make Edge-Vertex-Vertex-Loop-Face-Shell + +pub struct Mevvlfs<'brand, 'arena, V> { + body: ptr!(Body), + data: [V; 2], +} + +impl<'brand, 'arena, V> Mevvlfs<'brand, 'arena, V> { + pub fn new(body: ptr!(Body), data: [V; 2]) -> Self { + Self { body, data } + } +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Mevvlfs<'brand, 'arena, V> { + type Inverse = Kevvlfs<'brand, 'arena, V>; + type Error = Infallible; + type Check = (); + + fn check(&self, _dcel: &Dcel<'brand, 'arena, V>) -> Result { + Ok(()) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result> { + try_check!(self, dcel); + + let Mevvlfs { + body, + data: [d1, d2], + } = self; + + let shell = body.add_new_shell(dcel); + let face = shell.add_new_face(dcel); + let (edge, [a, b]) = Edge::create(*shell, dcel); + let loop_ = Loop::new(dcel); + let v1 = shell.add_new_vertex(d1, dcel); + let v2 = shell.add_new_vertex(d2, dcel); + + loop_.set_face(*face, dcel); + face.set_outer_loop(*loop_, dcel); + + a.update_origin(*v1, dcel); + b.update_origin(*v2, dcel); + + loop_.add_half_edge(a, dcel); + loop_.add_half_edge(b, dcel); + + Ok(Kevvlfs { + body, + edge, + vertices: [v1, v2], + loop_, + face, + shell, + }) + } +} + +pub struct Kevvlfs<'brand, 'arena, V> { + pub body: ptr!(Body), + pub edge: own!(Edge), + pub vertices: [own!(Vertex); 2], + pub loop_: own!(Loop), + pub face: own!(Face), + pub shell: own!(Shell), +} + +#[derive(Debug, Error)] +pub enum KevvlfsError { + #[error("edge vertices do not equal vertices")] + EdgeVerticesMismatch, + #[error("half_edge loop does not equal loop")] + HalfEdgeLoopMismatch, + #[error("loop is not cycle between half edges")] + InvalidLoop, + #[error("face outer loop does not match loop")] + FaceOuterLoopMismatch, + #[error("face has inner loops")] + FaceHasInnerLoops, + #[error("shell has more than one face")] + ShellHasMoreThanOneFace, + #[error("shell face does not match face")] + ShellFaceMismatch, + #[error("shell body does not match body")] + ShellBodyMismatch, +} + +impl<'brand, 'arena, V> Kevvlfs<'brand, 'arena, V> { + pub fn new( + body: ptr!(Body), + edge: own!(Edge), + vertices: [own!(Vertex); 2], + loop_: own!(Loop), + face: own!(Face), + shell: own!(Shell), + ) -> Self { + Self { + body, + edge, + vertices, + loop_, + face, + shell, + } + } +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Kevvlfs<'brand, 'arena, V> { + type Inverse = Mevvlfs<'brand, 'arena, V>; + type Error = KevvlfsError; + type Check = (); + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result { + let Kevvlfs { + body, + edge, + vertices: [v1, v2], + loop_, + face, + shell, + } = self; + + mklens!(dcel, edge, loop_, face, shell, body, v1, v2); + + let [a, b] = edge.half_edges(); + let edge_verts = edge.vertices(); + + or_err( + edge_verts == [v1, v2] || edge_verts == [v2, v1], + KevvlfsError::EdgeVerticesMismatch, + )?; + + or_err(a.loop_() == loop_, KevvlfsError::HalfEdgeLoopMismatch)?; + or_err(a.next() == b, KevvlfsError::InvalidLoop)?; + or_err(b.next() == a, KevvlfsError::InvalidLoop)?; + + or_err( + face.outer_loop() == loop_, + KevvlfsError::FaceOuterLoopMismatch, + )?; + or_err( + face.maybe_inner_loops().is_none(), + KevvlfsError::FaceHasInnerLoops, + )?; + + or_err(face.next() == face, KevvlfsError::ShellHasMoreThanOneFace)?; + or_err(shell.faces() == face, KevvlfsError::ShellFaceMismatch)?; + or_err(shell.body() == body, KevvlfsError::ShellBodyMismatch)?; + + Ok(()) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result> { + try_check!(self, dcel); + + let Kevvlfs { + body, + edge, + vertices, + loop_, + face, + shell, + } = self; + + body.remove_shell(*shell, dcel); + + edge.destroy(dcel); + loop_.free(dcel); + face.free(dcel); + shell.free(dcel); + + Ok(Mevvlfs { + body, + data: vertices.map(|v| v.destroy(dcel)), + }) + } +} diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..5132223 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,147 @@ +use crate::*; + +#[test] +fn mev_cycle() { + Dcel::::new(|mut dcel| { + let body = dcel.new_body(); + let op = dcel.mevvlfs(*body, [0, 1]).unwrap(); + let op2 = dcel.mev(*op.shell, *op.loop_, *op.vertices[1], 2); + let op3 = dcel.mev(*op.shell, *op.loop_, *op2.new_vertex, 3); + dcel.melf(*op.shell, [*op3.new_vertex, *op.vertices[0]], *op.loop_); + + let mut vertices = op + .loop_ + .iter_half_edges(&dcel) + .map(|x| *x.origin().data()) + .peekable(); + + assert!((0..4) + .cycle() + .skip(*vertices.peek().unwrap() as _) + .take(4) + .eq(vertices)); + }) +} + +#[test] +fn kemh_mekh() { + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + enum Vert { + Inner(u8), + Outer(u8), + } + use Vert::*; + + impl Vert { + fn flip(self) -> Self { + match self { + Outer(x) => Inner(x), + Inner(x) => Outer(x), + } + } + + fn is_outer(self) -> bool { + match self { + Outer(_) => true, + Inner(_) => false, + } + } + + fn either(self) -> u8 { + match self { + Outer(x) => x, + Inner(x) => x, + } + } + } + + Dcel::::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 mut kemh = Kemh::new(*shell, edge, *outer_loop, *inner_0); + + for i in 0..10 { + struct State { + seen: u8, + last: Option, + } + + let mut st = State { + seen: 0, + last: None, + }; + + for v in outer_loop + .iter_half_edges(&dcel) + .map(|x| *x.origin().data()) + { + let mut s = 1u8 << v.either(); + if v.is_outer() { + s <<= 4; + } + if st.seen & s == 0 { + st.seen |= s; + } else { + assert_eq!(v.either(), 0); + assert_eq!(st.seen & (s << 3), 0); + st.seen |= s << 3; + } + + if let Some(last) = st.last { + if v.either() == 0 { + assert!( + last == v.flip() + || (last.is_outer() == v.is_outer() && last.either() != 0) + ); + } else { + assert_eq!(last.is_outer(), v.is_outer()); + } + } + + st.last = Some(v); + } + + assert_eq!(st.seen, 255); + + let mekh = kemh.apply(&mut dcel).unwrap(); + + for (loop_, outer) in [(*outer_loop, true), (*mekh.hole_loop, false)] { + let mut seen = 0; + for v in loop_.iter_half_edges(&dcel).map(|x| *x.origin().data()) { + let s = 1 << v.either(); + assert_eq!(v.is_outer(), outer); + assert_eq!(seen & s, 0); + seen |= s; + } + assert_eq!(seen, 7); + } + + kemh = mekh.apply(&mut dcel).unwrap(); + } + }) +} -- cgit v1.2.3