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}