ncollide3d/pipeline/object/
collision_object.rs

1use crate::bounding_volume::{self, BoundingVolume, AABB};
2use crate::math::Isometry;
3use crate::pipeline::broad_phase::BroadPhaseProxyHandle;
4use crate::pipeline::narrow_phase::CollisionObjectGraphIndex;
5use crate::pipeline::object::CollisionGroups;
6use crate::pipeline::object::GeometricQueryType;
7use crate::shape::{Shape, ShapeHandle};
8use simba::scalar::RealField;
9
10bitflags! {
11    #[derive(Default)]
12    /// Flags indicating what changed in a collision object since the last collision world update.
13    pub struct CollisionObjectUpdateFlags: u8 {
14        /// Indicate that the collision object's position changed.
15        const POSITION_CHANGED = 0b00000001;
16        /// Indicate that the collision object's predicted position changed.
17        const PREDICTED_POSITION_CHANGED = 0b00000010;
18        /// Indicate that the collision object's shape changed.
19        const SHAPE_CHANGED = 0b000100;
20        /// Indicate that the collision object's collision group changed.
21        const COLLISION_GROUPS_CHANGED = 0b001000;
22        /// Indicate that the collision object's geometric query type changed.
23        const QUERY_TYPE_CHANGED = 0b0010000;
24    }
25}
26
27impl CollisionObjectUpdateFlags {
28    /// Checks if the collision object has been changed in a way that justify a broad-phase update.
29    pub fn needs_broad_phase_update(&self) -> bool {
30        !self.is_empty()
31    }
32
33    /// Checks if the collision object has been changed in a way that justify a narrow-phase update.
34    pub fn needs_narrow_phase_update(&self) -> bool {
35        // The only change that does not trigger an update
36        // is a change on predicted position.
37        self.intersects(
38            Self::POSITION_CHANGED
39                | Self::SHAPE_CHANGED
40                | Self::COLLISION_GROUPS_CHANGED
41                | Self::QUERY_TYPE_CHANGED,
42        )
43    }
44
45    /// Checks if the collision object has been changed in a way that justify an update of its bounding volume.
46    pub fn needs_bounding_volume_update(&self) -> bool {
47        // NOTE: the QUERY_TYPE_CHANGED is included here because the
48        // prediction margin may have changed.
49        self.intersects(Self::POSITION_CHANGED | Self::SHAPE_CHANGED | Self::QUERY_TYPE_CHANGED)
50    }
51
52    /// Checks if the collision object has been changed in a way that justify that the broad-phase
53    /// recompute all potential proximity pairs for this collision objects.
54    pub fn needs_broad_phase_redispatch(&self) -> bool {
55        self.intersects(
56            Self::SHAPE_CHANGED | Self::COLLISION_GROUPS_CHANGED | Self::QUERY_TYPE_CHANGED,
57        )
58    }
59}
60
61/// Trait implemented by collision objects.
62pub trait CollisionObjectRef<N: RealField + Copy> {
63    /// The interaction graph index of this collision object, if it has been registered into an interaction graph.
64    ///
65    /// Se the `glue::create_proxies` for more details.
66    fn graph_index(&self) -> Option<CollisionObjectGraphIndex>;
67    /// The broad-phase proxy handle of this collision object, if it has been registered into a broad-phase.
68    ///
69    /// Se the `glue::create_proxies` for more details.
70    fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle>;
71    /// The position of this collision object.
72    fn position(&self) -> &Isometry<N>;
73    /// The expected position of this collision object in the next updates.
74    ///
75    /// This is used to enlarge the collision object bounding volume such that at yields more potential interaction pairs.
76    /// This is typically needed for CCD (continuous collision detection) to be sure the broad-phase does not miss pential
77    /// interactions in-between two discontinuous positions of the collision object.
78    fn predicted_position(&self) -> Option<&Isometry<N>>;
79    /// The shape of this collision object.
80    fn shape(&self) -> &dyn Shape<N>;
81    /// The collision groups of this collision object.
82    fn collision_groups(&self) -> &CollisionGroups;
83    /// The type of geometric queries this collision object is subjected to.
84    fn query_type(&self) -> GeometricQueryType<N>;
85    /// Flags indicating what changed in this collision object.
86    fn update_flags(&self) -> CollisionObjectUpdateFlags;
87
88    /// Computes the AABB of this collision object, ignoring `self.predicted_position()`.
89    fn compute_aabb(&self) -> AABB<N> {
90        let mut aabb = bounding_volume::aabb(self.shape(), self.position());
91        aabb.loosen(self.query_type().query_limit());
92        aabb
93    }
94
95    /// Computes the swept AABB of this collision object, taking `self.predict_position()` into account.
96    ///
97    /// Given the AABB of this collision object at the position `self.position()’, and the AABB of
98    /// this collision object at the position `self.predicted_position()`, this returns an AABB that
99    /// bounds both.
100    fn compute_swept_aabb(&self) -> AABB<N> {
101        if let Some(predicted_pos) = self.predicted_position() {
102            let shape = self.shape();
103            let mut aabb1 = bounding_volume::aabb(shape, self.position());
104            let mut aabb2 = bounding_volume::aabb(shape, predicted_pos);
105            let margin = self.query_type().query_limit();
106            aabb1.loosen(margin);
107            aabb2.loosen(margin);
108            aabb1.merge(&aabb2);
109            aabb1
110        } else {
111            self.compute_aabb()
112        }
113    }
114}
115
116/// The unique identifier of a collision object stored in a `CollisionObjectSlab` structure.
117#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
118#[repr(transparent)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120pub struct CollisionObjectSlabHandle(pub usize);
121
122impl CollisionObjectSlabHandle {
123    /// The unique identifier corresponding to this handle.
124    #[inline]
125    pub fn uid(&self) -> usize {
126        self.0
127    }
128}
129
130/// A stand-alone object that has a position and a shape.
131pub struct CollisionObject<N: RealField + Copy, T> {
132    proxy_handle: Option<BroadPhaseProxyHandle>,
133    graph_index: Option<CollisionObjectGraphIndex>,
134    position: Isometry<N>,
135    predicted_position: Option<Isometry<N>>,
136    shape: ShapeHandle<N>,
137    collision_groups: CollisionGroups,
138    query_type: GeometricQueryType<N>,
139    update_flags: CollisionObjectUpdateFlags,
140    data: T,
141}
142
143impl<N: RealField + Copy, T> CollisionObject<N, T> {
144    /// Creates a new collision object.
145    pub fn new(
146        proxy_handle: Option<BroadPhaseProxyHandle>,
147        graph_index: Option<CollisionObjectGraphIndex>,
148        position: Isometry<N>,
149        shape: ShapeHandle<N>,
150        groups: CollisionGroups,
151        query_type: GeometricQueryType<N>,
152        data: T,
153    ) -> CollisionObject<N, T> {
154        CollisionObject {
155            proxy_handle,
156            graph_index,
157            position,
158            predicted_position: None,
159            shape,
160            collision_groups: groups,
161            data,
162            query_type,
163            update_flags: CollisionObjectUpdateFlags::all(),
164        }
165    }
166
167    /// The collision object non-stable graph index.
168    ///
169    /// This index may change whenever a collision object is removed from the world.
170    #[inline]
171    pub fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
172        self.graph_index
173    }
174
175    /// Sets the collision object unique but non-stable graph index.
176    #[inline]
177    pub fn set_graph_index(&mut self, index: Option<CollisionObjectGraphIndex>) {
178        self.graph_index = index
179    }
180
181    /// Mutable reference to this collision object's update flags.
182    pub fn update_flags_mut(&mut self) -> &mut CollisionObjectUpdateFlags {
183        &mut self.update_flags
184    }
185
186    /// Clears the update flags of this collision object.
187    pub fn clear_update_flags(&mut self) {
188        self.update_flags = CollisionObjectUpdateFlags::empty()
189    }
190
191    /// The collision object's broad phase proxy unique identifier.
192    #[inline]
193    pub fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
194        self.proxy_handle
195    }
196
197    /// Set collision object's broad phase proxy unique identifier.
198    #[inline]
199    pub fn set_proxy_handle(&mut self, handle: Option<BroadPhaseProxyHandle>) {
200        self.proxy_handle = handle
201    }
202
203    /// The collision object position.
204    #[inline]
205    pub fn position(&self) -> &Isometry<N> {
206        &self.position
207    }
208
209    /// The predicted collision object position.
210    #[inline]
211    pub fn predicted_position(&self) -> Option<&Isometry<N>> {
212        self.predicted_position.as_ref()
213    }
214
215    /// Sets the position of the collision object and resets the predicted position to None.
216    #[inline]
217    pub fn set_position(&mut self, pos: Isometry<N>) {
218        self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
219        self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
220        self.position = pos;
221        self.predicted_position = None;
222    }
223
224    /// Sets the position of the collision object and resets the predicted position.
225    #[inline]
226    pub fn set_position_with_prediction(&mut self, pos: Isometry<N>, prediction: Isometry<N>) {
227        self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
228        self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
229        self.position = pos;
230        self.predicted_position = Some(prediction);
231    }
232
233    /// Sets the predicted position of the collision object.
234    #[inline]
235    pub fn set_predicted_position(&mut self, pos: Option<Isometry<N>>) {
236        self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
237        self.predicted_position = pos;
238    }
239
240    /// Deforms the underlying shape if possible.
241    ///
242    /// Panics if the shape is not deformable.
243    #[inline]
244    pub fn set_deformations(&mut self, coords: &[N]) {
245        self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
246        self.shape
247            .make_mut()
248            .as_deformable_shape_mut()
249            .expect("Attempting to deform a non-deformable shape.")
250            .set_deformations(coords)
251    }
252
253    /// The collision object shape.
254    #[inline]
255    pub fn shape(&self) -> &ShapeHandle<N> {
256        &self.shape
257    }
258
259    /// Set the collision object shape.
260    #[inline]
261    pub fn set_shape(&mut self, shape: ShapeHandle<N>) {
262        self.update_flags |= CollisionObjectUpdateFlags::SHAPE_CHANGED;
263        self.shape = shape
264    }
265
266    /// The collision groups of the collision object.
267    #[inline]
268    pub fn collision_groups(&self) -> &CollisionGroups {
269        &self.collision_groups
270    }
271
272    /// Sets the collision groups of this collision object.
273    #[inline]
274    pub fn set_collision_groups(&mut self, groups: CollisionGroups) {
275        self.update_flags |= CollisionObjectUpdateFlags::COLLISION_GROUPS_CHANGED;
276        self.collision_groups = groups
277    }
278
279    /// The kind of queries this collision object is expected to .
280    #[inline]
281    pub fn query_type(&self) -> GeometricQueryType<N> {
282        self.query_type
283    }
284
285    /// Sets the `GeometricQueryType` of the collision object.
286    /// Use `CollisionWorld::set_query_type` to use this method.
287    #[inline]
288    pub fn set_query_type(&mut self, query_type: GeometricQueryType<N>) {
289        self.update_flags |= CollisionObjectUpdateFlags::QUERY_TYPE_CHANGED;
290        self.query_type = query_type;
291    }
292
293    /// Reference to the user-defined data associated to this object.
294    #[inline]
295    pub fn data(&self) -> &T {
296        &self.data
297    }
298
299    /// Mutable reference to the user-defined data associated to this object.
300    #[inline]
301    pub fn data_mut(&mut self) -> &mut T {
302        &mut self.data
303    }
304}
305
306impl<N: RealField + Copy, T> CollisionObjectRef<N> for CollisionObject<N, T> {
307    fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
308        self.graph_index()
309    }
310
311    fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
312        self.proxy_handle()
313    }
314
315    fn position(&self) -> &Isometry<N> {
316        self.position()
317    }
318
319    fn predicted_position(&self) -> Option<&Isometry<N>> {
320        self.predicted_position()
321    }
322
323    fn shape(&self) -> &dyn Shape<N> {
324        self.shape().as_ref()
325    }
326
327    fn collision_groups(&self) -> &CollisionGroups {
328        self.collision_groups()
329    }
330
331    fn query_type(&self) -> GeometricQueryType<N> {
332        self.query_type()
333    }
334
335    fn update_flags(&self) -> CollisionObjectUpdateFlags {
336        self.update_flags
337    }
338}