parry2d/shape/feature_id.rs
1#[cfg(feature = "rkyv")]
2use rkyv::{bytecheck, CheckBytes};
3
4/// An identifier of a geometric feature (vertex, edge, or face) of a shape.
5///
6/// Feature IDs are used throughout Parry to identify specific geometric features on shapes
7/// during collision detection, contact generation, and other geometric queries. They allow
8/// algorithms to track which parts of shapes are interacting, which is essential for:
9///
10/// - **Contact manifold generation**: Tracking persistent contact points between frames
11/// - **Collision response**: Determining which features are colliding
12/// - **Debug visualization**: Highlighting specific geometric elements
13/// - **Feature-based queries**: Retrieving geometric data for specific shape features
14///
15/// # Feature Types
16///
17/// - **Vertex**: A corner point of the shape (0-dimensional feature)
18/// - **Edge**: A line segment connecting two vertices (1-dimensional feature, 3D only)
19/// - **Face**: A flat surface bounded by edges (2-dimensional feature)
20/// - **Unknown**: Used when the feature type cannot be determined or is not applicable
21///
22/// # Shape-Specific Identifiers
23///
24/// The numeric ID within each feature type is shape-dependent. For example:
25/// - For a cuboid, vertex IDs might range from 0-7 (8 corners)
26/// - For a triangle, face ID 0 typically refers to the triangle itself
27/// - For composite shapes, IDs might encode both the sub-shape and the feature within it
28///
29/// The exact meaning of these IDs depends on the shape's internal representation, but they
30/// are guaranteed to allow efficient retrieval of the feature's geometric information.
31///
32/// # Examples
33///
34/// Basic usage of feature IDs in 2D:
35///
36/// ```
37/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
38/// use parry2d::shape::FeatureId;
39///
40/// // Create a vertex feature identifier
41/// let vertex_id = FeatureId::Vertex(5);
42/// assert_eq!(vertex_id.unwrap_vertex(), 5);
43///
44/// // Create a face feature identifier (in 2D, faces are edges of the polygon)
45/// let face_id = FeatureId::Face(2);
46/// assert_eq!(face_id.unwrap_face(), 2);
47///
48/// // Unknown feature (used as default)
49/// let unknown = FeatureId::Unknown;
50/// assert_eq!(unknown, FeatureId::default());
51/// # }
52/// ```
53///
54/// Basic usage of feature IDs in 3D:
55///
56/// ```
57/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
58/// use parry3d::shape::FeatureId;
59///
60/// // Create a vertex feature identifier
61/// let vertex_id = FeatureId::Vertex(5);
62/// assert_eq!(vertex_id.unwrap_vertex(), 5);
63///
64/// // Create an edge feature identifier (only available in 3D)
65/// let edge_id = FeatureId::Edge(3);
66/// assert_eq!(edge_id.unwrap_edge(), 3);
67///
68/// // Create a face feature identifier
69/// let face_id = FeatureId::Face(2);
70/// assert_eq!(face_id.unwrap_face(), 2);
71///
72/// // Unknown feature (used as default)
73/// let unknown = FeatureId::Unknown;
74/// assert_eq!(unknown, FeatureId::default());
75/// # }
76/// ```
77///
78/// Pattern matching on feature types in 3D:
79///
80/// ```
81/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
82/// use parry3d::shape::FeatureId;
83///
84/// fn describe_feature(feature: FeatureId) -> String {
85/// match feature {
86/// FeatureId::Vertex(id) => format!("Vertex #{}", id),
87/// FeatureId::Edge(id) => format!("Edge #{}", id),
88/// FeatureId::Face(id) => format!("Face #{}", id),
89/// FeatureId::Unknown => "Unknown feature".to_string(),
90/// }
91/// }
92///
93/// assert_eq!(describe_feature(FeatureId::Vertex(3)), "Vertex #3");
94/// assert_eq!(describe_feature(FeatureId::Edge(5)), "Edge #5");
95/// assert_eq!(describe_feature(FeatureId::Face(1)), "Face #1");
96/// # }
97/// ```
98///
99/// # 2D vs 3D
100///
101/// In 2D mode (`dim2` feature), the `Edge` variant is not available since edges in 2D
102/// are effectively the same as faces (line segments). In 2D:
103/// - Vertices represent corner points
104/// - Faces represent edges of the polygon
105///
106/// In 3D mode (`dim3` feature), all three types are available:
107/// - Vertices are 0D points
108/// - Edges are 1D line segments
109/// - Faces are 2D polygons
110#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
111#[cfg_attr(
112 feature = "rkyv",
113 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
114 archive(as = "Self")
115)]
116#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
117pub enum FeatureId {
118 /// Shape-dependent identifier of a vertex (0-dimensional corner point).
119 ///
120 /// The numeric ID is specific to each shape type and allows efficient lookup
121 /// of the vertex's position and other geometric properties.
122 Vertex(u32),
123 #[cfg(feature = "dim3")]
124 /// Shape-dependent identifier of an edge (1-dimensional line segment).
125 ///
126 /// Available only in 3D mode. The numeric ID is specific to each shape type
127 /// and allows efficient lookup of the edge's endpoints and direction.
128 Edge(u32),
129 /// Shape-dependent identifier of a face (2-dimensional flat surface).
130 ///
131 /// In 2D, faces represent the edges of polygons (line segments).
132 /// In 3D, faces represent polygonal surfaces. The numeric ID is specific
133 /// to each shape type and allows efficient lookup of the face's vertices,
134 /// normal vector, and other properties.
135 Face(u32),
136 // XXX: remove this variant.
137 /// Unknown or unidentified feature.
138 ///
139 /// Used as a default value or when the specific feature cannot be determined.
140 /// This variant should generally be avoided in production code.
141 #[default]
142 Unknown,
143}
144
145impl FeatureId {
146 /// Retrieves the numeric ID if this is a vertex feature.
147 ///
148 /// # Panics
149 ///
150 /// Panics if the feature is not a vertex (i.e., if it's an edge, face, or unknown).
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
156 /// use parry2d::shape::FeatureId;
157 ///
158 /// let vertex = FeatureId::Vertex(42);
159 /// assert_eq!(vertex.unwrap_vertex(), 42);
160 /// # }
161 /// ```
162 ///
163 /// This will panic:
164 ///
165 /// ```no_run
166 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
167 /// use parry2d::shape::FeatureId;
168 ///
169 /// let face = FeatureId::Face(5);
170 /// face.unwrap_vertex(); // Panics!
171 /// # }
172 /// # #[cfg(all(feature = "dim2", feature = "f64"))] {
173 /// use parry2d_f64::shape::FeatureId;
174 ///
175 /// let face = FeatureId::Face(5);
176 /// face.unwrap_vertex(); // Panics!
177 /// # }
178 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
179 /// use parry3d::shape::FeatureId;
180 ///
181 /// let face = FeatureId::Face(5);
182 /// face.unwrap_vertex(); // Panics!
183 /// # }
184 /// # #[cfg(all(feature = "dim3", feature = "f64"))] {
185 /// use parry3d_f64::shape::FeatureId;
186 ///
187 /// let face = FeatureId::Face(5);
188 /// face.unwrap_vertex(); // Panics!
189 /// # }
190 /// ```
191 pub fn unwrap_vertex(self) -> u32 {
192 match self {
193 FeatureId::Vertex(id) => id,
194 _ => panic!("The feature id does not identify a vertex."),
195 }
196 }
197
198 /// Retrieves the numeric ID if this is an edge feature.
199 ///
200 /// Available only in 3D mode (`dim3` feature).
201 ///
202 /// # Panics
203 ///
204 /// Panics if the feature is not an edge (i.e., if it's a vertex, face, or unknown).
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
210 /// use parry3d::shape::FeatureId;
211 ///
212 /// let edge = FeatureId::Edge(7);
213 /// assert_eq!(edge.unwrap_edge(), 7);
214 /// # }
215 /// ```
216 ///
217 /// This will panic:
218 ///
219 /// ```no_run
220 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
221 /// use parry3d::shape::FeatureId;
222 ///
223 /// let vertex = FeatureId::Vertex(3);
224 /// vertex.unwrap_edge(); // Panics!
225 /// # }
226 /// ```
227 #[cfg(feature = "dim3")]
228 pub fn unwrap_edge(self) -> u32 {
229 match self {
230 FeatureId::Edge(id) => id,
231 _ => panic!("The feature id does not identify an edge."),
232 }
233 }
234
235 /// Retrieves the numeric ID if this is a face feature.
236 ///
237 /// # Panics
238 ///
239 /// Panics if the feature is not a face (i.e., if it's a vertex, edge, or unknown).
240 ///
241 /// # Examples
242 ///
243 /// ```
244 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
245 /// use parry2d::shape::FeatureId;
246 ///
247 /// let face = FeatureId::Face(12);
248 /// assert_eq!(face.unwrap_face(), 12);
249 /// # }
250 /// ```
251 ///
252 /// This will panic:
253 ///
254 /// ```should_panic
255 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
256 /// use parry2d::shape::FeatureId;
257 ///
258 /// let vertex = FeatureId::Vertex(0);
259 /// vertex.unwrap_face(); // Panics!
260 /// # }
261 /// # #[cfg(all(feature = "dim2", feature = "f64"))] {
262 /// use parry2d_f64::shape::FeatureId;
263 ///
264 /// let vertex = FeatureId::Vertex(0);
265 /// vertex.unwrap_face(); // Panics!
266 /// # }
267 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
268 /// use parry3d::shape::FeatureId;
269 ///
270 /// let vertex = FeatureId::Vertex(0);
271 /// vertex.unwrap_face(); // Panics!
272 /// # }
273 /// # #[cfg(all(feature = "dim3", feature = "f64"))] {
274 /// use parry3d_f64::shape::FeatureId;
275 ///
276 /// let vertex = FeatureId::Vertex(0);
277 /// vertex.unwrap_face(); // Panics!
278 /// # }
279 /// ```
280 pub fn unwrap_face(self) -> u32 {
281 match self {
282 FeatureId::Face(id) => id,
283 _ => panic!("The feature id does not identify a face."),
284 }
285 }
286}
287
288/// A memory-efficient feature ID where the type and index are packed into a single `u32`.
289///
290/// `PackedFeatureId` is a space-optimized version of [`FeatureId`] that encodes both the
291/// feature type (vertex, edge, or face) and its numeric identifier in a single 32-bit value.
292/// This is particularly useful when storing large numbers of feature IDs, as it uses half
293/// the memory of a standard enum representation.
294///
295/// # Memory Layout
296///
297/// The packing scheme uses the upper 2 bits to encode the feature type, leaving 30 bits
298/// (0-1,073,741,823) for the feature index:
299///
300/// ```text
301/// ┌──┬──┬────────────────────────────────┐
302/// │31│30│29 0│
303/// ├──┴──┴────────────────────────────────┤
304/// │Type │ Feature Index │
305/// │(2b) │ (30 bits) │
306/// └─────┴────────────────────────────────┘
307///
308/// Type encoding:
309/// - 00: Unknown
310/// - 01: Vertex
311/// - 10: Edge (3D only)
312/// - 11: Face
313/// ```
314///
315/// # Use Cases
316///
317/// Use `PackedFeatureId` when:
318/// - Storing feature IDs in large data structures (e.g., contact manifolds)
319/// - Passing feature IDs across FFI boundaries where a fixed size is required
320/// - Memory usage is a concern and you have many feature IDs
321///
322/// Use regular [`FeatureId`] when:
323/// - Code clarity is more important than memory usage
324/// - You need to pattern match on feature types frequently
325/// - Working with small numbers of feature IDs
326///
327/// # Examples
328///
329/// Creating and unpacking feature IDs in 2D:
330///
331/// ```
332/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
333/// use parry2d::shape::{FeatureId, PackedFeatureId};
334///
335/// // Create a packed vertex ID
336/// let packed_vertex = PackedFeatureId::vertex(10);
337/// assert!(packed_vertex.is_vertex());
338/// assert!(!packed_vertex.is_face());
339///
340/// // Create a packed face ID
341/// let packed_face = PackedFeatureId::face(5);
342/// assert!(packed_face.is_face());
343///
344/// // Unpack to get the full enum
345/// let unpacked = packed_face.unpack();
346/// assert_eq!(unpacked, FeatureId::Face(5));
347/// # }
348/// ```
349///
350/// Creating and unpacking feature IDs in 3D:
351///
352/// ```
353/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
354/// use parry3d::shape::{FeatureId, PackedFeatureId};
355///
356/// // Create a packed vertex ID
357/// let packed_vertex = PackedFeatureId::vertex(10);
358/// assert!(packed_vertex.is_vertex());
359/// assert!(!packed_vertex.is_face());
360///
361/// // Create a packed edge ID (3D only)
362/// let packed_edge = PackedFeatureId::edge(7);
363/// assert!(packed_edge.is_edge());
364///
365/// // Create a packed face ID
366/// let packed_face = PackedFeatureId::face(5);
367/// assert!(packed_face.is_face());
368///
369/// // Unpack to get the full enum
370/// let unpacked = packed_face.unpack();
371/// assert_eq!(unpacked, FeatureId::Face(5));
372/// # }
373/// ```
374///
375/// Converting between packed and unpacked forms:
376///
377/// ```
378/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
379/// use parry2d::shape::{FeatureId, PackedFeatureId};
380///
381/// // From FeatureId to PackedFeatureId
382/// let feature = FeatureId::Vertex(42);
383/// let packed: PackedFeatureId = feature.into();
384/// assert!(packed.is_vertex());
385///
386/// // From PackedFeatureId back to FeatureId
387/// let unpacked = packed.unpack();
388/// assert_eq!(unpacked, FeatureId::Vertex(42));
389/// # }
390/// ```
391///
392/// Working with the unknown feature:
393///
394/// ```
395/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
396/// use parry2d::shape::PackedFeatureId;
397///
398/// let unknown = PackedFeatureId::UNKNOWN;
399/// assert!(unknown.is_unknown());
400/// assert!(!unknown.is_vertex());
401/// assert!(!unknown.is_face());
402/// # }
403/// ```
404///
405/// Checking feature types efficiently in 3D:
406///
407/// ```
408/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
409/// use parry3d::shape::PackedFeatureId;
410///
411/// let vertex = PackedFeatureId::vertex(100);
412/// let edge = PackedFeatureId::edge(50);
413/// let face = PackedFeatureId::face(25);
414///
415/// // Type checking is very fast (just bit masking)
416/// assert!(vertex.is_vertex());
417/// assert!(edge.is_edge());
418/// assert!(face.is_face());
419///
420/// // Different types are not equal
421/// assert_ne!(vertex, edge);
422/// assert_ne!(edge, face);
423/// # }
424/// ```
425///
426/// # Performance
427///
428/// `PackedFeatureId` provides several performance benefits:
429/// - **Memory**: Uses 4 bytes vs 8 bytes for `FeatureId` (on 64-bit systems)
430/// - **Cache efficiency**: Better cache utilization when storing many IDs
431/// - **Type checking**: Very fast (single bitwise AND operation)
432/// - **Conversion**: Converting to/from `FeatureId` is essentially free
433///
434/// # Limitations
435///
436/// The packing scheme limits feature indices to 30 bits (max value: 1,073,741,823).
437/// Attempting to create a packed feature ID with a larger index will panic in debug
438/// mode due to the assertion checks in the constructor methods.
439#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
440#[cfg_attr(
441 feature = "rkyv",
442 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
443 archive(as = "Self")
444)]
445#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
446pub struct PackedFeatureId(pub u32);
447
448impl PackedFeatureId {
449 /// Constant representing an unknown or unidentified feature.
450 ///
451 /// This is the default value and corresponds to `FeatureId::Unknown`.
452 ///
453 /// # Examples
454 ///
455 /// ```
456 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
457 /// use parry2d::shape::{PackedFeatureId, FeatureId};
458 ///
459 /// let unknown = PackedFeatureId::UNKNOWN;
460 /// assert!(unknown.is_unknown());
461 /// assert_eq!(unknown.unpack(), FeatureId::Unknown);
462 /// # }
463 /// ```
464 pub const UNKNOWN: Self = Self(0);
465
466 const CODE_MASK: u32 = 0x3fff_ffff;
467 const HEADER_MASK: u32 = !Self::CODE_MASK;
468 const HEADER_VERTEX: u32 = 0b01 << 30;
469 #[cfg(feature = "dim3")]
470 const HEADER_EDGE: u32 = 0b10 << 30;
471 const HEADER_FACE: u32 = 0b11 << 30;
472
473 /// Creates a packed feature ID for a vertex with the given index.
474 ///
475 /// # Panics
476 ///
477 /// Panics in debug mode if `code` uses any of the upper 2 bits (i.e., if `code >= 2^30`).
478 /// The maximum valid value is 1,073,741,823 (0x3FFFFFFF).
479 ///
480 /// # Examples
481 ///
482 /// ```
483 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
484 /// use parry2d::shape::{PackedFeatureId, FeatureId};
485 ///
486 /// let packed = PackedFeatureId::vertex(5);
487 /// assert!(packed.is_vertex());
488 /// assert_eq!(packed.unpack(), FeatureId::Vertex(5));
489 /// # }
490 /// ```
491 pub fn vertex(code: u32) -> Self {
492 assert_eq!(code & Self::HEADER_MASK, 0);
493 Self(Self::HEADER_VERTEX | code)
494 }
495
496 /// Creates a packed feature ID for an edge with the given index.
497 ///
498 /// Available only in 3D mode (`dim3` feature).
499 ///
500 /// # Panics
501 ///
502 /// Panics in debug mode if `code` uses any of the upper 2 bits (i.e., if `code >= 2^30`).
503 /// The maximum valid value is 1,073,741,823 (0x3FFFFFFF).
504 ///
505 /// # Examples
506 ///
507 /// ```
508 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
509 /// use parry3d::shape::{PackedFeatureId, FeatureId};
510 ///
511 /// let packed = PackedFeatureId::edge(10);
512 /// assert!(packed.is_edge());
513 /// assert_eq!(packed.unpack(), FeatureId::Edge(10));
514 /// # }
515 /// ```
516 #[cfg(feature = "dim3")]
517 pub fn edge(code: u32) -> Self {
518 assert_eq!(code & Self::HEADER_MASK, 0);
519 Self(Self::HEADER_EDGE | code)
520 }
521
522 /// Creates a packed feature ID for a face with the given index.
523 ///
524 /// # Panics
525 ///
526 /// Panics in debug mode if `code` uses any of the upper 2 bits (i.e., if `code >= 2^30`).
527 /// The maximum valid value is 1,073,741,823 (0x3FFFFFFF).
528 ///
529 /// # Examples
530 ///
531 /// ```
532 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
533 /// use parry2d::shape::{PackedFeatureId, FeatureId};
534 ///
535 /// let packed = PackedFeatureId::face(15);
536 /// assert!(packed.is_face());
537 /// assert_eq!(packed.unpack(), FeatureId::Face(15));
538 /// # }
539 /// ```
540 pub fn face(code: u32) -> Self {
541 assert_eq!(code & Self::HEADER_MASK, 0);
542 Self(Self::HEADER_FACE | code)
543 }
544
545 #[cfg(feature = "dim2")]
546 /// Converts an array of vertex feature ids into an array of packed feature ids.
547 pub(crate) fn vertices(code: [u32; 2]) -> [Self; 2] {
548 [Self::vertex(code[0]), Self::vertex(code[1])]
549 }
550
551 #[cfg(feature = "dim3")]
552 /// Converts an array of vertex feature ids into an array of packed feature ids.
553 pub(crate) fn vertices(code: [u32; 4]) -> [Self; 4] {
554 [
555 Self::vertex(code[0]),
556 Self::vertex(code[1]),
557 Self::vertex(code[2]),
558 Self::vertex(code[3]),
559 ]
560 }
561
562 #[cfg(feature = "dim3")]
563 /// Converts an array of edge feature ids into an array of packed feature ids.
564 pub(crate) fn edges(code: [u32; 4]) -> [Self; 4] {
565 [
566 Self::edge(code[0]),
567 Self::edge(code[1]),
568 Self::edge(code[2]),
569 Self::edge(code[3]),
570 ]
571 }
572
573 /// Unpacks this feature ID into the full `FeatureId` enum.
574 ///
575 /// This converts the compact packed representation back into the explicit enum form,
576 /// allowing you to pattern match on the feature type.
577 ///
578 /// # Examples
579 ///
580 /// ```
581 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
582 /// use parry2d::shape::{FeatureId, PackedFeatureId};
583 ///
584 /// let packed = PackedFeatureId::vertex(42);
585 /// let unpacked = packed.unpack();
586 ///
587 /// match unpacked {
588 /// FeatureId::Vertex(id) => assert_eq!(id, 42),
589 /// _ => panic!("Expected a vertex!"),
590 /// }
591 /// # }
592 /// ```
593 ///
594 /// Round-trip conversion:
595 ///
596 /// ```
597 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
598 /// use parry2d::shape::{FeatureId, PackedFeatureId};
599 ///
600 /// let original = FeatureId::Face(100);
601 /// let packed: PackedFeatureId = original.into();
602 /// let unpacked = packed.unpack();
603 ///
604 /// assert_eq!(original, unpacked);
605 /// # }
606 /// ```
607 pub fn unpack(self) -> FeatureId {
608 let header = self.0 & Self::HEADER_MASK;
609 let code = self.0 & Self::CODE_MASK;
610 match header {
611 Self::HEADER_VERTEX => FeatureId::Vertex(code),
612 #[cfg(feature = "dim3")]
613 Self::HEADER_EDGE => FeatureId::Edge(code),
614 Self::HEADER_FACE => FeatureId::Face(code),
615 _ => FeatureId::Unknown,
616 }
617 }
618
619 /// Checks if this feature ID identifies a face.
620 ///
621 /// This is a very fast operation (single bitwise AND and comparison).
622 ///
623 /// # Examples
624 ///
625 /// ```
626 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
627 /// use parry2d::shape::PackedFeatureId;
628 ///
629 /// let face = PackedFeatureId::face(5);
630 /// let vertex = PackedFeatureId::vertex(5);
631 ///
632 /// assert!(face.is_face());
633 /// assert!(!vertex.is_face());
634 /// # }
635 /// ```
636 pub fn is_face(self) -> bool {
637 self.0 & Self::HEADER_MASK == Self::HEADER_FACE
638 }
639
640 /// Checks if this feature ID identifies a vertex.
641 ///
642 /// This is a very fast operation (single bitwise AND and comparison).
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
648 /// use parry2d::shape::PackedFeatureId;
649 ///
650 /// let vertex = PackedFeatureId::vertex(10);
651 /// let face = PackedFeatureId::face(10);
652 ///
653 /// assert!(vertex.is_vertex());
654 /// assert!(!face.is_vertex());
655 /// # }
656 /// ```
657 pub fn is_vertex(self) -> bool {
658 self.0 & Self::HEADER_MASK == Self::HEADER_VERTEX
659 }
660
661 /// Checks if this feature ID identifies an edge.
662 ///
663 /// Available only in 3D mode (`dim3` feature).
664 ///
665 /// This is a very fast operation (single bitwise AND and comparison).
666 ///
667 /// # Examples
668 ///
669 /// ```
670 /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
671 /// use parry3d::shape::PackedFeatureId;
672 ///
673 /// let edge = PackedFeatureId::edge(7);
674 /// let vertex = PackedFeatureId::vertex(7);
675 ///
676 /// assert!(edge.is_edge());
677 /// assert!(!vertex.is_edge());
678 /// # }
679 /// ```
680 #[cfg(feature = "dim3")]
681 pub fn is_edge(self) -> bool {
682 self.0 & Self::HEADER_MASK == Self::HEADER_EDGE
683 }
684
685 /// Checks if this feature ID is unknown.
686 ///
687 /// # Examples
688 ///
689 /// ```
690 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
691 /// use parry2d::shape::PackedFeatureId;
692 ///
693 /// let unknown = PackedFeatureId::UNKNOWN;
694 /// let vertex = PackedFeatureId::vertex(0);
695 ///
696 /// assert!(unknown.is_unknown());
697 /// assert!(!vertex.is_unknown());
698 /// # }
699 /// ```
700 pub fn is_unknown(self) -> bool {
701 self == Self::UNKNOWN
702 }
703}
704
705impl From<FeatureId> for PackedFeatureId {
706 /// Converts a `FeatureId` into its packed representation.
707 ///
708 /// This is a lossless conversion that encodes the feature type and index
709 /// into a single `u32` value.
710 ///
711 /// # Examples
712 ///
713 /// ```
714 /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
715 /// use parry2d::shape::{FeatureId, PackedFeatureId};
716 ///
717 /// // Explicit conversion
718 /// let feature = FeatureId::Vertex(123);
719 /// let packed = PackedFeatureId::from(feature);
720 /// assert!(packed.is_vertex());
721 ///
722 /// // Using Into trait
723 /// let feature = FeatureId::Face(456);
724 /// let packed: PackedFeatureId = feature.into();
725 /// assert!(packed.is_face());
726 ///
727 /// // Round-trip conversion preserves the value
728 /// let original = FeatureId::Vertex(789);
729 /// let packed: PackedFeatureId = original.into();
730 /// assert_eq!(packed.unpack(), original);
731 /// # }
732 /// ```
733 fn from(value: FeatureId) -> Self {
734 match value {
735 FeatureId::Face(fid) => Self::face(fid),
736 #[cfg(feature = "dim3")]
737 FeatureId::Edge(fid) => Self::edge(fid),
738 FeatureId::Vertex(fid) => Self::vertex(fid),
739 FeatureId::Unknown => Self::UNKNOWN,
740 }
741 }
742}