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}