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