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(), entity2.index()))
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(), entity2.index())`.
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        self.add_edge_with(contact_edge, |_| {})
479    }
480
481    /// Creates a [`ContactEdge`] between two entities, calling the provided callback
482    /// to initialize the associated [`ContactPair`] in the list of active pairs.
483    ///
484    /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
485    ///
486    /// # Warning
487    ///
488    /// Creating a contact edge with this method will *not* trigger any collision events
489    /// or wake up the entities involved. Only use this method if you know what you are doing.
490    #[inline]
491    pub fn add_edge_with<F>(
492        &mut self,
493        contact_edge: ContactEdge,
494        pair_callback: F,
495    ) -> Option<ContactId>
496    where
497        F: FnMut(&mut ContactPair),
498    {
499        let pair_key = PairKey::new(
500            contact_edge.collider1.index(),
501            contact_edge.collider2.index(),
502        );
503        self.add_edge_and_key_with(contact_edge, pair_key, pair_callback)
504    }
505
506    /// Creates a [`ContactEdge`] between two entities with the given pair key, calling the provided callback
507    /// to initialize the associated [`ContactPair`] in the list of active pairs.
508    ///
509    /// The key must be equivalent to `PairKey::new(contacts.entity1.index(), contacts.entity2.index())`.
510    ///
511    /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
512    ///
513    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
514    /// If the key is not available, consider using [`add_edge`](Self::add_edge) or [`add_edge_with`](Self::add_edge_with) instead.
515    ///
516    /// # Warning
517    ///
518    /// Creating a contact edge with this method will *not* trigger any collision events
519    /// or wake up the entities involved. Only use this method if you know what you are doing.
520    #[inline]
521    pub fn add_edge_and_key_with<F>(
522        &mut self,
523        contact_edge: ContactEdge,
524        pair_key: PairKey,
525        mut pair_callback: F,
526    ) -> Option<ContactId>
527    where
528        F: FnMut(&mut ContactPair),
529    {
530        // Add the pair to the pair set for fast lookup.
531        if !self.pair_set.insert(pair_key) {
532            // The pair already exists.
533            return None;
534        }
535
536        let collider1 = contact_edge.collider1;
537        let collider2 = contact_edge.collider2;
538
539        // Get the indices of the entities in the graph.
540        let index1 = self
541            .entity_to_node
542            .get_or_insert_with(collider1, || self.edges.add_node(collider1));
543        let index2 = self
544            .entity_to_node
545            .get_or_insert_with(collider2, || self.edges.add_node(collider2));
546
547        // Add the edge to the graph.
548        let edge_id = ContactId(self.edges.add_edge(index1, index2, contact_edge).0);
549
550        // Create the contact pair. Contacts are created as active.
551        let mut pair = ContactPair::new(collider1, collider2, edge_id);
552
553        // Call the pair callback to allow for custom initialization.
554        pair_callback(&mut pair);
555
556        let pair_index = self.active_pairs.len();
557        self.active_pairs.push(pair);
558
559        // Set the contact ID and pair index of the edge.
560        let edge = self.edges.edge_weight_mut(edge_id.into()).unwrap();
561        edge.id = edge_id;
562        edge.pair_index = pair_index;
563
564        Some(edge_id)
565    }
566
567    /// Removes a [`ContactEdge`] between two entites and returns its value.
568    ///
569    /// # Warning
570    ///
571    /// Removing a contact edge with this method will *not* trigger any collision events
572    /// or wake up the entities involved. Only use this method if you know what you are doing.
573    ///
574    /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
575    #[inline]
576    pub fn remove_edge(&mut self, entity1: Entity, entity2: Entity) -> Option<ContactEdge> {
577        let (Some(index1), Some(index2)) =
578            (self.entity_to_node(entity1), self.entity_to_node(entity2))
579        else {
580            return None;
581        };
582
583        // Remove the edge from the graph.
584        self.edges.find_edge(index1, index2).and_then(|edge_id| {
585            let pair_key = PairKey::new(entity1.index(), entity2.index());
586            self.remove_edge_by_id(&pair_key, edge_id.into())
587        })
588    }
589
590    /// Removes a [`ContactEdge`] based on its pair key and ID and returns its value.
591    ///
592    /// # Warning
593    ///
594    /// Removing a contact edge with this method will *not* trigger any collision events
595    /// or wake up the entities involved. Only use this method if you know what you are doing.
596    ///
597    /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
598    #[inline]
599    pub fn remove_edge_by_id(&mut self, pair_key: &PairKey, id: ContactId) -> Option<ContactEdge> {
600        // Remove the pair from the pair set.
601        self.pair_set.remove(pair_key);
602
603        // Remove the edge from the graph.
604        let edge = self.edges.remove_edge(id.into())?;
605        let edge_count = self.edges.raw_edges().len();
606
607        // Remove the contact pair from the active or sleeping pairs.
608        let pair_index = edge.pair_index;
609        let contact_pairs = if edge.is_sleeping() {
610            &mut self.sleeping_pairs
611        } else {
612            &mut self.active_pairs
613        };
614
615        let moved_index = contact_pairs.len() - 1;
616        contact_pairs.swap_remove(pair_index);
617
618        if moved_index != pair_index {
619            // Fix moved pair index.
620            let moved_contact_id = contact_pairs[pair_index].contact_id;
621            let moved_edge = self
622                    .get_edge_mut_by_id(moved_contact_id)
623                    .unwrap_or_else(|| {
624                        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")
625                    });
626            debug_assert!(moved_edge.pair_index == moved_index);
627            moved_edge.pair_index = pair_index;
628        }
629
630        Some(edge)
631    }
632
633    /// Removes the collider of the given entity from the contact graph, calling the given callback
634    /// for each [`ContactEdge`] right before it is removed.
635    ///
636    /// # Warning
637    ///
638    /// Removing a collider with this method will *not* trigger any collision events
639    /// or wake up the entities involved. Only use this method if you know what you are doing.
640    #[inline]
641    pub fn remove_collider_with<F>(&mut self, entity: Entity, mut edge_callback: F)
642    where
643        F: FnMut(&mut StableUnGraph<Entity, ContactEdge>, ContactId),
644    {
645        // Remove the entity from the entity-to-node mapping,
646        // and get the index of the node in the graph.
647        let Some(index) = self.entity_to_node.remove(entity) else {
648            return;
649        };
650
651        // Remove the entity from the graph.
652        self.edges.remove_node_with(index, |graph, edge_index| {
653            let contact_id: ContactId = edge_index.into();
654            let contact_edge = graph.edge_weight(edge_index).unwrap_or_else(|| {
655                panic!("contact edge {contact_id:?} not found in contact graph")
656            });
657            let pair_key = PairKey::new(
658                contact_edge.collider1.index(),
659                contact_edge.collider2.index(),
660            );
661            let pair_index = contact_edge.pair_index;
662            let contact_pairs = if contact_edge.is_sleeping() {
663                &mut self.sleeping_pairs
664            } else {
665                &mut self.active_pairs
666            };
667
668            edge_callback(graph, contact_id);
669
670            // Remove the contact pair from the active or sleeping pairs.
671            let moved_index = contact_pairs.len() - 1;
672            let _ = contact_pairs.swap_remove(pair_index);
673
674            // Fix moved pair index.
675            if moved_index != pair_index {
676                let moved_contact_id = contact_pairs[pair_index].contact_id;
677                let moved_edge = graph
678                    .edge_weight_mut(moved_contact_id.into())
679                    .unwrap_or_else(|| {
680                        panic!("moved edge {moved_contact_id:?} not found in contact graph")
681                    });
682                debug_assert!(moved_edge.pair_index == moved_index);
683                moved_edge.pair_index = pair_index;
684            }
685
686            // Remove the pair from the pair set.
687            self.pair_set.remove(&pair_key);
688        });
689
690        // Removing the node swapped the last node to its place,
691        // so we need to remap the entity-to-node mapping of the swapped node.
692        if let Some(swapped) = self.edges.node_weight(index).copied() {
693            let swapped_index = self
694                .entity_to_node
695                .get_mut(swapped)
696                // This should never panic.
697                .expect("swapped entity has no entity-to-node mapping");
698            *swapped_index = index;
699        }
700    }
701
702    /// Transfers touching contacts of a body from the sleeping contacts to the active contacts,
703    /// calling the given callback for each [`ContactPair`] that is moved to active contacts.
704    #[inline]
705    pub fn wake_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
706    where
707        F: FnMut(&mut ContactGraph, &ContactPair),
708    {
709        // Get the index of the entity in the graph.
710        let Some(index) = self.entity_to_node(entity) else {
711            return;
712        };
713
714        // Find all edges connected to the entity.
715        let contact_ids: Vec<ContactId> = self
716            .edges
717            .edge_weights(index)
718            .filter_map(|edge| edge.is_sleeping().then_some(edge.id))
719            .collect();
720
721        // Iterate over the edges and move sleeping contacts to active contacts.
722        for id in contact_ids {
723            let edge = self
724                .edges
725                .edge_weight_mut(id.into())
726                .expect("edge should exist");
727
728            if !edge.is_touching() {
729                // Only wake touching contacts.
730                continue;
731            }
732
733            let pair_index = edge.pair_index;
734
735            // Remove the sleeping contact pair.
736            let moved_index = self.sleeping_pairs.len() - 1;
737            let transferred_pair = self.sleeping_pairs.swap_remove(pair_index);
738
739            // Update the pair index of the edge.
740            edge.pair_index = self.active_pairs.len();
741
742            // Set the edge to active.
743            edge.flags.set(ContactEdgeFlags::SLEEPING, false);
744
745            // Call the pair callback.
746            pair_callback(self, &transferred_pair);
747
748            // Add the transferred pair to the active pairs.
749            self.active_pairs.push(transferred_pair);
750
751            // Fix moved edge.
752            if moved_index != pair_index {
753                let moved_contact_id = self.sleeping_pairs[pair_index].contact_id;
754                let moved_edge = self
755                    .get_edge_mut_by_id(moved_contact_id)
756                    .unwrap_or_else(|| {
757                        panic!("error when waking contact pair {moved_contact_id:?} (other {id:?}) with pair index {pair_index:?}: moved edge not found in contact graph")
758                    });
759                debug_assert!(moved_edge.pair_index == moved_index);
760                moved_edge.pair_index = pair_index;
761            }
762        }
763    }
764
765    /// Transfers touching contacts of a body from the active contacts to the sleeping contacts,
766    /// calling the given callback for each [`ContactPair`] that is moved to sleeping contacts.
767    #[inline]
768    pub fn sleep_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
769    where
770        F: FnMut(&mut ContactGraph, &ContactPair),
771    {
772        // Get the index of the entity in the graph.
773        let Some(index) = self.entity_to_node(entity) else {
774            return;
775        };
776
777        // Find all edges connected to the entity.
778        let contact_ids: Vec<ContactId> = self
779            .edges
780            .edge_weights(index)
781            .filter_map(|edge| (!edge.is_sleeping()).then_some(edge.id))
782            .collect();
783
784        // Iterate over the edges and move active contacts to sleeping contacts.
785        for id in contact_ids {
786            let edge = self
787                .edges
788                .edge_weight_mut(id.into())
789                .expect("edge should exist");
790
791            if !edge.is_touching() {
792                // Only sleep touching contacts.
793                continue;
794            }
795
796            let pair_index = edge.pair_index;
797
798            // Remove the active contact pair.
799            let moved_index = self.active_pairs.len() - 1;
800            let transferred_pair = self.active_pairs.swap_remove(pair_index);
801
802            // Update the pair index of the edge.
803            edge.pair_index = self.sleeping_pairs.len();
804
805            // Set the edge to sleeping.
806            edge.flags.set(ContactEdgeFlags::SLEEPING, true);
807
808            // Call the edge callback.
809            pair_callback(self, &transferred_pair);
810
811            // Add the transferred pair to the sleeping pairs.
812            self.sleeping_pairs.push(transferred_pair);
813
814            // Fix moved edge.
815            if moved_index != pair_index {
816                let moved_contact_id = self.active_pairs[pair_index].contact_id;
817                let moved_edge = self
818                    .get_edge_mut_by_id(moved_contact_id)
819                    .unwrap_or_else(|| {
820                        panic!("error when sleeping contact pair {moved_contact_id:?} with pair index {pair_index:?}: moved edge not found in contact graph")
821                    });
822                debug_assert!(moved_edge.pair_index == moved_index);
823                moved_edge.pair_index = pair_index;
824            }
825        }
826    }
827
828    /// Clears all contact pairs and the contact graph.
829    ///
830    /// # Warning
831    ///
832    /// Clearing contact pairs with this method will *not* trigger any collision events
833    /// or wake up the entities involved. Only use this method if you know what you are doing.
834    ///
835    /// Additionally, this does *not* clear the [`ConstraintGraph`]! You should additionally
836    /// call [`ConstraintGraph::clear`].
837    ///
838    /// [`ConstraintGraph`]: crate::dynamics::solver::constraint_graph::ConstraintGraph
839    /// [`ConstraintGraph::clear`]: crate::dynamics::solver::constraint_graph::ConstraintGraph::clear
840    #[inline]
841    pub fn clear(&mut self) {
842        self.edges.clear();
843        self.active_pairs.clear();
844        self.sleeping_pairs.clear();
845        self.pair_set.clear();
846        self.entity_to_node.clear();
847    }
848}