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