Skip to main content

avian3d/collision/contact_types/
contact_graph.rs

1use crate::collision::contact_types::ContactEdgeFlags;
2use crate::prelude::*;
3use crate::{
4    data_structures::{
5        graph::NodeIndex, pair_key::PairKey, sparse_secondary_map::SparseSecondaryEntityMap,
6        stable_graph::StableUnGraph,
7    },
8    dynamics::solver::constraint_graph::ContactManifoldHandle,
9};
10use bevy::{platform::collections::HashSet, prelude::*};
11
12use super::{ContactEdge, ContactId};
13
14/// A resource that stores all [`ContactEdge`]s in the physics world in an [undirected graph](StableUnGraph),
15/// and their corresponding [`ContactPair`]s.
16///
17/// Contact pairs exist between [colliders](Collider) that have intersecting [AABBs](ColliderAabb),
18/// even if the shapes themselves are not yet touching. Internally, pairs for active (non-sleeping) bodies
19/// are stored separately from pairs for sleeping bodies for optimization purposes.
20///
21/// For a simpler API that abstracts over this complexity, consider using the [`Collisions`]
22/// system parameter.
23///
24/// # Usage
25///
26/// The following methods can be used for querying collisions:
27///
28/// - [`get`](Self::get) and [`get_mut`](Self::get_mut)
29/// - [`iter_active`](Self::iter_active) and [`iter_active_mut`](Self::iter_active_mut)
30/// - [`iter_sleeping`](Self::iter_sleeping) and [`iter_sleeping_mut`](Self::iter_sleeping_mut)
31/// - [`contains`](Self::contains)
32/// - [`contact_pairs_with`](Self::contact_pairs_with)
33/// - [`entities_colliding_with`](Self::entities_colliding_with)
34///
35/// For example, to iterate over all collisions with a given entity:
36///
37/// ```
38#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
39#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
40/// use bevy::prelude::*;
41///
42/// #[derive(Component)]
43/// struct PressurePlate;
44///
45/// fn activate_pressure_plates(mut query: Query<Entity, With<PressurePlate>>, contact_graph: Res<ContactGraph>) {
46///     for pressure_plate in &query {
47///         // Compute the total impulse applied to the pressure plate.
48///         let mut total_impulse = 0.0;
49///
50///         for contact_pair in contact_graph.contact_pairs_with(pressure_plate) {
51///             total_impulse += contact_pair.total_normal_impulse_magnitude();
52///         }
53///
54///         if total_impulse > 5.0 {
55///             println!("Pressure plate activated!");
56///         }
57///     }
58/// }
59/// ```
60///
61/// While mutable access is allowed, contact modification and filtering should typically
62/// be done using [`CollisionHooks`]. See the documentation for more information.
63///
64/// For advanced usage, there are also methods such as [`get_edge`](Self::get_edge) and [`get_edge_mut`](Self::get_edge_mut)
65/// methods to access the [`ContactEdge`]s directly, along with variants that take a [`ContactId`] to access edges by their ID.
66///
67/// # Warning
68///
69/// For users, this resource is primarily for querying and reading collision data.
70///
71/// Directly adding, modifying, or removing contact pairs using this resource will *not* trigger any collision events,
72/// wake up the entities involved, or perform any other cleanup. Only make structural modifications if you know what you are doing.
73///
74/// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
75#[derive(Resource, Clone, Debug, Default)]
76pub struct ContactGraph {
77    // TODO: Can and should edges be between bodies instead of colliders?
78    // TODO: We could have a separate intersection graph for sensors.
79    // TODO: Make the fields private, but expose a public API through methods.
80    /// The internal undirected graph where nodes are entities and edges are contact pairs.
81    pub edges: ContactGraphInternal,
82
83    /// Contact pairs for awake dynamic and kinematic bodies.
84    pub(crate) active_pairs: Vec<ContactPair>,
85
86    /// Contact pairs for sleeping dynamic bodies.
87    pub(crate) sleeping_pairs: Vec<ContactPair>,
88
89    /// A set of all contact pairs for fast lookup.
90    ///
91    /// The [`PairKey`] is a unique pair of entity indices, sorted in ascending order,
92    /// concatenated into a single `u64` key.
93    ///
94    /// Two entities have a contact pair if they have intersecting AABBs.
95    pub(crate) pair_set: HashSet<PairKey>,
96
97    /// A map from entities to their corresponding node indices in the contact graph.
98    entity_to_node: SparseSecondaryEntityMap<NodeIndex>,
99
100    /// A reusable scratch buffer of contact IDs used when transferring contacts
101    /// between the active and sleeping sets, to avoid allocating on every call
102    /// to [`sleep_entity_with`] and [`wake_entity_with`].
103    ///
104    /// [`sleep_entity_with`]: Self::sleep_entity_with
105    /// [`wake_entity_with`]: Self::wake_entity_with
106    scratch_contact_ids: Vec<ContactId>,
107}
108
109/// An undirected graph where each node is an entity and each edge is a [`ContactEdge`].
110///
111/// The graph maintains stable indices for nodes and edges even when items are removed.
112///
113/// This is stored internally in the [`ContactGraph`] resource, which provides a higher-level API
114/// for working with contact pairs.
115pub type ContactGraphInternal = StableUnGraph<Entity, ContactEdge>;
116
117impl ContactGraph {
118    /// Returns the [`NodeIndex`] of the given entity in the contact graph.
119    ///
120    /// If the entity is not in the graph, `None` is returned.
121    #[inline]
122    pub fn entity_to_node(&self, entity: Entity) -> Option<NodeIndex> {
123        self.entity_to_node.get(entity).copied()
124    }
125
126    /// Returns the [`ContactEdge`] between two entities.
127    /// If the edge does not exist, `None` is returned.
128    ///
129    /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
130    /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
131    #[inline]
132    pub fn get_edge(&self, entity1: Entity, entity2: Entity) -> Option<&ContactEdge> {
133        let (Some(index1), Some(index2)) =
134            (self.entity_to_node(entity1), self.entity_to_node(entity2))
135        else {
136            return None;
137        };
138
139        self.edges
140            .find_edge(index1, index2)
141            .and_then(|edge| self.get_edge_by_id(edge.into()))
142    }
143
144    /// Returns the [`ContactEdge`] between two entities based on their IDs.
145    /// If the edge does not exist, `None` is returned.
146    ///
147    /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
148    /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
149    #[inline]
150    pub fn get_edge_by_id(&self, id: ContactId) -> Option<&ContactEdge> {
151        self.edges.edge_weight(id.into())
152    }
153
154    /// Returns a mutable reference to the [`ContactEdge`] between two entities.
155    /// If the edge does not exist, `None` is returned.
156    ///
157    /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
158    /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
159    #[inline]
160    pub fn get_edge_mut(&mut self, entity1: Entity, entity2: Entity) -> Option<&mut ContactEdge> {
161        let (Some(index1), Some(index2)) =
162            (self.entity_to_node(entity1), self.entity_to_node(entity2))
163        else {
164            return None;
165        };
166
167        self.edges
168            .find_edge(index1, index2)
169            .and_then(|edge| self.get_edge_mut_by_id(edge.into()))
170    }
171
172    /// Returns a mutable reference to the [`ContactEdge`] between two entities based on their IDs.
173    /// If the edge does not exist, `None` is returned.
174    ///
175    /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
176    /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
177    #[inline]
178    pub fn get_edge_mut_by_id(&mut self, id: ContactId) -> Option<&mut ContactEdge> {
179        self.edges.edge_weight_mut(id.into())
180    }
181
182    /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities.
183    /// If the pair does not exist, `None` is returned.
184    ///
185    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
186    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
187    #[inline]
188    pub fn get(&self, entity1: Entity, entity2: Entity) -> Option<(&ContactEdge, &ContactPair)> {
189        self.get_edge(entity1, entity2)
190            .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
191    }
192
193    /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
194    /// If the pair does not exist, `None` is returned.
195    ///
196    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
197    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
198    #[inline]
199    pub fn get_by_id(&self, id: ContactId) -> Option<(&ContactEdge, &ContactPair)> {
200        self.get_edge_by_id(id)
201            .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
202    }
203
204    /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities.
205    /// If the pair does not exist, `None` is returned.
206    ///
207    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
208    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
209    #[inline]
210    pub fn get_mut(
211        &mut self,
212        entity1: Entity,
213        entity2: Entity,
214    ) -> Option<(&mut ContactEdge, &mut ContactPair)> {
215        let (Some(index1), Some(index2)) =
216            (self.entity_to_node(entity1), self.entity_to_node(entity2))
217        else {
218            return None;
219        };
220
221        self.edges
222            .find_edge(index1, index2)
223            .and_then(|edge| self.get_mut_by_id(edge.into()))
224    }
225
226    /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
227    /// If the pair does not exist, `None` is returned.
228    ///
229    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
230    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
231    #[inline]
232    pub fn get_mut_by_id(&mut self, id: ContactId) -> Option<(&mut ContactEdge, &mut ContactPair)> {
233        self.edges.edge_weight_mut(id.into()).and_then(|edge| {
234            if edge.is_sleeping() {
235                self.sleeping_pairs
236                    .get_mut(edge.pair_index)
237                    .map(|pair| (edge, pair))
238            } else {
239                self.active_pairs
240                    .get_mut(edge.pair_index)
241                    .map(|pair| (edge, pair))
242            }
243        })
244    }
245
246    /// Returns the [`ContactPair`] between two entities based on the [`ContactEdge`].
247    /// If the pair does not exist, `None` is returned.
248    ///
249    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
250    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
251    #[inline]
252    pub fn get_pair_by_edge(&self, edge: &ContactEdge) -> Option<&ContactPair> {
253        if edge.is_sleeping() {
254            self.sleeping_pairs.get(edge.pair_index)
255        } else {
256            self.active_pairs.get(edge.pair_index)
257        }
258    }
259
260    /// Returns a mutable reference to the [`ContactPair`] between two entities based on the [`ContactEdge`].
261    /// If the pair does not exist, `None` is returned.
262    ///
263    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
264    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
265    #[inline]
266    pub fn get_pair_mut_by_edge(&mut self, edge: &ContactEdge) -> Option<&mut ContactPair> {
267        if edge.is_sleeping() {
268            self.sleeping_pairs.get_mut(edge.pair_index)
269        } else {
270            self.active_pairs.get_mut(edge.pair_index)
271        }
272    }
273
274    /// Returns a [`ContactManifold`] of a contact pair based on the [`ContactManifoldHandle`].
275    /// If the manifold does not exist, `None` is returned.
276    #[inline]
277    pub fn get_manifold(&self, handle: ContactManifoldHandle) -> Option<&ContactManifold> {
278        let contact_pair = self.get_by_id(handle.contact_id)?.1;
279        contact_pair.manifolds.get(handle.manifold_index)
280    }
281
282    /// Returns a mutable reference to a [`ContactManifold`] of a contact pair based on the [`ContactManifoldHandle`].
283    /// If the manifold does not exist, `None` is returned.
284    #[inline]
285    pub fn get_manifold_mut(
286        &mut self,
287        handle: ContactManifoldHandle,
288    ) -> Option<&mut ContactManifold> {
289        let contact_pair = self.get_mut_by_id(handle.contact_id)?.1;
290        contact_pair.manifolds.get_mut(handle.manifold_index)
291    }
292
293    /// Returns `true` if the given entities have a contact pair.
294    ///
295    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
296    /// even if the shapes themselves are not yet touching.
297    #[inline]
298    pub fn contains(&self, entity1: Entity, entity2: Entity) -> bool {
299        self.contains_key(&PairKey::new(entity1.index_u32(), entity2.index_u32()))
300    }
301
302    /// Returns `true` if the given pair key is in the contact graph.
303    ///
304    /// The pair key should be equivalent to `PairKey::new(entity1.index_u32(), entity2.index_u32())`.
305    ///
306    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
307    /// If the key is not available, consider using [`contains`](Self::contains) instead.
308    #[inline]
309    pub fn contains_key(&self, pair_key: &PairKey) -> bool {
310        self.pair_set.contains(pair_key)
311    }
312
313    /// Returns a slice over all active (non-sleeping) contact pairs.
314    #[inline]
315    pub fn active_pairs(&self) -> &[ContactPair] {
316        &self.active_pairs
317    }
318
319    /// Returns a slice over all sleeping contact pairs.
320    #[inline]
321    pub fn sleeping_pairs(&self) -> &[ContactPair] {
322        &self.sleeping_pairs
323    }
324
325    /// Returns a mutable slice over all active (non-sleeping) contact pairs.
326    #[inline]
327    pub fn active_pairs_mut(&mut self) -> &mut [ContactPair] {
328        &mut self.active_pairs
329    }
330
331    /// Returns a mutable slice over all sleeping contact pairs.
332    #[inline]
333    pub fn sleeping_pairs_mut(&mut self) -> &mut [ContactPair] {
334        &mut self.sleeping_pairs
335    }
336
337    /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs.
338    ///
339    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
340    /// even if the shapes themselves are not yet touching.
341    ///
342    /// If you only want touching contacts, use [`iter_active_touching`](Self::iter_active_touching) instead.
343    #[inline]
344    pub fn iter_active(&self) -> impl Iterator<Item = &ContactPair> {
345        self.active_pairs.iter()
346    }
347
348    /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs
349    /// that are currently touching.
350    ///
351    /// This is a subset of [`iter_active`](Self::iter_active) that only includes pairs where the colliders are touching.
352    #[inline]
353    pub fn iter_active_touching(&self) -> impl Iterator<Item = &ContactPair> {
354        self.iter_active()
355            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
356    }
357
358    /// Returns a iterator yielding mutable access to all contact pairs.
359    ///
360    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
361    /// even if the shapes themselves are not yet touching.
362    ///
363    /// If you only want touching contacts, use [`iter_active_touching_mut`](Self::iter_active_touching_mut) instead.
364    #[inline]
365    pub fn iter_active_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
366        self.active_pairs.iter_mut()
367    }
368
369    /// Returns an iterator yielding mutable access to all active (non-sleeping) contact pairs
370    /// that are currently touching.
371    ///
372    /// This is a subset of [`iter_active_mut`](Self::iter_active_mut) that only includes pairs where the colliders are touching.
373    #[inline]
374    pub fn iter_active_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
375        self.iter_active_mut()
376            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
377    }
378
379    /// Returns an iterator yielding immutable access to all sleeping contact pairs.
380    ///
381    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
382    /// even if the shapes themselves are not yet touching.
383    ///
384    /// If you only want touching contacts, use [`iter_sleeping_touching`](Self::iter_sleeping_touching) instead.
385    #[inline]
386    pub fn iter_sleeping(&self) -> impl Iterator<Item = &ContactPair> {
387        self.sleeping_pairs.iter()
388    }
389
390    /// Returns an iterator yielding immutable access to all sleeping contact pairs
391    /// that are currently touching.
392    ///
393    /// This is a subset of [`iter_sleeping`](Self::iter_sleeping) that only includes pairs where the colliders are touching.
394    #[inline]
395    pub fn iter_sleeping_touching(&self) -> impl Iterator<Item = &ContactPair> {
396        self.iter_sleeping()
397            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
398    }
399
400    /// Returns an iterator yielding mutable access to all sleeping contact pairs.
401    ///
402    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
403    /// even if the shapes themselves are not yet touching.
404    ///
405    /// If you only want touching contacts, use [`iter_sleeping_touching_mut`](Self::iter_sleeping_touching_mut) instead.
406    #[inline]
407    pub fn iter_sleeping_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
408        self.sleeping_pairs.iter_mut()
409    }
410
411    /// Returns an iterator yielding mutable access to all sleeping contact pairs
412    /// that are currently touching.
413    ///
414    /// This is a subset of [`iter_sleeping_mut`](Self::iter_sleeping_mut) that only includes pairs where the colliders are touching.
415    #[inline]
416    pub fn iter_sleeping_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
417        self.iter_sleeping_mut()
418            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
419    }
420
421    /// Returns an iterator yielding immutable access to all contact edges involving the given entity.
422    #[inline]
423    pub fn contact_edges_with(&self, entity: Entity) -> impl Iterator<Item = &ContactEdge> {
424        let index = self.entity_to_node(entity);
425        if let Some(index) = index {
426            itertools::Either::Left(self.edges.edge_weights(index))
427        } else {
428            itertools::Either::Right(core::iter::empty())
429        }
430    }
431
432    /// Returns an iterator yielding mutable access to all contact edges involving the given entity.
433    #[inline]
434    pub fn contact_edges_with_mut(
435        &mut self,
436        entity: Entity,
437    ) -> impl Iterator<Item = &mut ContactEdge> {
438        let index = self.entity_to_node(entity);
439        if let Some(index) = index {
440            itertools::Either::Left(self.edges.edge_weights_mut(index))
441        } else {
442            itertools::Either::Right(core::iter::empty())
443        }
444    }
445
446    /// Returns an iterator yielding immutable access to all contact pairs involving the given entity.
447    ///
448    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
449    /// even if the shapes themselves are not yet touching.
450    ///
451    /// Use [`ContactEdge::is_touching`](ContactEdge::is_touching) to determine if the actual collider shapes are touching.
452    // TODO: A mutable version of this could be useful, but it would probably require some `unsafe`.
453    #[inline]
454    pub fn contact_pairs_with(&self, entity: Entity) -> impl Iterator<Item = &ContactPair> {
455        self.contact_edges_with(entity)
456            .filter_map(move |edge| self.get_pair_by_edge(edge))
457    }
458
459    /// Returns an iterator yielding immutable access to all entities that have a contact pair with the given entity.
460    ///
461    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
462    /// even if the shapes themselves are not yet touching.
463    #[inline]
464    pub fn entities_colliding_with(&self, entity: Entity) -> impl Iterator<Item = Entity> + '_ {
465        self.entity_to_node
466            .get(entity)
467            .into_iter()
468            .flat_map(move |&index| {
469                self.edges
470                    .neighbors(index)
471                    .map(|index| *self.edges.node_weight(index).unwrap())
472            })
473    }
474
475    /// Creates a [`ContactEdge`] between two entities and adds an associated [`ContactPair`]
476    /// to the list of active pairs.
477    ///
478    /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
479    ///
480    /// # Warning
481    ///
482    /// Creating a contact edge with this method will *not* trigger any collision events
483    /// or wake up the entities involved. Only use this method if you know what you are doing.
484    #[inline]
485    pub fn add_edge(&mut self, contact_edge: ContactEdge) -> Option<ContactId> {
486        let body1 = contact_edge.body1;
487        let body2 = contact_edge.body2;
488        self.add_edge_with(contact_edge, |pair| {
489            pair.body1 = body1;
490            pair.body2 = body2;
491        })
492    }
493
494    /// Creates a [`ContactEdge`] between two entities, calling the provided callback
495    /// to initialize the associated [`ContactPair`] in the list of active pairs.
496    ///
497    /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
498    ///
499    /// # Warning
500    ///
501    /// Creating a contact edge with this method will *not* trigger any collision events
502    /// or wake up the entities involved. Only use this method if you know what you are doing.
503    #[inline]
504    pub fn add_edge_with<F>(
505        &mut self,
506        contact_edge: ContactEdge,
507        pair_callback: F,
508    ) -> Option<ContactId>
509    where
510        F: FnMut(&mut ContactPair),
511    {
512        let pair_key = PairKey::new(
513            contact_edge.collider1.index_u32(),
514            contact_edge.collider2.index_u32(),
515        );
516        self.add_edge_and_key_with(contact_edge, pair_key, pair_callback)
517    }
518
519    /// Creates a [`ContactEdge`] between two entities with the given pair key, calling the provided callback
520    /// to initialize the associated [`ContactPair`] in the list of active pairs.
521    ///
522    /// The key must be equivalent to `PairKey::new(contacts.entity1.index_u32(), contacts.entity2.index_u32())`.
523    ///
524    /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
525    ///
526    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
527    /// If the key is not available, consider using [`add_edge`](Self::add_edge) or [`add_edge_with`](Self::add_edge_with) instead.
528    ///
529    /// # Warning
530    ///
531    /// Creating a contact edge with this method will *not* trigger any collision events
532    /// or wake up the entities involved. Only use this method if you know what you are doing.
533    #[inline]
534    pub fn add_edge_and_key_with<F>(
535        &mut self,
536        contact_edge: ContactEdge,
537        pair_key: PairKey,
538        mut pair_callback: F,
539    ) -> Option<ContactId>
540    where
541        F: FnMut(&mut ContactPair),
542    {
543        // Add the pair to the pair set for fast lookup.
544        if !self.pair_set.insert(pair_key) {
545            // The pair already exists.
546            return None;
547        }
548
549        let collider1 = contact_edge.collider1;
550        let collider2 = contact_edge.collider2;
551
552        // Get the indices of the entities in the graph.
553        let index1 = self
554            .entity_to_node
555            .get_or_insert_with(collider1, || self.edges.add_node(collider1));
556        let index2 = self
557            .entity_to_node
558            .get_or_insert_with(collider2, || self.edges.add_node(collider2));
559
560        // Add the edge to the graph.
561        let edge_id = ContactId(self.edges.add_edge(index1, index2, contact_edge).0);
562
563        // Create the contact pair. Contacts are created as active.
564        let mut pair = ContactPair::new(collider1, collider2, edge_id);
565
566        // Call the pair callback to allow for custom initialization.
567        pair_callback(&mut pair);
568
569        let pair_index = self.active_pairs.len();
570        self.active_pairs.push(pair);
571
572        // Set the contact ID and pair index of the edge.
573        let edge = self.edges.edge_weight_mut(edge_id.into()).unwrap();
574        edge.id = edge_id;
575        edge.pair_index = pair_index;
576
577        Some(edge_id)
578    }
579
580    /// Removes a [`ContactEdge`] between two entites and returns its value.
581    ///
582    /// # Warning
583    ///
584    /// Removing a contact edge with this method will *not* trigger any collision events
585    /// or wake up the entities involved. Only use this method if you know what you are doing.
586    ///
587    /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
588    #[inline]
589    pub fn remove_edge(&mut self, entity1: Entity, entity2: Entity) -> Option<ContactEdge> {
590        let (Some(index1), Some(index2)) =
591            (self.entity_to_node(entity1), self.entity_to_node(entity2))
592        else {
593            return None;
594        };
595
596        // Remove the edge from the graph.
597        self.edges.find_edge(index1, index2).and_then(|edge_id| {
598            let pair_key = PairKey::new(entity1.index_u32(), entity2.index_u32());
599            self.remove_edge_by_id(&pair_key, edge_id.into())
600        })
601    }
602
603    /// Removes a [`ContactEdge`] based on its pair key and ID and returns its value.
604    ///
605    /// # Warning
606    ///
607    /// Removing a contact edge with this method will *not* trigger any collision events
608    /// or wake up the entities involved. Only use this method if you know what you are doing.
609    ///
610    /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
611    #[inline]
612    pub fn remove_edge_by_id(&mut self, pair_key: &PairKey, id: ContactId) -> Option<ContactEdge> {
613        // Remove the pair from the pair set.
614        self.pair_set.remove(pair_key);
615
616        // Remove the edge from the graph.
617        let edge = self.edges.remove_edge(id.into())?;
618        let edge_count = self.edges.raw_edges().len();
619
620        // Remove the contact pair from the active or sleeping pairs.
621        let pair_index = edge.pair_index;
622        let contact_pairs = if edge.is_sleeping() {
623            &mut self.sleeping_pairs
624        } else {
625            &mut self.active_pairs
626        };
627
628        let moved_index = contact_pairs.len() - 1;
629        contact_pairs.swap_remove(pair_index);
630
631        if moved_index != pair_index {
632            // Fix moved pair index.
633            let moved_contact_id = contact_pairs[pair_index].contact_id;
634            let moved_edge = self
635                    .get_edge_mut_by_id(moved_contact_id)
636                    .unwrap_or_else(|| {
637                        panic!("error when removing contact pair {id:?} with pair index {pair_index:?}: moved edge {moved_contact_id:?} not found in contact graph with {edge_count} edges and {moved_index} sleeping pairs")
638                    });
639            debug_assert!(moved_edge.pair_index == moved_index);
640            moved_edge.pair_index = pair_index;
641        }
642
643        Some(edge)
644    }
645
646    /// Removes the collider of the given entity from the contact graph, calling the given callback
647    /// for each [`ContactEdge`] right before it is removed.
648    ///
649    /// # Warning
650    ///
651    /// Removing a collider with this method will *not* trigger any collision events
652    /// or wake up the entities involved. Only use this method if you know what you are doing.
653    #[inline]
654    pub fn remove_collider_with<F>(&mut self, entity: Entity, mut edge_callback: F)
655    where
656        F: FnMut(&mut StableUnGraph<Entity, ContactEdge>, ContactId),
657    {
658        // Remove the entity from the entity-to-node mapping,
659        // and get the index of the node in the graph.
660        let Some(index) = self.entity_to_node.remove(entity) else {
661            return;
662        };
663
664        // Remove the entity from the graph.
665        self.edges.remove_node_with(index, |graph, edge_index| {
666            let contact_id: ContactId = edge_index.into();
667            let contact_edge = graph.edge_weight(edge_index).unwrap_or_else(|| {
668                panic!("contact edge {contact_id:?} not found in contact graph")
669            });
670            let pair_key = PairKey::new(
671                contact_edge.collider1.index_u32(),
672                contact_edge.collider2.index_u32(),
673            );
674            let pair_index = contact_edge.pair_index;
675            let contact_pairs = if contact_edge.is_sleeping() {
676                &mut self.sleeping_pairs
677            } else {
678                &mut self.active_pairs
679            };
680
681            edge_callback(graph, contact_id);
682
683            // Remove the contact pair from the active or sleeping pairs.
684            let moved_index = contact_pairs.len() - 1;
685            let _ = contact_pairs.swap_remove(pair_index);
686
687            // Fix moved pair index.
688            if moved_index != pair_index {
689                let moved_contact_id = contact_pairs[pair_index].contact_id;
690                let moved_edge = graph
691                    .edge_weight_mut(moved_contact_id.into())
692                    .unwrap_or_else(|| {
693                        panic!("moved edge {moved_contact_id:?} not found in contact graph")
694                    });
695                debug_assert!(moved_edge.pair_index == moved_index);
696                moved_edge.pair_index = pair_index;
697            }
698
699            // Remove the pair from the pair set.
700            self.pair_set.remove(&pair_key);
701        });
702
703        // Removing the node swapped the last node to its place,
704        // so we need to remap the entity-to-node mapping of the swapped node.
705        if let Some(swapped) = self.edges.node_weight(index).copied() {
706            let swapped_index = self
707                .entity_to_node
708                .get_mut(swapped)
709                // This should never panic.
710                .expect("swapped entity has no entity-to-node mapping");
711            *swapped_index = index;
712        }
713    }
714
715    /// Transfers the contacts of a body from the sleeping contacts to the active contacts,
716    /// calling the given callback for each [`ContactPair`] that is moved to active contacts.
717    #[inline]
718    pub fn wake_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
719    where
720        F: FnMut(&mut ContactGraph, &ContactPair),
721    {
722        // Get the index of the entity in the graph.
723        let Some(index) = self.entity_to_node(entity) else {
724            return;
725        };
726
727        // Find all edges connected to the entity.
728        let mut contact_ids = core::mem::take(&mut self.scratch_contact_ids);
729        contact_ids.extend(
730            self.edges
731                .edge_weights(index)
732                .filter_map(|edge| edge.is_sleeping().then_some(edge.id)),
733        );
734
735        // Iterate over the edges and move sleeping contacts to active contacts.
736        for &id in &contact_ids {
737            let edge = self
738                .edges
739                .edge_weight_mut(id.into())
740                .expect("edge should exist");
741
742            let pair_index = edge.pair_index;
743
744            // Remove the sleeping contact pair.
745            let moved_index = self.sleeping_pairs.len() - 1;
746            let transferred_pair = self.sleeping_pairs.swap_remove(pair_index);
747
748            // Update the pair index of the edge.
749            edge.pair_index = self.active_pairs.len();
750
751            // Set the edge to active.
752            edge.flags.set(ContactEdgeFlags::SLEEPING, false);
753
754            // Call the pair callback.
755            pair_callback(self, &transferred_pair);
756
757            // Add the transferred pair to the active pairs.
758            self.active_pairs.push(transferred_pair);
759
760            // Fix moved edge.
761            if moved_index != pair_index {
762                let moved_contact_id = self.sleeping_pairs[pair_index].contact_id;
763                let moved_edge = self
764                    .get_edge_mut_by_id(moved_contact_id)
765                    .unwrap_or_else(|| {
766                        panic!("error when waking contact pair {moved_contact_id:?} (other {id:?}) with pair index {pair_index:?}: moved edge not found in contact graph")
767                    });
768                debug_assert!(moved_edge.pair_index == moved_index);
769                moved_edge.pair_index = pair_index;
770            }
771        }
772
773        // Restore the scratch buffer.
774        contact_ids.clear();
775        self.scratch_contact_ids = contact_ids;
776    }
777
778    /// Transfers the contacts of a body from the active contacts to the sleeping contacts,
779    /// calling the given callback for each [`ContactPair`] that is moved to sleeping contacts.
780    ///
781    /// A contact is only moved to the sleeping set if `should_sleep` returns `true` for the
782    /// other body in the pair. This prevents a non-touching pair between this body and a still-awake
783    /// body from being put to sleep. A pair may sleep only once *both* of its bodies are asleep or immovable.
784    #[inline]
785    pub fn sleep_entity_with<F, S>(&mut self, entity: Entity, mut pair_callback: F, should_sleep: S)
786    where
787        F: FnMut(&mut ContactGraph, &ContactPair),
788        S: Fn(Option<Entity>) -> bool,
789    {
790        // Get the index of the entity in the graph.
791        let Some(index) = self.entity_to_node(entity) else {
792            return;
793        };
794
795        // Find all edges connected to the entity.
796        let mut contact_ids = core::mem::take(&mut self.scratch_contact_ids);
797        contact_ids.extend(
798            self.edges
799                .edge_weights(index)
800                .filter_map(|edge| (!edge.is_sleeping()).then_some(edge.id)),
801        );
802
803        // Iterate over the edges and move active contacts to sleeping contacts.
804        for &id in &contact_ids {
805            let edge = self
806                .edges
807                .edge_weight_mut(id.into())
808                .expect("edge should exist");
809
810            // Only sleep the contact if the other body is also asleep or immovable.
811            // Otherwise the pair must stay active so the narrow phase keeps updating it.
812            let other_body = if edge.collider1 == entity {
813                edge.body2
814            } else {
815                edge.body1
816            };
817            if !should_sleep(other_body) {
818                continue;
819            }
820
821            let pair_index = edge.pair_index;
822
823            // Remove the active contact pair.
824            let moved_index = self.active_pairs.len() - 1;
825            let transferred_pair = self.active_pairs.swap_remove(pair_index);
826
827            // Update the pair index of the edge.
828            edge.pair_index = self.sleeping_pairs.len();
829
830            // Set the edge to sleeping.
831            edge.flags.set(ContactEdgeFlags::SLEEPING, true);
832
833            // Call the edge callback.
834            pair_callback(self, &transferred_pair);
835
836            // Add the transferred pair to the sleeping pairs.
837            self.sleeping_pairs.push(transferred_pair);
838
839            // Fix moved edge.
840            if moved_index != pair_index {
841                let moved_contact_id = self.active_pairs[pair_index].contact_id;
842                let moved_edge = self
843                    .get_edge_mut_by_id(moved_contact_id)
844                    .unwrap_or_else(|| {
845                        panic!("error when sleeping contact pair {moved_contact_id:?} with pair index {pair_index:?}: moved edge not found in contact graph")
846                    });
847                debug_assert!(moved_edge.pair_index == moved_index);
848                moved_edge.pair_index = pair_index;
849            }
850        }
851
852        // Restore the scratch buffer.
853        contact_ids.clear();
854        self.scratch_contact_ids = contact_ids;
855    }
856
857    /// Clears all contact pairs and the contact graph.
858    ///
859    /// # Warning
860    ///
861    /// Clearing contact pairs with this method will *not* trigger any collision events
862    /// or wake up the entities involved. Only use this method if you know what you are doing.
863    ///
864    /// Additionally, this does *not* clear the [`ConstraintGraph`]! You should additionally
865    /// call [`ConstraintGraph::clear`].
866    ///
867    /// [`ConstraintGraph`]: crate::dynamics::solver::constraint_graph::ConstraintGraph
868    /// [`ConstraintGraph::clear`]: crate::dynamics::solver::constraint_graph::ConstraintGraph::clear
869    #[inline]
870    pub fn clear(&mut self) {
871        self.edges.clear();
872        self.active_pairs.clear();
873        self.sleeping_pairs.clear();
874        self.pair_set.clear();
875        self.entity_to_node.clear();
876    }
877}