honeycomb_kernels/remeshing/
cut.rs

1use honeycomb_core::{
2    cmap::{CMap2, DartIdType, EdgeIdType, SewError},
3    geometry::{CoordsFloat, Vertex2},
4    stm::{Transaction, TransactionClosureResult, retry, try_or_coerce},
5};
6
7use crate::utils::{EdgeAnchor, FaceAnchor, VertexAnchor};
8
9/// Cut an edge in half and build triangles from the new vertex.
10///
11/// This function takes an edge of the map's boundary as argument, cut it in half, and build two
12/// triangles from the new vertex.
13///
14/// ```text
15///
16///       +                   +
17///      / \                 /|\
18///     /   \               / | \
19///    /     \     -->     /  |  \
20///   /       \           /   |   \
21///  /         \         /    |    \
22/// +-----------+       +-----+-----+
23///       e
24///
25/// ```
26///
27/// This function expects to operate on a triangular mesh. At the moment, calling it on another type
28/// of mesh may result in non-explicit errors (e.g. an internal sew operation will consistently fail
29/// due to a dart being non-free) as there is no check on the face's degree.
30///
31/// # Arguments
32///
33/// - `t: &mut Transaction` -- Associated transaction.
34/// - `map: &mut CMap2` -- Edited map.
35/// - `e: EdgeIdType` -- Edge to cut.
36/// - `[nd1, nd2, nd3]: [DartIdType; 3]` -- Free darts used to create the new edges.
37///
38/// # Errors
39///
40/// This function will abort and raise an error if:
41/// - the transaction cannot be completed,
42/// - one of the edge's vertex has no associated coordinates value,
43/// - one internal sew operation fails.
44///
45/// The returned error can be used in conjunction with transaction control to avoid any
46/// modifications in case of failure at attribute level. The user can then choose to retry or
47/// abort as he wishes using `Transaction::with_control_and_err`.
48#[inline]
49pub fn cut_outer_edge<T: CoordsFloat>(
50    t: &mut Transaction,
51    map: &CMap2<T>,
52    e: EdgeIdType,
53    [nd1, nd2, nd3]: [DartIdType; 3],
54) -> TransactionClosureResult<(), SewError> {
55    // unfallible
56    try_or_coerce!(map.link::<2>(t, nd1, nd2), SewError);
57    try_or_coerce!(map.link::<1>(t, nd2, nd3), SewError);
58
59    let f_anchor = if map.contains_attribute::<FaceAnchor>() {
60        let fid = map.face_id_tx(t, e)?;
61        map.remove_attribute::<FaceAnchor>(t, fid)?
62    } else {
63        None
64    };
65    let e_anchor = if map.contains_attribute::<EdgeAnchor>() {
66        map.read_attribute::<EdgeAnchor>(t, e)?
67    } else {
68        None
69    };
70
71    let ld = e as DartIdType;
72    let (b0ld, b1ld) = (map.beta_tx::<0>(t, ld)?, map.beta_tx::<1>(t, ld)?);
73
74    let (vid1, vid2) = (map.vertex_id_tx(t, ld)?, map.vertex_id_tx(t, b1ld)?);
75    let new_v = match (map.read_vertex(t, vid1)?, map.read_vertex(t, vid2)?) {
76        (Some(v1), Some(v2)) => Vertex2::average(&v1, &v2),
77        _ => retry()?,
78    };
79    map.write_vertex(t, nd1, new_v)?;
80
81    map.unsew::<1>(t, ld)?;
82    map.unsew::<1>(t, b1ld)?;
83
84    map.sew::<1>(t, ld, nd1)?;
85    map.sew::<1>(t, nd1, b0ld)?;
86    map.sew::<1>(t, nd3, b1ld)?;
87    map.sew::<1>(t, b1ld, nd2)?;
88
89    // FIXME: expose a split method for `CMap2` to automatically handle faces?
90    if let Some(a) = f_anchor {
91        let fid1 = map.face_id_tx(t, nd1)?;
92        let fid2 = map.face_id_tx(t, nd2)?;
93        map.write_attribute(t, fid1, a)?;
94        map.write_attribute(t, fid2, a)?;
95        if map.contains_attribute::<EdgeAnchor>() {
96            let eid = map.edge_id_tx(t, nd1)?;
97            map.write_attribute(t, eid, EdgeAnchor::from(a))?;
98        }
99    }
100    if let Some(a) = e_anchor {
101        let vid = map.vertex_id_tx(t, nd1)?;
102        map.write_attribute(t, vid, VertexAnchor::from(a))?;
103        map.write_attribute(t, nd3 as EdgeIdType, a)?;
104    }
105
106    Ok(())
107}
108
109/// Cut an edge in half and build triangles from the new vertex.
110///
111/// This function takes an edge of the map's as argument, cut it in half, and build four triangles
112/// from the new vertex.
113///
114/// ```text
115///
116///       +                   +
117///      / \                 /|\
118///     /   \               / | \
119///    /     \             /  |  \
120///   /       \           /   |   \
121///  /         \         /    |    \
122/// +-----------+  -->  +-----+-----+
123///  \    e    /         \    |    /
124///   \       /           \   |   /
125///    \     /             \  |  /
126///     \   /               \ | /
127///      \ /                 \|/
128///       +                   +
129///
130/// ```
131///
132/// This function expects to operate on a triangular mesh. At the moment, calling it on another type
133/// of mesh may result in non-explicit errors (e.g. an internal sew operation will consistently fail
134/// due to a dart being non-free) as there is no check on each faces' degree.
135///
136/// # Arguments
137///
138/// - `t: &mut Transaction` -- Associated transaction.
139/// - `map: &mut CMap2` -- Edited map.
140/// - `e: EdgeIdType` -- Edge to cut.
141/// - `[nd1, nd2, nd3, nd4, nd5, nd6]: [DartIdType; 6]` -- Free darts used to create the new edges.
142///
143/// # Errors
144///
145/// This function will abort and raise an error if:
146/// - the transaction cannot be completed,
147/// - one of the edge's vertex has no associated coordinates value,
148/// - one internal sew operation fails.
149///
150/// The returned error can be used in conjunction with transaction control to avoid any
151/// modifications in case of failure at attribute level. The user can then choose to retry or
152/// abort as he wishes using `Transaction::with_control_and_err`.
153#[inline]
154pub fn cut_inner_edge<T: CoordsFloat>(
155    t: &mut Transaction,
156    map: &CMap2<T>,
157    e: EdgeIdType,
158    [nd1, nd2, nd3, nd4, nd5, nd6]: [DartIdType; 6],
159) -> TransactionClosureResult<(), SewError> {
160    // unfallible
161    try_or_coerce!(map.link::<2>(t, nd1, nd2), SewError);
162    try_or_coerce!(map.link::<1>(t, nd2, nd3), SewError);
163    try_or_coerce!(map.link::<2>(t, nd4, nd5), SewError);
164    try_or_coerce!(map.link::<1>(t, nd5, nd6), SewError);
165
166    let (ld, rd) = (e as DartIdType, map.beta_tx::<2>(t, e as DartIdType)?);
167
168    let lf_anchor = if map.contains_attribute::<FaceAnchor>() {
169        let fid = map.face_id_tx(t, ld)?;
170        map.remove_attribute::<FaceAnchor>(t, fid)?
171    } else {
172        None
173    };
174    if let Some(a) = lf_anchor {
175        if map.contains_attribute::<EdgeAnchor>() {
176            let eid = map.edge_id_tx(t, nd1)?;
177            map.write_attribute(t, eid, EdgeAnchor::from(a))?;
178        }
179    }
180    let rf_anchor = if map.contains_attribute::<FaceAnchor>() {
181        let fid = map.face_id_tx(t, rd)?;
182        map.remove_attribute::<FaceAnchor>(t, fid)?
183    } else {
184        None
185    };
186    if let Some(a) = rf_anchor {
187        if map.contains_attribute::<EdgeAnchor>() {
188            let eid = map.edge_id_tx(t, nd4)?;
189            map.write_attribute(t, eid, EdgeAnchor::from(a))?;
190        }
191    }
192    if map.contains_attribute::<EdgeAnchor>() {
193        if let Some(a) = map.read_attribute::<EdgeAnchor>(t, e)? {
194            let vid1 = map.vertex_id_tx(t, nd1)?;
195            let vid2 = map.vertex_id_tx(t, nd4)?;
196            map.write_attribute(t, vid1, VertexAnchor::from(a))?;
197            map.write_attribute(t, vid2, VertexAnchor::from(a))?;
198        }
199    }
200
201    let (b0ld, b1ld) = (map.beta_tx::<0>(t, ld)?, map.beta_tx::<1>(t, ld)?);
202    let (b0rd, b1rd) = (map.beta_tx::<0>(t, rd)?, map.beta_tx::<1>(t, rd)?);
203
204    let (vid1, vid2) = (map.vertex_id_tx(t, ld)?, map.vertex_id_tx(t, b1ld)?);
205    let new_v = match (map.read_vertex(t, vid1)?, map.read_vertex(t, vid2)?) {
206        (Some(v1), Some(v2)) => Vertex2::average(&v1, &v2),
207        _ => retry()?,
208    };
209    map.write_vertex(t, nd1, new_v)?;
210
211    map.unsew::<2>(t, ld)?;
212    map.unsew::<1>(t, ld)?;
213    map.unsew::<1>(t, b1ld)?;
214    map.unsew::<1>(t, rd)?;
215    map.unsew::<1>(t, b1rd)?;
216
217    map.sew::<2>(t, ld, nd6)?;
218    map.sew::<2>(t, rd, nd3)?;
219
220    map.sew::<1>(t, ld, nd1)?;
221    map.sew::<1>(t, nd1, b0ld)?;
222    map.sew::<1>(t, nd3, b1ld)?;
223    map.sew::<1>(t, b1ld, nd2)?;
224
225    map.sew::<1>(t, rd, nd4)?;
226    map.sew::<1>(t, nd4, b0rd)?;
227    map.sew::<1>(t, nd6, b1rd)?;
228    map.sew::<1>(t, b1rd, nd5)?;
229
230    // TODO: expose a split method for `CMap2` to automatically handle faces?
231    if let Some(a) = lf_anchor {
232        let fid1 = map.face_id_tx(t, nd1)?;
233        let fid2 = map.face_id_tx(t, nd2)?;
234        map.write_attribute(t, fid1, a)?;
235        map.write_attribute(t, fid2, a)?;
236    }
237    if let Some(a) = rf_anchor {
238        let fid4 = map.face_id_tx(t, nd4)?;
239        let fid5 = map.face_id_tx(t, nd5)?;
240        map.write_attribute(t, fid4, a)?;
241        map.write_attribute(t, fid5, a)?;
242    }
243
244    Ok(())
245}