1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! 3D link implementations
use crate::cmap::{CMap3, DartIdType, LinkError, NULL_DART_ID};
use crate::geometry::CoordsFloat;
use crate::stm::{Transaction, TransactionClosureResult, abort};
/// 3-links
impl<T: CoordsFloat> CMap3<T> {
/// 3-link operation.
pub(crate) fn three_link_tx(
&self,
t: &mut Transaction,
ld: DartIdType,
rd: DartIdType,
) -> TransactionClosureResult<(), LinkError> {
self.betas.three_link_core(t, ld, rd)?;
let (mut lside, mut rside) = (self.beta_tx::<1>(t, ld)?, self.beta_tx::<0>(t, rd)?);
// while we haven't completed the loop, or reached an end
while lside != ld && lside != NULL_DART_ID {
if rside == NULL_DART_ID {
// (*)
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
self.betas.three_link_core(t, lside, rside)?;
(lside, rside) = (self.beta_tx::<1>(t, lside)?, self.beta_tx::<0>(t, rside)?);
}
// the face was open, so we need to cover the other direction
// for meshes, we should be working on complete faces at all times,
// so branch prediction will hopefully save use
if lside == NULL_DART_ID {
if rside != NULL_DART_ID {
// (*)
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
(lside, rside) = (self.beta_tx::<0>(t, ld)?, self.beta_tx::<1>(t, rd)?);
while lside != NULL_DART_ID {
if rside == NULL_DART_ID {
// (*)
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
self.betas.three_link_core(t, lside, rside)?;
(lside, rside) = (self.beta_tx::<0>(t, lside)?, self.beta_tx::<1>(t, rside)?);
}
}
// (*): if we land on NULL on one side, the other side should be NULL as well
// if that is not the case, it means (either):
// - we're trying to sew open faces with a different number of darts
// - we're trying to sew open faces that are offset by one (or more) dart(s)
// in both case, this is way too clunky to be considered valid
Ok(())
}
}
/// 3-unlinks
impl<T: CoordsFloat> CMap3<T> {
/// 3-unlink operation.
pub(crate) fn three_unlink_tx(
&self,
t: &mut Transaction,
ld: DartIdType,
) -> TransactionClosureResult<(), LinkError> {
let rd = self.beta_tx::<3>(t, ld)?;
self.betas.three_unlink_core(t, ld)?;
let (mut lside, mut rside) = (self.beta_tx::<1>(t, ld)?, self.beta_tx::<0>(t, rd)?);
// while we haven't completed the loop, or reached an end
while lside != ld && lside != NULL_DART_ID {
if lside != self.beta_tx::<3>(t, rside)? {
// (*); FIXME: add dedicated err ~LinkError::DivergentStructures ?
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
self.betas.three_unlink_core(t, lside)?;
(lside, rside) = (self.beta_tx::<1>(t, lside)?, self.beta_tx::<0>(t, rside)?);
}
// the face was open, so we need to cover the other direction
// for meshes, we should be working on complete faces at all times,
// so branch prediction will hopefully save use
if lside == NULL_DART_ID {
if rside != NULL_DART_ID {
// (**)
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
(lside, rside) = (self.beta_tx::<0>(t, ld)?, self.beta_tx::<1>(t, rd)?);
while lside != NULL_DART_ID {
if lside != self.beta_tx::<3>(t, rside)? {
// (*); FIXME: add dedicated err ~LinkError::DivergentStructures ?
abort(LinkError::AsymmetricalFaces(ld, rd))?;
}
assert_eq!(lside, self.beta_tx::<3>(t, rside)?); // (*)
self.betas.three_unlink_core(t, lside)?;
(lside, rside) = (self.beta_tx::<0>(t, lside)?, self.beta_tx::<1>(t, rside)?);
}
}
// (*) : this can be changed, but the idea here is to ensure we're unlinking the expected
// construct
// (**): if we land on NULL on one side, the other side should be NULL as well
Ok(())
}
}