Skip to main content

rapier3d/geometry/
narrow_phase.rs

1#[cfg(feature = "parallel")]
2use rayon::prelude::*;
3
4use crate::data::Coarena;
5use crate::data::graph::EdgeIndex;
6use crate::dynamics::{
7    CoefficientCombineRule, ImpulseJointSet, IslandManager, RigidBodyDominance, RigidBodySet,
8    RigidBodyType,
9};
10use crate::geometry::{
11    BoundingVolume, BroadPhasePairEvent, ColliderChanges, ColliderGraphIndex, ColliderHandle,
12    ColliderPair, ColliderSet, CollisionEvent, ContactData, ContactManifold, ContactManifoldData,
13    ContactPair, InteractionGraph, IntersectionPair, SolverContact, SolverFlags,
14    TemporaryInteractionIndex,
15};
16use crate::math::{MAX_MANIFOLD_POINTS, Real};
17use crate::pipeline::{
18    ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext,
19    PhysicsHooks,
20};
21use crate::prelude::{CollisionEventFlags, MultibodyJointSet};
22use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
23use parry::utils::PoseOpt;
24use parry::utils::hashmap::HashMap;
25use std::sync::Arc;
26
27#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
29struct ColliderGraphIndices {
30    contact_graph_index: ColliderGraphIndex,
31    intersection_graph_index: ColliderGraphIndex,
32}
33
34impl ColliderGraphIndices {
35    fn invalid() -> Self {
36        Self {
37            contact_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
38            intersection_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
39        }
40    }
41}
42
43#[derive(Copy, Clone, PartialEq, Eq)]
44enum PairRemovalMode {
45    FromContactGraph,
46    FromIntersectionGraph,
47    Auto,
48}
49
50/// The narrow-phase collision detector that computes precise contact points between colliders.
51///
52/// After the broad-phase quickly filters out distant object pairs, the narrow-phase performs
53/// detailed geometric computations to find exact:
54/// - Contact points (where surfaces touch)
55/// - Contact normals (which direction surfaces face)
56/// - Penetration depths (how much objects overlap)
57///
58/// You typically don't interact with this directly - it's managed by [`PhysicsPipeline::step`](crate::pipeline::PhysicsPipeline::step).
59/// However, you can access it to query contact information or intersection state between specific colliders.
60///
61/// **For spatial queries** (raycasts, shape casts), use [`QueryPipeline`](crate::pipeline::QueryPipeline) instead.
62#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
63#[derive(Clone)]
64pub struct NarrowPhase {
65    #[cfg_attr(
66        feature = "serde-serialize",
67        serde(skip, default = "crate::geometry::default_persistent_query_dispatcher")
68    )]
69    query_dispatcher: Arc<dyn PersistentQueryDispatcher<ContactManifoldData, ContactData>>,
70    contact_graph: InteractionGraph<ColliderHandle, ContactPair>,
71    intersection_graph: InteractionGraph<ColliderHandle, IntersectionPair>,
72    graph_indices: Coarena<ColliderGraphIndices>,
73}
74
75pub(crate) type ContactManifoldIndex = usize;
76
77impl Default for NarrowPhase {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83impl NarrowPhase {
84    /// Creates a new empty narrow-phase.
85    pub fn new() -> Self {
86        Self::with_query_dispatcher(DefaultQueryDispatcher)
87    }
88
89    /// Creates a new empty narrow-phase with a custom query dispatcher.
90    pub fn with_query_dispatcher<D>(d: D) -> Self
91    where
92        D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
93    {
94        Self {
95            query_dispatcher: Arc::new(d),
96            contact_graph: InteractionGraph::new(),
97            intersection_graph: InteractionGraph::new(),
98            graph_indices: Coarena::new(),
99        }
100    }
101
102    /// The query dispatcher used by this narrow-phase to select the right collision-detection
103    /// algorithms depending on the shape types.
104    pub fn query_dispatcher(
105        &self,
106    ) -> &dyn PersistentQueryDispatcher<ContactManifoldData, ContactData> {
107        &*self.query_dispatcher
108    }
109
110    /// The contact graph containing all contact pairs and their contact information.
111    pub fn contact_graph(&self) -> &InteractionGraph<ColliderHandle, ContactPair> {
112        &self.contact_graph
113    }
114
115    /// The intersection graph containing all intersection pairs and their intersection information.
116    pub fn intersection_graph(&self) -> &InteractionGraph<ColliderHandle, IntersectionPair> {
117        &self.intersection_graph
118    }
119
120    /// All the contacts involving the given collider.
121    ///
122    /// It is strongly recommended to use the [`NarrowPhase::contact_pairs_with`] method instead. This
123    /// method can be used if the generation number of the collider handle isn't known.
124    pub fn contact_pairs_with_unknown_gen(
125        &self,
126        collider: u32,
127    ) -> impl Iterator<Item = &ContactPair> {
128        self.graph_indices
129            .get_unknown_gen(collider)
130            .map(|id| id.contact_graph_index)
131            .into_iter()
132            .flat_map(move |id| self.contact_graph.interactions_with(id))
133            .map(|pair| pair.2)
134    }
135
136    /// All the contact pairs involving the given collider.
137    ///
138    /// The returned contact pairs identify pairs of colliders with intersecting bounding-volumes.
139    /// To check if any geometric contact happened between the collider shapes, check
140    /// [`ContactPair::has_any_active_contact`].
141    pub fn contact_pairs_with(
142        &self,
143        collider: ColliderHandle,
144    ) -> impl Iterator<Item = &ContactPair> {
145        self.graph_indices
146            .get(collider.0)
147            .map(|id| id.contact_graph_index)
148            .into_iter()
149            .flat_map(move |id| self.contact_graph.interactions_with(id))
150            .map(|pair| pair.2)
151    }
152
153    /// All the intersection pairs involving the given collider.
154    ///
155    /// It is strongly recommended to use the [`NarrowPhase::intersection_pairs_with`]  method instead.
156    /// This method can be used if the generation number of the collider handle isn't known.
157    pub fn intersection_pairs_with_unknown_gen(
158        &self,
159        collider: u32,
160    ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
161        self.graph_indices
162            .get_unknown_gen(collider)
163            .map(|id| id.intersection_graph_index)
164            .into_iter()
165            .flat_map(move |id| {
166                self.intersection_graph
167                    .interactions_with(id)
168                    .map(|e| (e.0, e.1, e.2.intersecting))
169            })
170    }
171
172    /// All the intersection pairs involving the given collider, where at least one collider
173    /// involved in the intersection is a sensor.
174    ///
175    /// The returned contact pairs identify pairs of colliders (where at least one is a sensor) with
176    /// intersecting bounding-volumes. To check if any geometric overlap happened between the collider shapes, check
177    /// the returned boolean.
178    pub fn intersection_pairs_with(
179        &self,
180        collider: ColliderHandle,
181    ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
182        self.graph_indices
183            .get(collider.0)
184            .map(|id| id.intersection_graph_index)
185            .into_iter()
186            .flat_map(move |id| {
187                self.intersection_graph
188                    .interactions_with(id)
189                    .map(|e| (e.0, e.1, e.2.intersecting))
190            })
191    }
192
193    /// Returns the contact pair at the given temporary index.
194    pub fn contact_pair_at_index(&self, id: TemporaryInteractionIndex) -> &ContactPair {
195        &self.contact_graph.graph.edges[id.index()].weight
196    }
197
198    /// The contact pair involving two specific colliders.
199    ///
200    /// It is strongly recommended to use the [`NarrowPhase::contact_pair`] method instead. This
201    /// method can be used if the generation number of the collider handle isn't known.
202    ///
203    /// If this returns `None`, there is no contact between the two colliders.
204    /// If this returns `Some`, then there may be a contact between the two colliders. Check the
205    /// result [`ContactPair::has_any_active_contact`] method to see if there is an actual contact.
206    pub fn contact_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<&ContactPair> {
207        let id1 = self.graph_indices.get_unknown_gen(collider1)?;
208        let id2 = self.graph_indices.get_unknown_gen(collider2)?;
209        self.contact_graph
210            .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
211            .map(|c| c.2)
212    }
213
214    /// The contact pair involving two specific colliders.
215    ///
216    /// If this returns `None`, there is no contact between the two colliders.
217    /// If this returns `Some`, then there may be a contact between the two colliders. Check the
218    /// result [`ContactPair::has_any_active_contact`] method to see if there is an actual contact.
219    pub fn contact_pair(
220        &self,
221        collider1: ColliderHandle,
222        collider2: ColliderHandle,
223    ) -> Option<&ContactPair> {
224        let id1 = self.graph_indices.get(collider1.0)?;
225        let id2 = self.graph_indices.get(collider2.0)?;
226        self.contact_graph
227            .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
228            .map(|c| c.2)
229    }
230
231    /// The intersection pair involving two specific colliders.
232    ///
233    /// It is strongly recommended to use the [`NarrowPhase::intersection_pair`] method instead. This
234    /// method can be used if the generation number of the collider handle isn't known.
235    ///
236    /// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders.
237    /// If this returns `Some(true)`, then there may be an intersection between the two colliders.
238    pub fn intersection_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<bool> {
239        let id1 = self.graph_indices.get_unknown_gen(collider1)?;
240        let id2 = self.graph_indices.get_unknown_gen(collider2)?;
241        self.intersection_graph
242            .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
243            .map(|c| c.2.intersecting)
244    }
245
246    /// The intersection pair involving two specific colliders.
247    ///
248    /// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders.
249    /// If this returns `Some(true)`, then there may be an intersection between the two colliders.
250    pub fn intersection_pair(
251        &self,
252        collider1: ColliderHandle,
253        collider2: ColliderHandle,
254    ) -> Option<bool> {
255        let id1 = self.graph_indices.get(collider1.0)?;
256        let id2 = self.graph_indices.get(collider2.0)?;
257        self.intersection_graph
258            .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
259            .map(|c| c.2.intersecting)
260    }
261
262    /// All the contact pairs maintained by this narrow-phase.
263    pub fn contact_pairs(&self) -> impl Iterator<Item = &ContactPair> {
264        self.contact_graph.interactions()
265    }
266
267    /// All the intersection pairs maintained by this narrow-phase.
268    pub fn intersection_pairs(
269        &self,
270    ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
271        self.intersection_graph
272            .interactions_with_endpoints()
273            .map(|e| (e.0, e.1, e.2.intersecting))
274    }
275
276    // #[cfg(feature = "parallel")]
277    // pub(crate) fn contact_pairs_vec_mut(&mut self) -> &mut Vec<ContactPair> {
278    //     &mut self.contact_graph.interactions
279    // }
280
281    /// Maintain the narrow-phase internal state by taking collider removal into account.
282    #[profiling::function]
283    pub fn handle_user_changes(
284        &mut self,
285        mut islands: Option<&mut IslandManager>,
286        modified_colliders: &[ColliderHandle],
287        removed_colliders: &[ColliderHandle],
288        colliders: &mut ColliderSet,
289        bodies: &mut RigidBodySet,
290        events: &dyn EventHandler,
291    ) {
292        // TODO: avoid these hash-maps.
293        // They are necessary to handle the swap-remove done internally
294        // by the contact/intersection graphs when a node is removed.
295        let mut prox_id_remap = HashMap::default();
296        let mut contact_id_remap = HashMap::default();
297
298        for collider in removed_colliders {
299            // NOTE: if the collider does not have any graph indices currently, there is nothing
300            // to remove in the narrow-phase for this collider.
301            if let Some(graph_idx) = self
302                .graph_indices
303                .remove(collider.0, ColliderGraphIndices::invalid())
304            {
305                let intersection_graph_id = prox_id_remap
306                    .get(collider)
307                    .copied()
308                    .unwrap_or(graph_idx.intersection_graph_index);
309                let contact_graph_id = contact_id_remap
310                    .get(collider)
311                    .copied()
312                    .unwrap_or(graph_idx.contact_graph_index);
313
314                self.remove_collider(
315                    intersection_graph_id,
316                    contact_graph_id,
317                    islands.as_deref_mut(),
318                    colliders,
319                    bodies,
320                    &mut prox_id_remap,
321                    &mut contact_id_remap,
322                    events,
323                );
324            }
325        }
326
327        self.handle_user_changes_on_colliders(
328            islands,
329            modified_colliders,
330            colliders,
331            bodies,
332            events,
333        );
334    }
335
336    #[profiling::function]
337    pub(crate) fn remove_collider(
338        &mut self,
339        intersection_graph_id: ColliderGraphIndex,
340        contact_graph_id: ColliderGraphIndex,
341        islands: Option<&mut IslandManager>,
342        colliders: &mut ColliderSet,
343        bodies: &mut RigidBodySet,
344        prox_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
345        contact_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
346        events: &dyn EventHandler,
347    ) {
348        // Wake up every body in contact with the deleted collider and generate Stopped collision events.
349        if let Some(islands) = islands {
350            for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
351                if let Some(parent) = colliders.get(a).and_then(|c| c.parent.as_ref()) {
352                    islands.wake_up(bodies, parent.handle, true)
353                }
354
355                if let Some(parent) = colliders.get(b).and_then(|c| c.parent.as_ref()) {
356                    islands.wake_up(bodies, parent.handle, true)
357                }
358
359                if pair.start_event_emitted {
360                    events.handle_collision_event(
361                        bodies,
362                        colliders,
363                        CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
364                        Some(pair),
365                    );
366                }
367            }
368        } else {
369            // If there is no island, don’t wake-up bodies, but do send the Stopped collision event.
370            for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
371                if pair.start_event_emitted {
372                    events.handle_collision_event(
373                        bodies,
374                        colliders,
375                        CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
376                        Some(pair),
377                    );
378                }
379            }
380        }
381
382        // Generate Stopped collision events for intersections.
383        for (a, b, pair) in self
384            .intersection_graph
385            .interactions_with(intersection_graph_id)
386        {
387            if pair.start_event_emitted {
388                events.handle_collision_event(
389                    bodies,
390                    colliders,
391                    CollisionEvent::Stopped(
392                        a,
393                        b,
394                        CollisionEventFlags::REMOVED | CollisionEventFlags::SENSOR,
395                    ),
396                    None,
397                );
398            }
399        }
400
401        // We have to manage the fact that one other collider will
402        // have its graph index changed because of the node's swap-remove.
403        if let Some(replacement) = self.intersection_graph.remove_node(intersection_graph_id) {
404            if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
405                replacement.intersection_graph_index = intersection_graph_id;
406            } else {
407                prox_id_remap.insert(replacement, intersection_graph_id);
408                // I feel like this should never happen now that the narrow-phase is the one owning
409                // the graph_indices. Let's put an unreachable in there and see if anybody still manages
410                // to reach it. If nobody does, we will remove this.
411                unreachable!();
412            }
413        }
414
415        if let Some(replacement) = self.contact_graph.remove_node(contact_graph_id) {
416            if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
417                replacement.contact_graph_index = contact_graph_id;
418            } else {
419                contact_id_remap.insert(replacement, contact_graph_id);
420                // I feel like this should never happen now that the narrow-phase is the one owning
421                // the graph_indices. Let's put an unreachable in there and see if anybody still manages
422                // to reach it. If nobody does, we will remove this.
423                unreachable!();
424            }
425        }
426    }
427
428    #[profiling::function]
429    pub(crate) fn handle_user_changes_on_colliders(
430        &mut self,
431        mut islands: Option<&mut IslandManager>,
432        modified_colliders: &[ColliderHandle],
433        colliders: &ColliderSet,
434        bodies: &mut RigidBodySet,
435        events: &dyn EventHandler,
436    ) {
437        let mut pairs_to_remove = vec![];
438
439        for handle in modified_colliders {
440            // NOTE: we use `get` because the collider may no longer
441            //       exist if it has been removed.
442            if let Some(co) = colliders.get(*handle) {
443                if !co.changes.needs_narrow_phase_update() {
444                    // No flag relevant to the narrow-phase is enabled for this collider.
445                    continue;
446                }
447
448                if let Some(gid) = self.graph_indices.get(handle.0) {
449                    // For each modified colliders, we need to wake-up the bodies it is in contact with
450                    // so that the narrow-phase properly takes into account the change in, e.g.,
451                    // collision groups. Waking up the modified collider's parent isn't enough because
452                    // it could be a fixed or kinematic body which don't propagate the wake-up state.
453                    if let Some(islands) = islands.as_deref_mut() {
454                        if let Some(co_parent) = &co.parent {
455                            islands.wake_up(bodies, co_parent.handle, true);
456                        }
457
458                        for inter in self
459                            .contact_graph
460                            .interactions_with(gid.contact_graph_index)
461                        {
462                            let other_handle = if *handle == inter.0 { inter.1 } else { inter.0 };
463                            let other_parent = colliders
464                                .get(other_handle)
465                                .and_then(|co| co.parent.as_ref());
466
467                            if let Some(other_parent) = other_parent {
468                                islands.wake_up(bodies, other_parent.handle, true);
469                            }
470                        }
471                    }
472
473                    // For each collider which had their sensor status modified, we need
474                    // to transfer their contact/intersection graph edges to the intersection/contact graph.
475                    // To achieve this we will remove the relevant contact/intersection pairs form the
476                    // contact/intersection graphs, and then add them into the other graph.
477                    if co.changes.intersects(ColliderChanges::TYPE) {
478                        if co.is_sensor() {
479                            // Find the contact pairs for this collider and
480                            // push them to `pairs_to_remove`.
481                            for inter in self
482                                .contact_graph
483                                .interactions_with(gid.contact_graph_index)
484                            {
485                                pairs_to_remove.push((
486                                    ColliderPair::new(inter.0, inter.1),
487                                    PairRemovalMode::FromContactGraph,
488                                ));
489                            }
490                        } else {
491                            // Find the contact pairs for this collider and
492                            // push them to `pairs_to_remove` if both involved
493                            // colliders are not sensors.
494                            for inter in self
495                                .intersection_graph
496                                .interactions_with(gid.intersection_graph_index)
497                                .filter(|(h1, h2, _)| {
498                                    !colliders[*h1].is_sensor() && !colliders[*h2].is_sensor()
499                                })
500                            {
501                                pairs_to_remove.push((
502                                    ColliderPair::new(inter.0, inter.1),
503                                    PairRemovalMode::FromIntersectionGraph,
504                                ));
505                            }
506                        }
507                    }
508
509                    // NOTE: if a collider only changed parent, we don’t need to remove it from any
510                    //       of the graphs as re-parenting doesn’t change the sensor status of a
511                    //       collider. If needed, their collision/intersection data will be
512                    //       updated/removed automatically in the contact or intersection update
513                    //       functions.
514                }
515            }
516        }
517
518        // Remove the pair from the relevant graph.
519        for pair in &pairs_to_remove {
520            self.remove_pair(
521                islands.as_deref_mut(),
522                colliders,
523                bodies,
524                &pair.0,
525                events,
526                pair.1,
527            );
528        }
529
530        // Add the removed pair to the relevant graph.
531        for pair in pairs_to_remove {
532            self.add_pair(colliders, &pair.0);
533        }
534    }
535
536    #[profiling::function]
537    fn remove_pair(
538        &mut self,
539        islands: Option<&mut IslandManager>,
540        colliders: &ColliderSet,
541        bodies: &mut RigidBodySet,
542        pair: &ColliderPair,
543        events: &dyn EventHandler,
544        mode: PairRemovalMode,
545    ) {
546        if let (Some(co1), Some(co2)) =
547            (colliders.get(pair.collider1), colliders.get(pair.collider2))
548        {
549            // TODO: could we just unwrap here?
550            // Don't we have the guarantee that we will get a `AddPair` before a `DeletePair`?
551            if let (Some(gid1), Some(gid2)) = (
552                self.graph_indices.get(pair.collider1.0),
553                self.graph_indices.get(pair.collider2.0),
554            ) {
555                if mode == PairRemovalMode::FromIntersectionGraph
556                    || (mode == PairRemovalMode::Auto && (co1.is_sensor() || co2.is_sensor()))
557                {
558                    let intersection = self
559                        .intersection_graph
560                        .remove_edge(gid1.intersection_graph_index, gid2.intersection_graph_index);
561
562                    // Emit an intersection lost event if we had an intersection before removing the edge.
563                    if let Some(mut intersection) = intersection {
564                        if intersection.intersecting
565                            && (co1.flags.active_events | co2.flags.active_events)
566                                .contains(ActiveEvents::COLLISION_EVENTS)
567                        {
568                            intersection.emit_stop_event(
569                                bodies,
570                                colliders,
571                                pair.collider1,
572                                pair.collider2,
573                                events,
574                            )
575                        }
576                    }
577                } else {
578                    let contact_pair = self
579                        .contact_graph
580                        .remove_edge(gid1.contact_graph_index, gid2.contact_graph_index);
581
582                    // Emit a contact stopped event if we had a contact before removing the edge.
583                    // Also wake up the dynamic bodies that were in contact.
584                    if let Some(mut ctct) = contact_pair {
585                        if ctct.has_any_active_contact() {
586                            if let Some(islands) = islands {
587                                if let Some(co_parent1) = &co1.parent {
588                                    islands.wake_up(bodies, co_parent1.handle, true);
589                                }
590
591                                if let Some(co_parent2) = co2.parent {
592                                    islands.wake_up(bodies, co_parent2.handle, true);
593                                }
594                            }
595
596                            if (co1.flags.active_events | co2.flags.active_events)
597                                .contains(ActiveEvents::COLLISION_EVENTS)
598                            {
599                                ctct.emit_stop_event(bodies, colliders, events);
600                            }
601                        }
602                    }
603                }
604            }
605        }
606    }
607
608    #[profiling::function]
609    fn add_pair(&mut self, colliders: &ColliderSet, pair: &ColliderPair) {
610        if let (Some(co1), Some(co2)) =
611            (colliders.get(pair.collider1), colliders.get(pair.collider2))
612        {
613            // These colliders have no parents - continue.
614
615            let (gid1, gid2) = self.graph_indices.ensure_pair_exists(
616                pair.collider1.0,
617                pair.collider2.0,
618                ColliderGraphIndices::invalid(),
619            );
620
621            if co1.is_sensor() || co2.is_sensor() {
622                // NOTE: the collider won't have a graph index as long
623                // as it does not interact with anything.
624                if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.intersection_graph_index)
625                {
626                    gid1.intersection_graph_index =
627                        self.intersection_graph.graph.add_node(pair.collider1);
628                }
629
630                if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.intersection_graph_index)
631                {
632                    gid2.intersection_graph_index =
633                        self.intersection_graph.graph.add_node(pair.collider2);
634                }
635
636                if self
637                    .intersection_graph
638                    .graph
639                    .find_edge(gid1.intersection_graph_index, gid2.intersection_graph_index)
640                    .is_none()
641                {
642                    let _ = self.intersection_graph.add_edge(
643                        gid1.intersection_graph_index,
644                        gid2.intersection_graph_index,
645                        IntersectionPair::new(),
646                    );
647                }
648            } else {
649                // NOTE: same code as above, but for the contact graph.
650                // TODO: refactor both pieces of code somehow?
651
652                // NOTE: the collider won't have a graph index as long
653                // as it does not interact with anything.
654                if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.contact_graph_index) {
655                    gid1.contact_graph_index = self.contact_graph.graph.add_node(pair.collider1);
656                }
657
658                if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.contact_graph_index) {
659                    gid2.contact_graph_index = self.contact_graph.graph.add_node(pair.collider2);
660                }
661
662                if self
663                    .contact_graph
664                    .graph
665                    .find_edge(gid1.contact_graph_index, gid2.contact_graph_index)
666                    .is_none()
667                {
668                    let interaction = ContactPair::new(pair.collider1, pair.collider2);
669                    let _ = self.contact_graph.add_edge(
670                        gid1.contact_graph_index,
671                        gid2.contact_graph_index,
672                        interaction,
673                    );
674                }
675            }
676        }
677    }
678
679    pub(crate) fn register_pairs(
680        &mut self,
681        mut islands: Option<&mut IslandManager>,
682        colliders: &ColliderSet,
683        bodies: &mut RigidBodySet,
684        broad_phase_events: &[BroadPhasePairEvent],
685        events: &dyn EventHandler,
686    ) {
687        for event in broad_phase_events {
688            match event {
689                BroadPhasePairEvent::AddPair(pair) => {
690                    self.add_pair(colliders, pair);
691                }
692                BroadPhasePairEvent::DeletePair(pair) => {
693                    self.remove_pair(
694                        islands.as_deref_mut(),
695                        colliders,
696                        bodies,
697                        pair,
698                        events,
699                        PairRemovalMode::Auto,
700                    );
701                }
702            }
703        }
704    }
705
706    #[profiling::function]
707    pub(crate) fn compute_intersections(
708        &mut self,
709        bodies: &RigidBodySet,
710        colliders: &ColliderSet,
711        hooks: &dyn PhysicsHooks,
712        events: &dyn EventHandler,
713    ) {
714        let nodes = &self.intersection_graph.graph.nodes;
715        let query_dispatcher = &*self.query_dispatcher;
716
717        // TODO: don't iterate on all the edges.
718        par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| {
719            let handle1 = nodes[edge.source().index()].weight;
720            let handle2 = nodes[edge.target().index()].weight;
721            let had_intersection = edge.weight.intersecting;
722            let co1 = &colliders[handle1];
723            let co2 = &colliders[handle2];
724            let rb_handle1 = co1.parent.map(|p| p.handle);
725            let rb_handle2 = co2.parent.map(|p| p.handle);
726
727            'emit_events: {
728                if !co1.changes.needs_narrow_phase_update()
729                    && !co2.changes.needs_narrow_phase_update()
730                {
731                    // No update needed for these colliders.
732                    return;
733                }
734
735                if rb_handle1 == rb_handle2 && co1.parent.is_some() {
736                    // Same parents. Ignore collisions.
737                    edge.weight.intersecting = false;
738                    break 'emit_events;
739                }
740                // TODO: avoid lookup into bodies.
741                let mut rb_type1 = RigidBodyType::Fixed;
742                let mut rb_type2 = RigidBodyType::Fixed;
743
744                if let Some(co_parent1) = &co1.parent {
745                    rb_type1 = bodies[co_parent1.handle].body_type;
746                }
747
748                if let Some(co_parent2) = &co2.parent {
749                    rb_type2 = bodies[co_parent2.handle].body_type;
750                }
751
752                // Filter based on the rigid-body types.
753                if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
754                    && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
755                {
756                    edge.weight.intersecting = false;
757                    break 'emit_events;
758                }
759
760                // Filter based on collision groups.
761                if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
762                    edge.weight.intersecting = false;
763                    break 'emit_events;
764                }
765
766                let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
767
768                if active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) {
769                    let context = PairFilterContext {
770                        bodies,
771                        colliders,
772                        rigid_body1: rb_handle1,
773                        rigid_body2: rb_handle2,
774                        collider1: handle1,
775                        collider2: handle2,
776                    };
777
778                    if !hooks.filter_intersection_pair(&context) {
779                        // No intersection allowed.
780                        edge.weight.intersecting = false;
781                        break 'emit_events;
782                    }
783                }
784
785                let pos12 = co1.pos.inv_mul(&co2.pos);
786                edge.weight.intersecting = query_dispatcher
787                    .intersection_test(&pos12, &*co1.shape, &*co2.shape)
788                    .unwrap_or(false);
789            }
790
791            let active_events = co1.flags.active_events | co2.flags.active_events;
792
793            if active_events.contains(ActiveEvents::COLLISION_EVENTS)
794                && had_intersection != edge.weight.intersecting
795            {
796                if edge.weight.intersecting {
797                    edge.weight
798                        .emit_start_event(bodies, colliders, handle1, handle2, events);
799                } else {
800                    edge.weight
801                        .emit_stop_event(bodies, colliders, handle1, handle2, events);
802                }
803            }
804        });
805    }
806
807    #[profiling::function]
808    pub(crate) fn compute_contacts(
809        &mut self,
810        prediction_distance: Real,
811        dt: Real,
812        islands: &mut IslandManager,
813        bodies: &mut RigidBodySet,
814        colliders: &ColliderSet,
815        impulse_joints: &ImpulseJointSet,
816        multibody_joints: &MultibodyJointSet,
817        hooks: &dyn PhysicsHooks,
818        events: &dyn EventHandler,
819    ) {
820        let query_dispatcher = &*self.query_dispatcher;
821        #[cfg(feature = "parallel")]
822        let (snd, rcv) = std::sync::mpsc::channel();
823
824        // TODO PERF: don't iterate on all the edges.
825        par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
826            let pair = &mut edge.weight;
827            let had_any_active_contact = pair.has_any_active_contact();
828            let co1 = &colliders[pair.collider1];
829            let co2 = &colliders[pair.collider2];
830            let rb_handle1 = co1.parent.map(|p| p.handle);
831            let rb_handle2 = co2.parent.map(|p| p.handle);
832
833            'emit_events: {
834                if !co1.changes.needs_narrow_phase_update()
835                    && !co2.changes.needs_narrow_phase_update()
836                {
837                    // No update needed for these colliders.
838                    return;
839                }
840
841                if rb_handle1 == rb_handle2 && co1.parent.is_some() {
842                    // Same parents. Ignore collisions.
843                    pair.clear();
844                    break 'emit_events;
845                }
846
847                let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]);
848                let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]);
849
850                let rb_type1 = rb1.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
851                let rb_type2 = rb2.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
852
853                // Deal with contacts disabled between bodies attached by joints.
854                if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) {
855                    for (_, joint) in
856                        impulse_joints.joints_between(co_parent1.handle, co_parent2.handle)
857                    {
858                        if !joint.data.contacts_enabled {
859                            pair.clear();
860                            break 'emit_events;
861                        }
862                    }
863
864                    let link1 = multibody_joints.rigid_body_link(co_parent1.handle);
865                    let link2 = multibody_joints.rigid_body_link(co_parent2.handle);
866
867                    if let (Some(link1), Some(link2)) = (link1, link2) {
868                        // If both bodies belong to the same multibody, apply some additional built-in
869                        // contact filtering rules.
870                        if link1.multibody == link2.multibody {
871                            // 1) check if self-contacts is enabled.
872                            if let Some(mb) = multibody_joints.get_multibody(link1.multibody) {
873                                if !mb.self_contacts_enabled() {
874                                    pair.clear();
875                                    break 'emit_events;
876                                }
877                            }
878
879                            // 2) if they are attached by a joint, check if  contacts is disabled.
880                            if let Some((_, _, mb_link)) =
881                                multibody_joints.joint_between(co_parent1.handle, co_parent2.handle)
882                            {
883                                if !mb_link.joint.data.contacts_enabled {
884                                    pair.clear();
885                                    break 'emit_events;
886                                }
887                            }
888                        }
889                    }
890                }
891
892                // Filter based on the rigid-body types.
893                if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
894                    && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
895                {
896                    pair.clear();
897                    break 'emit_events;
898                }
899
900                // Filter based on collision groups.
901                if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
902                    pair.clear();
903                    break 'emit_events;
904                }
905
906                let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
907
908                let mut solver_flags = if active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) {
909                    let context = PairFilterContext {
910                        bodies,
911                        colliders,
912                        rigid_body1: rb_handle1,
913                        rigid_body2: rb_handle2,
914                        collider1: pair.collider1,
915                        collider2: pair.collider2,
916                    };
917
918                    if let Some(solver_flags) = hooks.filter_contact_pair(&context) {
919                        solver_flags
920                    } else {
921                        // No contact allowed.
922                        pair.clear();
923                        break 'emit_events;
924                    }
925                } else {
926                    SolverFlags::default()
927                };
928
929                if !co1.flags.solver_groups.test(co2.flags.solver_groups) {
930                    solver_flags.remove(SolverFlags::COMPUTE_IMPULSES);
931                }
932
933                if co1.changes.contains(ColliderChanges::SHAPE)
934                    || co2.changes.contains(ColliderChanges::SHAPE)
935                {
936                    // The shape changed so the workspace is no longer valid.
937                    pair.workspace = None;
938                }
939
940                let pos12 = co1.pos.inv_mul(&co2.pos);
941
942                let contact_skin_sum = co1.contact_skin() + co2.contact_skin();
943                let soft_ccd_prediction1 = rb1.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
944                let soft_ccd_prediction2 = rb2.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
945                let effective_prediction_distance = if soft_ccd_prediction1 > 0.0
946                    || soft_ccd_prediction2 > 0.0
947                {
948                    let aabb1 = co1.compute_collision_aabb(0.0);
949                    let aabb2 = co2.compute_collision_aabb(0.0);
950                    let inv_dt = crate::utils::inv(dt);
951
952                    let linvel1 = rb1
953                        .map(|rb| rb.linvel().clamp_length_max(soft_ccd_prediction1 * inv_dt))
954                        .unwrap_or_default();
955                    let linvel2 = rb2
956                        .map(|rb| rb.linvel().clamp_length_max(soft_ccd_prediction2 * inv_dt))
957                        .unwrap_or_default();
958
959                    if !aabb1.intersects(&aabb2)
960                        && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1)
961                    {
962                        pair.clear();
963                        break 'emit_events;
964                    }
965
966                    prediction_distance.max(dt * (linvel1 - linvel2).length()) + contact_skin_sum
967                } else {
968                    prediction_distance + contact_skin_sum
969                };
970
971                let _ = query_dispatcher.contact_manifolds(
972                    &pos12,
973                    &*co1.shape,
974                    &*co2.shape,
975                    effective_prediction_distance,
976                    &mut pair.manifolds,
977                    &mut pair.workspace,
978                );
979
980                let friction = CoefficientCombineRule::combine(
981                    co1.material.friction,
982                    co2.material.friction,
983                    co1.material.friction_combine_rule,
984                    co2.material.friction_combine_rule,
985                );
986                let restitution = CoefficientCombineRule::combine(
987                    co1.material.restitution,
988                    co2.material.restitution,
989                    co1.material.restitution_combine_rule,
990                    co2.material.restitution_combine_rule,
991                );
992
993                let zero = RigidBodyDominance(0); // The value doesn't matter, it will be MAX because of the effective groups.
994                let dominance1 = rb1.map(|rb| rb.dominance).unwrap_or(zero);
995                let dominance2 = rb2.map(|rb| rb.dominance).unwrap_or(zero);
996
997                for manifold in &mut pair.manifolds {
998                    let world_pos1 = manifold.subshape_pos1.prepend_to(&co1.pos);
999                    let world_pos2 = manifold.subshape_pos2.prepend_to(&co2.pos);
1000                    manifold.data.solver_contacts.clear();
1001                    manifold.data.rigid_body1 = rb_handle1;
1002                    manifold.data.rigid_body2 = rb_handle2;
1003                    manifold.data.solver_flags = solver_flags;
1004                    manifold.data.relative_dominance = dominance1.effective_group(&rb_type1)
1005                        - dominance2.effective_group(&rb_type2);
1006                    manifold.data.normal = world_pos1.rotation * manifold.local_n1;
1007
1008                    // Generate solver contacts.
1009                    #[allow(unused_mut)] // Mut not needed in 2D.
1010                    let mut selected = [0, 1, 2, 3];
1011                    #[allow(unused_mut)] // Mut not needed in 2D.
1012                    let mut num_selected = MAX_MANIFOLD_POINTS.min(manifold.points.len());
1013
1014                    #[cfg(feature = "dim3")]
1015                    // super::manifold_reduction::reduce_manifold_bepu_like(
1016                    //     manifold,
1017                    //     &mut selected,
1018                    //     &mut num_selected,
1019                    // );
1020                    #[cfg(feature = "dim3")]
1021                    super::manifold_reduction::reduce_manifold_naive(
1022                        manifold,
1023                        &mut selected,
1024                        &mut num_selected,
1025                        prediction_distance,
1026                    );
1027
1028                    for contact_id in &selected[..num_selected] {
1029                        //     // manifold.points.iter().enumerate() {
1030                        let contact = &manifold.points[*contact_id];
1031                        let effective_contact_dist =
1032                            contact.dist - co1.contact_skin() - co2.contact_skin();
1033
1034                        let keep_solver_contact = effective_contact_dist < prediction_distance || {
1035                            let world_pt1 = world_pos1 * contact.local_p1;
1036                            let world_pt2 = world_pos2 * contact.local_p2;
1037                            let vel1 = rb1
1038                                .map(|rb| rb.velocity_at_point(world_pt1))
1039                                .unwrap_or_default();
1040                            let vel2 = rb2
1041                                .map(|rb| rb.velocity_at_point(world_pt2))
1042                                .unwrap_or_default();
1043                            effective_contact_dist + (vel2 - vel1).dot(manifold.data.normal) * dt
1044                                < prediction_distance
1045                        };
1046
1047                        if keep_solver_contact {
1048                            // Generate the solver contact.
1049                            let world_pt1 = world_pos1 * contact.local_p1;
1050                            let world_pt2 = world_pos2 * contact.local_p2;
1051
1052                            let effective_point = world_pt1.midpoint(world_pt2);
1053
1054                            let solver_contact = SolverContact {
1055                                contact_id: [*contact_id as u32],
1056                                point: effective_point,
1057                                dist: effective_contact_dist,
1058                                friction,
1059                                restitution,
1060                                tangent_velocity: Default::default(),
1061                                is_new: (contact.data.impulse == 0.0) as u32 as Real,
1062                                warmstart_impulse: contact.data.warmstart_impulse,
1063                                warmstart_tangent_impulse: contact.data.warmstart_tangent_impulse,
1064                                #[cfg(feature = "dim2")]
1065                                warmstart_twist_impulse: na::zero(),
1066                                #[cfg(feature = "dim3")]
1067                                warmstart_twist_impulse: contact.data.warmstart_twist_impulse,
1068                                #[cfg(feature = "dim3")]
1069                                padding: Default::default(),
1070                            };
1071
1072                            manifold.data.solver_contacts.push(solver_contact);
1073                        }
1074                    }
1075
1076                    // Apply the user-defined contact modification.
1077                    if active_hooks.contains(ActiveHooks::MODIFY_SOLVER_CONTACTS) {
1078                        let mut modifiable_solver_contacts =
1079                            std::mem::take(&mut manifold.data.solver_contacts);
1080                        let mut modifiable_user_data = manifold.data.user_data;
1081                        let mut modifiable_normal = manifold.data.normal;
1082
1083                        let mut context = ContactModificationContext {
1084                            bodies,
1085                            colliders,
1086                            rigid_body1: rb_handle1,
1087                            rigid_body2: rb_handle2,
1088                            collider1: pair.collider1,
1089                            collider2: pair.collider2,
1090                            manifold,
1091                            solver_contacts: &mut modifiable_solver_contacts,
1092                            normal: &mut modifiable_normal,
1093                            user_data: &mut modifiable_user_data,
1094                        };
1095
1096                        hooks.modify_solver_contacts(&mut context);
1097
1098                        manifold.data.solver_contacts = modifiable_solver_contacts;
1099                        manifold.data.normal = modifiable_normal;
1100                        manifold.data.user_data = modifiable_user_data;
1101                    }
1102                }
1103            }
1104
1105            /*
1106             * Handle actions on contact start/stop:
1107             *  - Emit event (if applicable).
1108             *  - Notify the island manager to potentially wake up the bodies.
1109             */
1110            let has_any_active_contact = pair.has_any_active_contact();
1111            if has_any_active_contact != had_any_active_contact {
1112                let active_events = co1.flags.active_events | co2.flags.active_events;
1113                if active_events.contains(ActiveEvents::COLLISION_EVENTS) {
1114                    if has_any_active_contact {
1115                        pair.emit_start_event(bodies, colliders, events);
1116                    } else {
1117                        pair.emit_stop_event(bodies, colliders, events);
1118                    }
1119                }
1120
1121                #[cfg(not(feature = "parallel"))]
1122                islands.interaction_started_or_stopped(
1123                    bodies,
1124                    rb_handle1,
1125                    rb_handle2,
1126                    has_any_active_contact,
1127                    true,
1128                );
1129                #[cfg(feature = "parallel")]
1130                {
1131                    // When running in parallel mode, defer the islands call after the loop.
1132                    let _ = snd.send((rb_handle1, rb_handle2, has_any_active_contact));
1133                }
1134            }
1135        });
1136
1137        #[cfg(feature = "parallel")]
1138        {
1139            drop(snd);
1140            for (parent1, parent2, any_active_contact) in rcv.iter() {
1141                islands.interaction_started_or_stopped(
1142                    bodies,
1143                    parent1,
1144                    parent2,
1145                    any_active_contact,
1146                    true,
1147                );
1148            }
1149        }
1150    }
1151
1152    /// Retrieve all the interactions with at least one contact point, happening between two active bodies.
1153    // NOTE: this is very similar to the code from ImpulseJointSet::select_active_interactions.
1154    pub(crate) fn select_active_contacts<'a>(
1155        &'a mut self,
1156        islands: &IslandManager,
1157        bodies: &RigidBodySet,
1158        out_contact_pairs: &mut Vec<TemporaryInteractionIndex>,
1159        out_manifolds: &mut Vec<&'a mut ContactManifold>,
1160        out: &mut [Vec<ContactManifoldIndex>],
1161    ) {
1162        for out_island in &mut out[..islands.active_islands().len()] {
1163            out_island.clear();
1164        }
1165
1166        // TODO: don't iterate through all the interactions.
1167        for (pair_id, inter) in self.contact_graph.graph.edges.iter_mut().enumerate() {
1168            let mut push_pair = false;
1169
1170            for manifold in &mut inter.weight.manifolds {
1171                if manifold
1172                    .data
1173                    .solver_flags
1174                    .contains(SolverFlags::COMPUTE_IMPULSES)
1175                    && manifold.data.num_active_contacts() != 0
1176                {
1177                    let (active_island_id1, rb_type1, sleeping1) =
1178                        if let Some(handle1) = manifold.data.rigid_body1 {
1179                            let rb1 = &bodies[handle1];
1180                            (
1181                                rb1.ids.active_island_id,
1182                                rb1.body_type,
1183                                rb1.activation.sleeping,
1184                            )
1185                        } else {
1186                            (0, RigidBodyType::Fixed, true)
1187                        };
1188
1189                    let (active_island_id2, rb_type2, sleeping2) =
1190                        if let Some(handle2) = manifold.data.rigid_body2 {
1191                            let rb2 = &bodies[handle2];
1192                            (
1193                                rb2.ids.active_island_id,
1194                                rb2.body_type,
1195                                rb2.activation.sleeping,
1196                            )
1197                        } else {
1198                            (0, RigidBodyType::Fixed, true)
1199                        };
1200
1201                    if (rb_type1.is_dynamic() || rb_type2.is_dynamic())
1202                        && (!rb_type1.is_dynamic() || !sleeping1)
1203                        && (!rb_type2.is_dynamic() || !sleeping2)
1204                    {
1205                        let island_awake_index = if !rb_type1.is_dynamic() {
1206                            islands.islands[active_island_id2]
1207                                .id_in_awake_list()
1208                                .expect("Internal error: island should be awake.")
1209                        } else {
1210                            islands.islands[active_island_id1]
1211                                .id_in_awake_list()
1212                                .expect("Internal error: island should be awake.")
1213                        };
1214
1215                        out[island_awake_index].push(out_manifolds.len());
1216                        out_manifolds.push(manifold);
1217                        push_pair = true;
1218                    }
1219                }
1220            }
1221
1222            if push_pair {
1223                out_contact_pairs.push(EdgeIndex::new(pair_id as u32));
1224            }
1225        }
1226    }
1227}
1228
1229#[cfg(test)]
1230#[cfg(feature = "f32")]
1231#[cfg(feature = "dim3")]
1232mod test {
1233    use crate::math::Vector;
1234    use crate::prelude::{
1235        CCDSolver, ColliderBuilder, DefaultBroadPhase, IntegrationParameters, PhysicsPipeline,
1236        RigidBodyBuilder,
1237    };
1238
1239    use super::*;
1240
1241    /// Test for https://github.com/dimforge/rapier/issues/734.
1242    #[test]
1243    pub fn collider_set_parent_depenetration() {
1244        // This tests the scenario:
1245        // 1. Body A has two colliders attached (and overlapping), Body B has none.
1246        // 2. One of the colliders from Body A gets re-parented to Body B.
1247        //    -> Collision is properly detected between the colliders of A and B.
1248        let mut rigid_body_set = RigidBodySet::new();
1249        let mut collider_set = ColliderSet::new();
1250
1251        /* Create the ground. */
1252        let collider = ColliderBuilder::ball(0.5);
1253
1254        /* Create body 1, which will contain both colliders at first. */
1255        let rigid_body_1 = RigidBodyBuilder::dynamic()
1256            .translation(Vector::new(0.0, 0.0, 0.0))
1257            .build();
1258        let body_1_handle = rigid_body_set.insert(rigid_body_1);
1259
1260        /* Create collider 1. Parent it to rigid body 1. */
1261        let collider_1_handle =
1262            collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1263
1264        /* Create collider 2. Parent it to rigid body 1. */
1265        let collider_2_handle =
1266            collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1267
1268        /* Create body 2. No attached colliders yet. */
1269        let rigid_body_2 = RigidBodyBuilder::dynamic()
1270            .translation(Vector::new(0.0, 0.0, 0.0))
1271            .build();
1272        let body_2_handle = rigid_body_set.insert(rigid_body_2);
1273
1274        /* Create other structures necessary for the simulation. */
1275        let gravity = Vector::ZERO;
1276        let integration_parameters = IntegrationParameters::default();
1277        let mut physics_pipeline = PhysicsPipeline::new();
1278        let mut island_manager = IslandManager::new();
1279        let mut broad_phase = DefaultBroadPhase::new();
1280        let mut narrow_phase = NarrowPhase::new();
1281        let mut impulse_joint_set = ImpulseJointSet::new();
1282        let mut multibody_joint_set = MultibodyJointSet::new();
1283        let mut ccd_solver = CCDSolver::new();
1284        let physics_hooks = ();
1285        let event_handler = ();
1286
1287        physics_pipeline.step(
1288            gravity,
1289            &integration_parameters,
1290            &mut island_manager,
1291            &mut broad_phase,
1292            &mut narrow_phase,
1293            &mut rigid_body_set,
1294            &mut collider_set,
1295            &mut impulse_joint_set,
1296            &mut multibody_joint_set,
1297            &mut ccd_solver,
1298            &physics_hooks,
1299            &event_handler,
1300        );
1301        let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1302        let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1303        assert!(
1304            (collider_1_position.translation - collider_2_position.translation).length() < 0.5f32
1305        );
1306
1307        let contact_pair = narrow_phase
1308            .contact_pair(collider_1_handle, collider_2_handle)
1309            .expect("The contact pair should exist.");
1310        assert_eq!(contact_pair.manifolds.len(), 0);
1311        assert!(
1312            narrow_phase
1313                .intersection_pair(collider_1_handle, collider_2_handle)
1314                .is_none(),
1315            "Interaction pair is for sensors"
1316        );
1317        /* Parent collider 2 to body 2. */
1318        collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1319
1320        physics_pipeline.step(
1321            gravity,
1322            &integration_parameters,
1323            &mut island_manager,
1324            &mut broad_phase,
1325            &mut narrow_phase,
1326            &mut rigid_body_set,
1327            &mut collider_set,
1328            &mut impulse_joint_set,
1329            &mut multibody_joint_set,
1330            &mut ccd_solver,
1331            &physics_hooks,
1332            &event_handler,
1333        );
1334
1335        let contact_pair = narrow_phase
1336            .contact_pair(collider_1_handle, collider_2_handle)
1337            .expect("The contact pair should exist.");
1338        assert_eq!(contact_pair.manifolds.len(), 1);
1339        assert!(
1340            narrow_phase
1341                .intersection_pair(collider_1_handle, collider_2_handle)
1342                .is_none(),
1343            "Interaction pair is for sensors"
1344        );
1345
1346        /* Run the game loop, stepping the simulation once per frame. */
1347        for _ in 0..200 {
1348            physics_pipeline.step(
1349                gravity,
1350                &integration_parameters,
1351                &mut island_manager,
1352                &mut broad_phase,
1353                &mut narrow_phase,
1354                &mut rigid_body_set,
1355                &mut collider_set,
1356                &mut impulse_joint_set,
1357                &mut multibody_joint_set,
1358                &mut ccd_solver,
1359                &physics_hooks,
1360                &event_handler,
1361            );
1362
1363            let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1364            let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1365            println!("collider 1 position: {}", collider_1_position.translation);
1366            println!("collider 2 position: {}", collider_2_position.translation);
1367        }
1368
1369        let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1370        let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1371        println!("collider 2 position: {}", collider_2_position.translation);
1372        assert!(
1373            (collider_1_position.translation - collider_2_position.translation).length() >= 0.5f32,
1374            "colliders should no longer be penetrating."
1375        );
1376    }
1377
1378    /// Test for https://github.com/dimforge/rapier/issues/734.
1379    #[test]
1380    pub fn collider_set_parent_no_self_intersection() {
1381        // This tests the scenario:
1382        // 1. Body A and Body B each have one collider attached.
1383        //    -> There should be a collision detected between A and B.
1384        // 2. The collider from Body B gets attached to Body A.
1385        //    -> There should no longer be any collision between A and B.
1386        // 3. Re-parent one of the collider from Body A to Body B again.
1387        //    -> There should a collision again.
1388        let mut rigid_body_set = RigidBodySet::new();
1389        let mut collider_set = ColliderSet::new();
1390
1391        /* Create the ground. */
1392        let collider = ColliderBuilder::ball(0.5);
1393
1394        /* Create body 1, which will contain collider 1. */
1395        let rigid_body_1 = RigidBodyBuilder::dynamic()
1396            .translation(Vector::new(0.0, 0.0, 0.0))
1397            .build();
1398        let body_1_handle = rigid_body_set.insert(rigid_body_1);
1399
1400        /* Create collider 1. Parent it to rigid body 1. */
1401        let collider_1_handle =
1402            collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1403
1404        /* Create body 2, which will contain collider 2 at first. */
1405        let rigid_body_2 = RigidBodyBuilder::dynamic()
1406            .translation(Vector::new(0.0, 0.0, 0.0))
1407            .build();
1408        let body_2_handle = rigid_body_set.insert(rigid_body_2);
1409
1410        /* Create collider 2. Parent it to rigid body 2. */
1411        let collider_2_handle =
1412            collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set);
1413
1414        /* Create other structures necessary for the simulation. */
1415        let gravity = Vector::ZERO;
1416        let integration_parameters = IntegrationParameters::default();
1417        let mut physics_pipeline = PhysicsPipeline::new();
1418        let mut island_manager = IslandManager::new();
1419        let mut broad_phase = DefaultBroadPhase::new();
1420        let mut narrow_phase = NarrowPhase::new();
1421        let mut impulse_joint_set = ImpulseJointSet::new();
1422        let mut multibody_joint_set = MultibodyJointSet::new();
1423        let mut ccd_solver = CCDSolver::new();
1424        let physics_hooks = ();
1425        let event_handler = ();
1426
1427        physics_pipeline.step(
1428            gravity,
1429            &integration_parameters,
1430            &mut island_manager,
1431            &mut broad_phase,
1432            &mut narrow_phase,
1433            &mut rigid_body_set,
1434            &mut collider_set,
1435            &mut impulse_joint_set,
1436            &mut multibody_joint_set,
1437            &mut ccd_solver,
1438            &physics_hooks,
1439            &event_handler,
1440        );
1441
1442        let contact_pair = narrow_phase
1443            .contact_pair(collider_1_handle, collider_2_handle)
1444            .expect("The contact pair should exist.");
1445        assert_eq!(
1446            contact_pair.manifolds.len(),
1447            1,
1448            "There should be a contact manifold."
1449        );
1450
1451        let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1452        let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1453        assert!(
1454            (collider_1_position.translation - collider_2_position.translation).length() < 0.5f32
1455        );
1456
1457        /* Parent collider 2 to body 1. */
1458        collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set);
1459        physics_pipeline.step(
1460            gravity,
1461            &integration_parameters,
1462            &mut island_manager,
1463            &mut broad_phase,
1464            &mut narrow_phase,
1465            &mut rigid_body_set,
1466            &mut collider_set,
1467            &mut impulse_joint_set,
1468            &mut multibody_joint_set,
1469            &mut ccd_solver,
1470            &physics_hooks,
1471            &event_handler,
1472        );
1473
1474        let contact_pair = narrow_phase
1475            .contact_pair(collider_1_handle, collider_2_handle)
1476            .expect("The contact pair should no longer exist.");
1477        assert_eq!(
1478            contact_pair.manifolds.len(),
1479            0,
1480            "Colliders with same parent should not be in contact together."
1481        );
1482
1483        /* Parent collider 2 back to body 1. */
1484        collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1485        physics_pipeline.step(
1486            gravity,
1487            &integration_parameters,
1488            &mut island_manager,
1489            &mut broad_phase,
1490            &mut narrow_phase,
1491            &mut rigid_body_set,
1492            &mut collider_set,
1493            &mut impulse_joint_set,
1494            &mut multibody_joint_set,
1495            &mut ccd_solver,
1496            &physics_hooks,
1497            &event_handler,
1498        );
1499
1500        let contact_pair = narrow_phase
1501            .contact_pair(collider_1_handle, collider_2_handle)
1502            .expect("The contact pair should exist.");
1503        assert_eq!(
1504            contact_pair.manifolds.len(),
1505            1,
1506            "There should be a contact manifold."
1507        );
1508    }
1509}