diff options
Diffstat (limited to 'src/mev.rs')
-rw-r--r-- | src/mev.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/mev.rs b/src/mev.rs new file mode 100644 index 0000000..41a2ceb --- /dev/null +++ b/src/mev.rs @@ -0,0 +1,140 @@ +use crate::*; + +// Make Edge-Vertex + +pub struct Mev<'brand, 'arena, V> { + pub loop_: ptr!(Loop), + pub vertex: ptr!(Vertex), + pub data: V, +} + +impl<'brand, 'arena, V> Mev<'brand, 'arena, V> { + pub fn new(loop_: ptr!(Loop), vertex: ptr!(Vertex), data: V) -> Self { + Self { + loop_, + vertex, + data, + } + } +} + +#[derive(Debug, Error)] +pub enum MevError { + #[error("vertex is not part of loop")] + VertexLoopMismatch, +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Mev<'brand, 'arena, V> { + type Inverse = Kev<'brand, 'arena, V>; + type Error = MevError; + type Check = ptr!(HalfEdge); + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result<Self::Check, Self::Error> { + self.vertex + .find_outgoing(self.loop_, dcel) + .ok_or(MevError::VertexLoopMismatch) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result<Self::Inverse, OperatorErr<Self, Self::Error>> { + // + // o + // a / \ d + // < < + // + + // < n < + // b | | c + // o + // a / \ d + // < < + + let a = try_check!(self, dcel); + let d = a.prev(dcel); + + let shell = self.loop_.face(dcel).shell(dcel); + let (edge, [b, c]) = Edge::create(shell, dcel); + let vertex = shell.add_new_vertex(self.data, dcel); + + dcel.follow(d, c); + dcel.follow(c, b); + dcel.follow(b, a); + + b.set_loop_(self.loop_, dcel); + c.set_loop_(self.loop_, dcel); + + b.update_origin(*vertex, dcel); + c.update_origin(self.vertex, dcel); + + Ok(Kev { edge, vertex }) + } +} + +pub struct Kev<'brand, 'arena, V> { + pub edge: own!(Edge), + pub vertex: own!(Vertex), +} + +impl<'brand, 'arena, V> Kev<'brand, 'arena, V> { + pub fn new(edge: own!(Edge), vertex: own!(Vertex)) -> Self { + Self { edge, vertex } + } +} + +#[derive(Debug, Error)] +pub enum KevError { + #[error("half edges don't go back and forth between new and old vertex")] + NotBackForth, + #[error("new vertex is not the turning point")] + EdgeVertexMismatch, + #[error("vertex has more than one outgoing edge")] + VertexNotSingleton, +} + +impl<'brand, 'arena, V> Operator<'brand, 'arena, V> for Kev<'brand, 'arena, V> { + type Inverse = Mev<'brand, 'arena, V>; + type Error = KevError; + type Check = [ptr!(HalfEdge); 2]; + + fn check(&self, dcel: &Dcel<'brand, 'arena, V>) -> Result<Self::Check, Self::Error> { + use KevError::*; + + let [mut b, mut c] = self.edge.lens(dcel).half_edges(); + + if b.next() == c { + [b, c] = [c, b]; + } + + or_err(c.next() == b, NotBackForth)?; + or_err(b.origin().eq(*self.vertex), EdgeVertexMismatch)?; + + or_err( + self.vertex.iter_outgoing(dcel).count() == 1, + VertexNotSingleton, + )?; + + Ok([b.item, c.item]) + } + + fn apply( + self, + dcel: &mut Dcel<'brand, 'arena, V>, + ) -> Result<Self::Inverse, OperatorErr<Self, Self::Error>> { + let [b, c] = try_check!(self, dcel); + + let a = b.next(dcel); + let d = c.prev(dcel); + dcel.follow(d, a); + + self.edge.destroy(dcel); + let data = self.vertex.destroy(dcel); + + Ok(Mev { + data, + vertex: a.origin(dcel), + loop_: a.loop_(dcel), + }) + } +} |