honeycomb_kernels/remeshing/
relaxation.rs

1use honeycomb_core::{
2    cmap::{CMap2, VertexIdType},
3    geometry::{CoordsFloat, Vector2},
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(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(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(t, vid, p + delta)?;
97
98    Ok(())
99}