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