rapier3d/geometry/
interaction_groups.rs

1#![allow(clippy::bad_bit_mask)] // Clippy will complain about the bitmasks due to Group::NONE being 0.
2
3/// Pairwise filtering using bit masks.
4///
5/// This filtering method is based on two 32-bit values:
6/// - The interaction groups memberships.
7/// - The interaction groups filter.
8///
9/// An interaction is allowed between two filters `a` and `b` when two conditions
10/// are met simultaneously:
11/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
12/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
13///
14/// In other words, interactions are allowed between two filter iff. the following condition is met:
15/// ```ignore
16/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
17/// ```
18#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
19#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
20#[repr(C)]
21pub struct InteractionGroups {
22    /// Groups memberships.
23    pub memberships: Group,
24    /// Groups filter.
25    pub filter: Group,
26}
27
28impl InteractionGroups {
29    /// Initializes with the given interaction groups and interaction mask.
30    pub const fn new(memberships: Group, filter: Group) -> Self {
31        Self {
32            memberships,
33            filter,
34        }
35    }
36
37    /// Allow interaction with everything.
38    pub const fn all() -> Self {
39        Self::new(Group::ALL, Group::ALL)
40    }
41
42    /// Prevent all interactions.
43    pub const fn none() -> Self {
44        Self::new(Group::NONE, Group::NONE)
45    }
46
47    /// Sets the group this filter is part of.
48    pub const fn with_memberships(mut self, memberships: Group) -> Self {
49        self.memberships = memberships;
50        self
51    }
52
53    /// Sets the interaction mask of this filter.
54    pub const fn with_filter(mut self, filter: Group) -> Self {
55        self.filter = filter;
56        self
57    }
58
59    /// Check if interactions should be allowed based on the interaction memberships and filter.
60    ///
61    /// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common
62    /// with the filter of `rhs`, and vice-versa.
63    #[inline]
64    pub const fn test(self, rhs: Self) -> bool {
65        // NOTE: since const ops is not stable, we have to convert `Group` into u32
66        // to use & operator in const context.
67        (self.memberships.bits() & rhs.filter.bits()) != 0
68            && (rhs.memberships.bits() & self.filter.bits()) != 0
69    }
70}
71
72impl Default for InteractionGroups {
73    fn default() -> Self {
74        Self {
75            memberships: Group::GROUP_1,
76            filter: Group::ALL,
77        }
78    }
79}
80
81bitflags::bitflags! {
82    /// A bit mask identifying groups for interaction.
83    #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
84    #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
85    pub struct Group: u32 {
86        /// The group n°1.
87        const GROUP_1 = 1 << 0;
88        /// The group n°2.
89        const GROUP_2 = 1 << 1;
90        /// The group n°3.
91        const GROUP_3 = 1 << 2;
92        /// The group n°4.
93        const GROUP_4 = 1 << 3;
94        /// The group n°5.
95        const GROUP_5 = 1 << 4;
96        /// The group n°6.
97        const GROUP_6 = 1 << 5;
98        /// The group n°7.
99        const GROUP_7 = 1 << 6;
100        /// The group n°8.
101        const GROUP_8 = 1 << 7;
102        /// The group n°9.
103        const GROUP_9 = 1 << 8;
104        /// The group n°10.
105        const GROUP_10 = 1 << 9;
106        /// The group n°11.
107        const GROUP_11 = 1 << 10;
108        /// The group n°12.
109        const GROUP_12 = 1 << 11;
110        /// The group n°13.
111        const GROUP_13 = 1 << 12;
112        /// The group n°14.
113        const GROUP_14 = 1 << 13;
114        /// The group n°15.
115        const GROUP_15 = 1 << 14;
116        /// The group n°16.
117        const GROUP_16 = 1 << 15;
118        /// The group n°17.
119        const GROUP_17 = 1 << 16;
120        /// The group n°18.
121        const GROUP_18 = 1 << 17;
122        /// The group n°19.
123        const GROUP_19 = 1 << 18;
124        /// The group n°20.
125        const GROUP_20 = 1 << 19;
126        /// The group n°21.
127        const GROUP_21 = 1 << 20;
128        /// The group n°22.
129        const GROUP_22 = 1 << 21;
130        /// The group n°23.
131        const GROUP_23 = 1 << 22;
132        /// The group n°24.
133        const GROUP_24 = 1 << 23;
134        /// The group n°25.
135        const GROUP_25 = 1 << 24;
136        /// The group n°26.
137        const GROUP_26 = 1 << 25;
138        /// The group n°27.
139        const GROUP_27 = 1 << 26;
140        /// The group n°28.
141        const GROUP_28 = 1 << 27;
142        /// The group n°29.
143        const GROUP_29 = 1 << 28;
144        /// The group n°30.
145        const GROUP_30 = 1 << 29;
146        /// The group n°31.
147        const GROUP_31 = 1 << 30;
148        /// The group n°32.
149        const GROUP_32 = 1 << 31;
150
151        /// All of the groups.
152        const ALL = u32::MAX;
153        /// None of the groups.
154        const NONE = 0;
155    }
156}
157
158impl From<u32> for Group {
159    #[inline]
160    fn from(val: u32) -> Self {
161        Self::from_bits_retain(val)
162    }
163}
164
165impl From<Group> for u32 {
166    #[inline]
167    fn from(val: Group) -> Self {
168        val.bits()
169    }
170}