honeycomb_kernels/remeshing/
swap.rs1use honeycomb_core::{
2 cmap::{CMap2, DartIdType, EdgeIdType, NULL_DART_ID, NULL_EDGE_ID, SewError},
3 geometry::CoordsFloat,
4 stm::{Transaction, TransactionClosureResult, abort, try_or_coerce},
5};
6
7use crate::utils::{FaceAnchor, VertexAnchor};
8
9#[derive(thiserror::Error, Debug, PartialEq, Eq)]
11pub enum EdgeSwapError {
12 #[error("core operation failed: {0}")]
14 FailedCoreOp(#[from] SewError),
15 #[error("cannot swap edge due to constraints: {0}")]
17 NotSwappable(&'static str),
18 #[error("cannot swap null edge")]
20 NullEdge,
21 #[error("cannot swap an edge adjacent to a single cell")]
23 IncompleteEdge,
24 #[error("cannot swap an edge adjacent to a non-triangular cell")]
26 BadTopology,
27}
28
29#[inline]
76pub fn swap_edge<T: CoordsFloat>(
77 t: &mut Transaction,
78 map: &CMap2<T>,
79 e: EdgeIdType,
80) -> TransactionClosureResult<(), EdgeSwapError> {
81 if e == NULL_EDGE_ID {
82 abort(EdgeSwapError::NullEdge)?;
83 }
84 let (l, r) = (e as DartIdType, map.beta_transac::<2>(t, e as DartIdType)?);
85 if r == NULL_DART_ID {
86 abort(EdgeSwapError::IncompleteEdge)?;
87 }
88 let (l_a, r_a) = if map.contains_attribute::<FaceAnchor>() {
89 let l_fid = map.face_id_transac(t, l)?;
90 let r_fid = map.face_id_transac(t, r)?;
91 let l_a = map.remove_attribute::<FaceAnchor>(t, l_fid)?;
92 let r_a = map.remove_attribute::<FaceAnchor>(t, r_fid)?;
93 if l_a != r_a {
94 abort(EdgeSwapError::NotSwappable(
95 "edge separates two distinct surfaces",
96 ))?;
97 }
98 (l_a, r_a)
99 } else {
100 (None, None)
101 };
102
103 let (b1l, b1r) = (map.beta_transac::<1>(t, l)?, map.beta_transac::<1>(t, r)?);
104 let (b0l, b0r) = (map.beta_transac::<0>(t, l)?, map.beta_transac::<0>(t, r)?);
105 if map.beta_transac::<1>(t, b1l)? != b0l || map.beta_transac::<1>(t, b1r)? != b0r {
106 abort(EdgeSwapError::BadTopology)?;
107 }
108
109 try_or_coerce!(map.unsew::<1>(t, l), EdgeSwapError);
110 try_or_coerce!(map.unsew::<1>(t, r), EdgeSwapError);
111 try_or_coerce!(map.unsew::<1>(t, b0l), EdgeSwapError);
112 try_or_coerce!(map.unsew::<1>(t, b0r), EdgeSwapError);
113 try_or_coerce!(map.unsew::<1>(t, b1l), EdgeSwapError);
114 try_or_coerce!(map.unsew::<1>(t, b1r), EdgeSwapError);
115
116 let l_vid = map.vertex_id_transac(t, l)?;
118 let r_vid = map.vertex_id_transac(t, r)?;
119 let _ = map.remove_vertex(t, l_vid)?;
120 let _ = map.remove_vertex(t, r_vid)?;
121 if map.contains_attribute::<VertexAnchor>() {
122 map.remove_attribute::<VertexAnchor>(t, l_vid)?;
123 map.remove_attribute::<VertexAnchor>(t, r_vid)?;
124 }
125
126 try_or_coerce!(map.sew::<1>(t, l, b0r), EdgeSwapError);
127 try_or_coerce!(map.sew::<1>(t, b0r, b1l), EdgeSwapError);
128 try_or_coerce!(map.sew::<1>(t, b1l, l), EdgeSwapError);
129 try_or_coerce!(map.sew::<1>(t, r, b0l), EdgeSwapError);
130 try_or_coerce!(map.sew::<1>(t, b0l, b1r), EdgeSwapError);
131 try_or_coerce!(map.sew::<1>(t, b1r, r), EdgeSwapError);
132
133 match (l_a, r_a) {
135 (Some(l_a), Some(r_a)) => {
136 let l_fid = map.face_id_transac(t, l)?;
137 let r_fid = map.face_id_transac(t, r)?;
138 map.write_attribute(t, l_fid, l_a)?;
139 map.write_attribute(t, r_fid, r_a)?;
140 }
141 (Some(_), None) | (None, Some(_)) => unreachable!(),
142 (None, None) => {}
143 }
144
145 Ok(())
146}