Skip to main content

honeycomb_kernels/remeshing/
relaxation.rs

1use honeycomb_core::{
2    cmap::{CMap2, CMap3, VertexIdType},
3    geometry::{CoordsFloat, Vector2, Vector3},
4    stm::{StmClosureResult, Transaction},
5};
6
7/// Move a vertex to the average of the others' values.
8///
9/// This function computes the average of a list of coordinates and assigns that value to the
10/// specified vertex.
11///
12/// # Arguments
13///
14/// - `t: &mut Transaction` -- Associated transaction.
15/// - `map: &mut CMap2` -- Edited map.
16/// - `vid: VertexIdType` -- Vertex to move.
17/// - `others: &[VertexIdType]` -- List of vertex to compute the average from.
18///
19/// # Errors
20///
21/// This function will abort and raise an error if the transaction cannot be completed.
22///
23/// # Panics
24///
25/// This function may panic if one vertex in the `others` list has no associated coordinates.
26///
27/// # Example
28///
29/// For an example of usage, see the `shift` [benchmark code][BENCH].
30///
31/// [BENCH]: https://github.com/LIHPC-Computational-Geometry/honeycomb/tree/master/benches/src
32#[inline]
33pub fn move_vertex_to_average<T: CoordsFloat>(
34    t: &mut Transaction,
35    map: &CMap2<T>,
36    vid: VertexIdType,
37    others: &[VertexIdType],
38) -> StmClosureResult<()> {
39    neighbor_based_smooth(t, map, vid, others, T::one())
40}
41
42/// Generic neighbor-based vertex smoothing function.
43///
44/// This function smooths the vertex position by moving it toward the average of its neighbors'
45/// positions weighted by lambda.
46///
47/// Note that it is up to the user to provide a correct list of neighbor IDs, and "acceptable"
48/// lambda parameter. For example:
49///
50/// - `lambda == 1` nullifies the influence of the original vertex position,
51/// - `0 < lambda < 1` results in a Laplacian smoothing.
52///
53/// # Arguments
54///
55/// - `t: &mut Transaction` -- Associated transaction.
56/// - `map: &mut CMap2` -- Edited map.
57/// - `vid: VertexIdType` -- Vertex to move.
58/// - `neighbors_id: &[VertexIdType]` -- List of vertex to compute the average from.
59/// - `lambda: T` -- Coefficient weighting the applied offset.
60///
61/// # Errors
62///
63/// This function will abort and raise an error if the transaction cannot be completed.
64///
65/// # Panics
66///
67/// This function may panic if one vertex in the `neighbors_id` list has no associated coordinates.
68#[inline]
69pub fn neighbor_based_smooth<T: CoordsFloat>(
70    t: &mut Transaction,
71    map: &CMap2<T>,
72    vid: VertexIdType,
73    neighbors_id: &[VertexIdType],
74    lambda: T,
75) -> StmClosureResult<()> {
76    let p = map
77        .read_vertex_tx(t, vid)?
78        .expect("E: no coordinates associated to vertex ID");
79
80    let n = neighbors_id.len();
81    let mut neighbors: smallvec::SmallVec<_, 16> = smallvec::SmallVec::with_capacity(n);
82    for &nid in neighbors_id {
83        neighbors.push(
84            map.read_vertex_tx(t, nid)?
85                .expect("E: no coordinates associated to vertex ID"),
86        );
87    }
88
89    let delta = neighbors
90        .into_iter()
91        .map(|v| v - p)
92        .fold(Vector2::default(), |a, b| a + b)
93        * lambda
94        / T::from(n).unwrap();
95
96    map.write_vertex_tx(t, vid, p + delta)?;
97
98    Ok(())
99}
100
101/// Move a 3-map vertex to the average of the supplied neighboring vertices.
102///
103/// # Errors
104///
105/// This function will abort and raise an error if the transaction cannot be completed.
106///
107/// # Panics
108///
109/// This function may panic if one of the vertices has no associated coordinates.
110#[inline]
111pub fn move_vertex_to_average_3d<T: CoordsFloat>(
112    t: &mut Transaction,
113    map: &CMap3<T>,
114    vid: VertexIdType,
115    others: &[VertexIdType],
116) -> StmClosureResult<()> {
117    neighbor_based_smooth_3d(t, map, vid, others, T::one())
118}
119
120/// Smooth a 3-map vertex toward the average of the supplied neighboring vertices.
121///
122/// # Errors
123///
124/// This function will abort and raise an error if the transaction cannot be completed.
125///
126/// # Panics
127///
128/// This function may panic if one of the vertices has no associated coordinates.
129#[inline]
130pub fn neighbor_based_smooth_3d<T: CoordsFloat>(
131    t: &mut Transaction,
132    map: &CMap3<T>,
133    vid: VertexIdType,
134    neighbors_id: &[VertexIdType],
135    lambda: T,
136) -> StmClosureResult<()> {
137    let p = map
138        .read_vertex_tx(t, vid)?
139        .expect("E: no coordinates associated to vertex ID");
140
141    let n = neighbors_id.len();
142    let mut neighbors: smallvec::SmallVec<_, 16> = smallvec::SmallVec::with_capacity(n);
143    for &nid in neighbors_id {
144        neighbors.push(
145            map.read_vertex_tx(t, nid)?
146                .expect("E: no coordinates associated to vertex ID"),
147        );
148    }
149
150    let delta = neighbors
151        .into_iter()
152        .map(|v| v - p)
153        .fold(Vector3::default(), |a, b| a + b)
154        * lambda
155        / T::from(n).unwrap();
156
157    map.write_vertex_tx(t, vid, p + delta)?;
158
159    Ok(())
160}
161
162#[cfg(test)]
163mod tests {
164    use honeycomb_core::{
165        cmap::{CMap3, CMapBuilder},
166        geometry::Vertex3,
167        stm::atomically,
168    };
169
170    use super::{move_vertex_to_average_3d, neighbor_based_smooth_3d};
171
172    #[test]
173    fn smooth_vertices_3d() {
174        let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build().unwrap();
175        map.set_vertex(1, Vertex3(0.0, 0.0, 0.0));
176        map.set_vertex(2, Vertex3(2.0, 0.0, 0.0));
177        map.set_vertex(3, Vertex3(0.0, 2.0, 2.0));
178
179        atomically(|transaction| move_vertex_to_average_3d(transaction, &map, 1, &[2, 3]));
180        assert_eq!(map.read_vertex(1), Some(Vertex3(1.0, 1.0, 1.0)));
181
182        map.set_vertex(1, Vertex3(0.0, 0.0, 0.0));
183        atomically(|transaction| neighbor_based_smooth_3d(transaction, &map, 1, &[2, 3], 0.5));
184        assert_eq!(map.read_vertex(1), Some(Vertex3(0.5, 0.5, 0.5)));
185    }
186}