honeycomb_kernels/remeshing/
anchoring.rs

1//! geometrical anchoring code
2
3use honeycomb_core::{
4    attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate},
5    cmap::{EdgeIdType, FaceIdType, OrbitPolicy, VertexIdType},
6};
7
8/// Geometrical 0-cell identifier type.
9pub type NodeIdType = u32;
10/// Geometrical 1-cell identifier type.
11pub type CurveIdType = u32;
12/// Geometrical 2-cell identifier type.
13pub type SurfaceIdType = u32;
14/// Geometrical 3-cell identifier type.
15pub type BodyIdType = u32;
16
17// --- Vertex anchors
18
19/// Geometrical mesh anchor.
20///
21/// This enum is used as an attribute to link mesh vertices to entities of the represented geometry.
22///
23/// The `AttributeUpdate` implementation is used to enforce the dimensional conditions required to
24/// merge two anchors. The merge-ability of two anchors also depends on their intersection; we
25/// expect this to be handled outside of the merge functor, as doing it inside would require leaking
26/// map data into the trait's methods.
27#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
28pub enum VertexAnchor {
29    /// Vertex is linked to a node.
30    Node(NodeIdType),
31    /// Vertex is linked to a curve.
32    Curve(CurveIdType),
33    /// Vertex is linked to a surface.
34    Surface(SurfaceIdType),
35    /// Vertex is linked to a 3D body.
36    Body(BodyIdType),
37}
38
39impl VertexAnchor {
40    /// Return the dimension of the associated anchor.
41    #[must_use = "unused return value"]
42    pub const fn anchor_dim(&self) -> u8 {
43        match self {
44            Self::Node(_) => 0,
45            Self::Curve(_) => 1,
46            Self::Surface(_) => 2,
47            Self::Body(_) => 3,
48        }
49    }
50}
51
52impl AttributeBind for VertexAnchor {
53    type StorageType = AttrSparseVec<Self>;
54    type IdentifierType = VertexIdType;
55    const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
56}
57
58impl AttributeUpdate for VertexAnchor {
59    fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
60        match (attr1, attr2) {
61            (Self::Node(id1), Self::Node(id2)) => {
62                if id1 == id2 {
63                    Ok(Self::Node(id1))
64                } else {
65                    Err(AttributeError::FailedMerge(
66                        std::any::type_name::<Self>(),
67                        "anchors have the same dimension but different IDs",
68                    ))
69                }
70            }
71            (Self::Node(id), _) | (_, Self::Node(id)) => Ok(Self::Node(id)),
72            (Self::Curve(id1), Self::Curve(id2)) => {
73                if id1 == id2 {
74                    Ok(Self::Curve(id1))
75                } else {
76                    Err(AttributeError::FailedMerge(
77                        std::any::type_name::<Self>(),
78                        "anchors have the same dimension but different IDs",
79                    ))
80                }
81            }
82            (Self::Curve(id), _) | (_, Self::Curve(id)) => Ok(Self::Curve(id)),
83            (Self::Surface(id1), Self::Surface(id2)) => {
84                if id1 == id2 {
85                    Ok(Self::Surface(id1))
86                } else {
87                    Err(AttributeError::FailedMerge(
88                        std::any::type_name::<Self>(),
89                        "anchors have the same dimension but different IDs",
90                    ))
91                }
92            }
93            (Self::Surface(id), _) | (_, Self::Surface(id)) => Ok(Self::Surface(id)),
94            (Self::Body(id1), Self::Body(id2)) => {
95                if id1 == id2 {
96                    Ok(Self::Body(id1))
97                } else {
98                    Err(AttributeError::FailedMerge(
99                        std::any::type_name::<Self>(),
100                        "anchors have the same dimension but different IDs",
101                    ))
102                }
103            }
104        }
105    }
106
107    fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
108        Ok((attr, attr))
109    }
110
111    fn merge_incomplete(val: Self) -> Result<Self, AttributeError> {
112        Ok(val)
113    }
114}
115
116impl From<EdgeAnchor> for VertexAnchor {
117    fn from(value: EdgeAnchor) -> Self {
118        match value {
119            EdgeAnchor::Curve(i) => VertexAnchor::Curve(i),
120            EdgeAnchor::Surface(i) => VertexAnchor::Surface(i),
121            EdgeAnchor::Body(i) => VertexAnchor::Body(i),
122        }
123    }
124}
125
126impl From<FaceAnchor> for VertexAnchor {
127    fn from(value: FaceAnchor) -> Self {
128        match value {
129            FaceAnchor::Surface(i) => VertexAnchor::Surface(i),
130            FaceAnchor::Body(i) => VertexAnchor::Body(i),
131        }
132    }
133}
134
135// --- Edge anchors
136
137/// Geometrical mesh anchor.
138///
139/// This enum is used as an attribute to link mesh edges to entities of the represented geometry..
140///
141/// The `AttributeUpdate` implementation is used to enforce the dimensional conditions required to
142/// merge two anchors. The merge-ability of two anchors also depends on their intersection; we
143/// expect this to be handled outside of the merge functor, as doing it inside would require leaking
144/// map data into the trait's methods.
145#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
146pub enum EdgeAnchor {
147    /// Vertex is linked to a curve.
148    Curve(CurveIdType),
149    /// Vertex is linked to a surface.
150    Surface(SurfaceIdType),
151    /// Vertex is linked to a 3D body.
152    Body(BodyIdType),
153}
154
155impl EdgeAnchor {
156    /// Return the dimension of the associated anchor.
157    #[must_use = "unused return value"]
158    pub const fn anchor_dim(&self) -> u8 {
159        match self {
160            Self::Curve(_) => 1,
161            Self::Surface(_) => 2,
162            Self::Body(_) => 3,
163        }
164    }
165}
166
167impl AttributeBind for EdgeAnchor {
168    type StorageType = AttrSparseVec<Self>;
169    type IdentifierType = EdgeIdType;
170    const BIND_POLICY: OrbitPolicy = OrbitPolicy::Edge;
171}
172
173impl AttributeUpdate for EdgeAnchor {
174    fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
175        match (attr1, attr2) {
176            (Self::Curve(id1), Self::Curve(id2)) => {
177                if id1 == id2 {
178                    Ok(Self::Curve(id1))
179                } else {
180                    Err(AttributeError::FailedMerge(
181                        std::any::type_name::<Self>(),
182                        "anchors have the same dimension but different IDs",
183                    ))
184                }
185            }
186            (Self::Curve(id), _) | (_, Self::Curve(id)) => Ok(Self::Curve(id)),
187            (Self::Surface(id1), Self::Surface(id2)) => {
188                if id1 == id2 {
189                    Ok(Self::Surface(id1))
190                } else {
191                    Err(AttributeError::FailedMerge(
192                        std::any::type_name::<Self>(),
193                        "anchors have the same dimension but different IDs",
194                    ))
195                }
196            }
197            (Self::Surface(id), _) | (_, Self::Surface(id)) => Ok(Self::Surface(id)),
198            (Self::Body(id1), Self::Body(id2)) => {
199                if id1 == id2 {
200                    Ok(Self::Body(id1))
201                } else {
202                    Err(AttributeError::FailedMerge(
203                        std::any::type_name::<Self>(),
204                        "anchors have the same dimension but different IDs",
205                    ))
206                }
207            }
208        }
209    }
210
211    fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
212        Ok((attr, attr))
213    }
214
215    fn merge_incomplete(val: Self) -> Result<Self, AttributeError> {
216        Ok(val)
217    }
218}
219
220impl From<FaceAnchor> for EdgeAnchor {
221    fn from(value: FaceAnchor) -> Self {
222        match value {
223            FaceAnchor::Surface(i) => EdgeAnchor::Surface(i),
224            FaceAnchor::Body(i) => EdgeAnchor::Body(i),
225        }
226    }
227}
228
229// --- Face anchors
230
231/// Geometrical mesh anchor.
232///
233/// This enum is used as an attribute to link mesh faces to entities of the represented geometry..
234///
235/// The `AttributeUpdate` implementation is used to enforce the dimensional conditions required to
236/// merge two anchors. The merge-ability of two anchors also depends on their intersection; we
237/// expect this to be handled outside of the merge functor, as doing it inside would require leaking
238/// map data into the trait's methods.
239#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
240pub enum FaceAnchor {
241    /// Vertex is linked to a surface.
242    Surface(SurfaceIdType),
243    /// Vertex is linked to a 3D body.
244    Body(BodyIdType),
245}
246
247impl FaceAnchor {
248    /// Return the dimension of the associated anchor.
249    #[must_use = "unused return value"]
250    pub const fn anchor_dim(&self) -> u8 {
251        match self {
252            Self::Surface(_) => 2,
253            Self::Body(_) => 3,
254        }
255    }
256}
257
258impl AttributeBind for FaceAnchor {
259    type StorageType = AttrSparseVec<Self>;
260    type IdentifierType = FaceIdType;
261    const BIND_POLICY: OrbitPolicy = OrbitPolicy::Face;
262}
263
264impl AttributeUpdate for FaceAnchor {
265    fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
266        match (attr1, attr2) {
267            (Self::Surface(id1), Self::Surface(id2)) => {
268                if id1 == id2 {
269                    Ok(Self::Surface(id1))
270                } else {
271                    Err(AttributeError::FailedMerge(
272                        std::any::type_name::<Self>(),
273                        "anchors have the same dimension but different IDs",
274                    ))
275                }
276            }
277            (Self::Surface(id), _) | (_, Self::Surface(id)) => Ok(Self::Surface(id)),
278            (Self::Body(id1), Self::Body(id2)) => {
279                if id1 == id2 {
280                    Ok(Self::Body(id1))
281                } else {
282                    Err(AttributeError::FailedMerge(
283                        std::any::type_name::<Self>(),
284                        "anchors have the same dimension but different IDs",
285                    ))
286                }
287            }
288        }
289    }
290
291    fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
292        Ok((attr, attr))
293    }
294
295    fn merge_incomplete(val: Self) -> Result<Self, AttributeError> {
296        Ok(val)
297    }
298}