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