From 219261b7042fba1a54ecd478b56e902d9ca8787b Mon Sep 17 00:00:00 2001 From: Charlotte Pabst Date: Thu, 7 Mar 2024 21:52:30 +0100 Subject: --- src/mekh.rs | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 src/mekh.rs (limited to 'src/mekh.rs') 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, + }) + } +} -- cgit v1.2.3