parry3d/shape/
feature_id.rs

1#[cfg(feature = "rkyv")]
2use rkyv::{bytecheck, CheckBytes};
3
4/// An identifier of a feature of a convex polyhedron.
5///
6/// This identifier is shape-dependent and is such that it
7/// allows an efficient retrieval of the geometric information of the
8/// feature.
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[cfg_attr(
11    feature = "rkyv",
12    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
13    archive(as = "Self")
14)]
15#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
16pub enum FeatureId {
17    /// Shape-dependent identifier of a vertex.
18    Vertex(u32),
19    #[cfg(feature = "dim3")]
20    /// Shape-dependent identifier of an edge.
21    Edge(u32),
22    /// Shape-dependent identifier of a face.
23    Face(u32),
24    // XXX: remove this variant.
25    /// Unknown identifier.
26    #[default]
27    Unknown,
28}
29
30impl FeatureId {
31    /// Revries the value of the identifier if `self` is a vertex.
32    pub fn unwrap_vertex(self) -> u32 {
33        match self {
34            FeatureId::Vertex(id) => id,
35            _ => panic!("The feature id does not identify a vertex."),
36        }
37    }
38
39    /// Revries the value of the identifier if `self` is an edge.
40    #[cfg(feature = "dim3")]
41    pub fn unwrap_edge(self) -> u32 {
42        match self {
43            FeatureId::Edge(id) => id,
44            _ => panic!("The feature id does not identify an edge."),
45        }
46    }
47
48    /// Retrieves the value of the identifier if `self` is a face.
49    pub fn unwrap_face(self) -> u32 {
50        match self {
51            FeatureId::Face(id) => id,
52            _ => panic!("The feature id does not identify a face."),
53        }
54    }
55}
56
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58#[cfg_attr(
59    feature = "rkyv",
60    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
61    archive(as = "Self")
62)]
63#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
64/// A feature id where the feature type is packed into the same value as the feature index.
65pub struct PackedFeatureId(pub u32);
66
67impl PackedFeatureId {
68    /// Packed feature id identifying an unknown feature.
69    pub const UNKNOWN: Self = Self(0);
70
71    const CODE_MASK: u32 = 0x3fff_ffff;
72    const HEADER_MASK: u32 = !Self::CODE_MASK;
73    const HEADER_VERTEX: u32 = 0b01 << 30;
74    #[cfg(feature = "dim3")]
75    const HEADER_EDGE: u32 = 0b10 << 30;
76    const HEADER_FACE: u32 = 0b11 << 30;
77
78    /// Converts a vertex feature id into a packed feature id.
79    pub fn vertex(code: u32) -> Self {
80        assert_eq!(code & Self::HEADER_MASK, 0);
81        Self(Self::HEADER_VERTEX | code)
82    }
83
84    /// Converts a edge feature id into a packed feature id.
85    #[cfg(feature = "dim3")]
86    pub fn edge(code: u32) -> Self {
87        assert_eq!(code & Self::HEADER_MASK, 0);
88        Self(Self::HEADER_EDGE | code)
89    }
90
91    /// Converts a face feature id into a packed feature id.
92    pub fn face(code: u32) -> Self {
93        assert_eq!(code & Self::HEADER_MASK, 0);
94        Self(Self::HEADER_FACE | code)
95    }
96
97    #[cfg(feature = "dim2")]
98    /// Converts an array of vertex feature ids into an array of packed feature ids.
99    pub(crate) fn vertices(code: [u32; 2]) -> [Self; 2] {
100        [Self::vertex(code[0]), Self::vertex(code[1])]
101    }
102
103    #[cfg(feature = "dim3")]
104    /// Converts an array of vertex feature ids into an array of packed feature ids.
105    pub(crate) fn vertices(code: [u32; 4]) -> [Self; 4] {
106        [
107            Self::vertex(code[0]),
108            Self::vertex(code[1]),
109            Self::vertex(code[2]),
110            Self::vertex(code[3]),
111        ]
112    }
113
114    #[cfg(feature = "dim3")]
115    /// Converts an array of edge feature ids into an array of packed feature ids.
116    pub(crate) fn edges(code: [u32; 4]) -> [Self; 4] {
117        [
118            Self::edge(code[0]),
119            Self::edge(code[1]),
120            Self::edge(code[2]),
121            Self::edge(code[3]),
122        ]
123    }
124
125    /// Unpacks this feature id into an explicit enum.
126    pub fn unpack(self) -> FeatureId {
127        let header = self.0 & Self::HEADER_MASK;
128        let code = self.0 & Self::CODE_MASK;
129        match header {
130            Self::HEADER_VERTEX => FeatureId::Vertex(code),
131            #[cfg(feature = "dim3")]
132            Self::HEADER_EDGE => FeatureId::Edge(code),
133            Self::HEADER_FACE => FeatureId::Face(code),
134            _ => FeatureId::Unknown,
135        }
136    }
137
138    /// Is the identified feature a face?
139    pub fn is_face(self) -> bool {
140        self.0 & Self::HEADER_MASK == Self::HEADER_FACE
141    }
142
143    /// Is the identified feature a vertex?
144    pub fn is_vertex(self) -> bool {
145        self.0 & Self::HEADER_MASK == Self::HEADER_VERTEX
146    }
147
148    /// Is the identified feature an edge?
149    #[cfg(feature = "dim3")]
150    pub fn is_edge(self) -> bool {
151        self.0 & Self::HEADER_MASK == Self::HEADER_EDGE
152    }
153
154    /// Is the identified feature unknown?
155    pub fn is_unknown(self) -> bool {
156        self == Self::UNKNOWN
157    }
158}
159
160impl From<FeatureId> for PackedFeatureId {
161    fn from(value: FeatureId) -> Self {
162        match value {
163            FeatureId::Face(fid) => Self::face(fid),
164            #[cfg(feature = "dim3")]
165            FeatureId::Edge(fid) => Self::edge(fid),
166            FeatureId::Vertex(fid) => Self::vertex(fid),
167            FeatureId::Unknown => Self::UNKNOWN,
168        }
169    }
170}