1use crate::math::{Real, Vect};
2use crate::plugin::context::{RapierContextColliders, RapierContextSimulation, RapierRigidBodySet};
3use crate::utils::iso_to_transform;
4use bevy::prelude::*;
5use rapier::geometry::{
6 ColliderHandle, Contact, ContactManifold, ContactManifoldData, ContactPair, InteractionGraph,
7 IntersectionPair, PairContacts, SoftPairContacts, SolverContact, SolverFlags, NEW_CONTACT_BIT,
8};
9
10impl RapierContextSimulation {
11 pub fn contact_pairs_with<'a, 'b: 'a>(
17 &'a self,
18 context_colliders: &'b RapierContextColliders,
19 rigidbody_set: &'b RapierRigidBodySet,
20 collider: Entity,
21 ) -> impl Iterator<Item = ContactPairView<'a>> {
22 context_colliders
23 .entity2collider
24 .get(&collider)
25 .into_iter()
26 .flat_map(|h| {
27 self.narrow_phase
28 .contact_pairs_with(*h)
29 .map(|raw| ContactPairView {
30 context_colliders,
31 rigidbody_set,
32 raw,
33 })
34 })
35 }
36
37 pub fn intersection_pairs_with<'a, 'b: 'a>(
44 &'a self,
45 rapier_colliders: &'b RapierContextColliders,
46 collider: Entity,
47 ) -> impl Iterator<Item = (Entity, Entity, bool)> + 'a {
48 rapier_colliders
49 .entity2collider
50 .get(&collider)
51 .into_iter()
52 .flat_map(|h| {
53 self.narrow_phase
54 .intersection_pairs_with(*h)
55 .filter_map(|(h1, h2, inter)| {
56 let e1 = rapier_colliders.collider_entity(h1);
57 let e2 = rapier_colliders.collider_entity(h2);
58 match (e1, e2) {
59 (Some(e1), Some(e2)) => Some((e1, e2, inter)),
60 _ => None,
61 }
62 })
63 })
64 }
65
66 pub fn contact_pair<'a, 'b: 'a>(
72 &'a self,
73 context_colliders: &'b RapierContextColliders,
74 rigidbody_set: &'b RapierRigidBodySet,
75 collider1: Entity,
76 collider2: Entity,
77 ) -> Option<ContactPairView<'a>> {
78 let h1 = context_colliders.entity2collider.get(&collider1)?;
79 let h2 = context_colliders.entity2collider.get(&collider2)?;
80 self.narrow_phase
81 .contact_pair(*h1, *h2)
82 .map(|raw| ContactPairView {
83 context_colliders,
84 rigidbody_set,
85 raw,
86 })
87 }
88
89 pub fn intersection_pair(
94 &self,
95 rapier_colliders: &RapierContextColliders,
96 collider1: Entity,
97 collider2: Entity,
98 ) -> Option<bool> {
99 let h1 = rapier_colliders.entity2collider.get(&collider1)?;
100 let h2 = rapier_colliders.entity2collider.get(&collider2)?;
101 self.narrow_phase.intersection_pair(*h1, *h2)
102 }
103
104 pub fn contact_pairs<'a, 'b: 'a>(
106 &'a self,
107 context_colliders: &'b RapierContextColliders,
108 rigidbody_set: &'b RapierRigidBodySet,
109 ) -> impl Iterator<Item = ContactPairView<'a>> {
110 self.narrow_phase
111 .contact_pairs()
112 .map(|raw| ContactPairView {
113 context_colliders,
114 rigidbody_set,
115 raw,
116 })
117 }
118
119 pub fn contact_graph(&self) -> &InteractionGraph<ColliderHandle, ContactPair> {
125 self.narrow_phase.contact_graph()
126 }
127
128 pub fn intersection_graph(&self) -> &InteractionGraph<ColliderHandle, IntersectionPair> {
134 self.narrow_phase.intersection_graph()
135 }
136
137 pub fn intersection_pairs<'a, 'b: 'a>(
139 &'a self,
140 rapier_colliders: &'b RapierContextColliders,
141 ) -> impl Iterator<Item = (Entity, Entity, bool)> + 'a {
142 self.narrow_phase
143 .intersection_pairs()
144 .filter_map(|(h1, h2, inter)| {
145 let e1 = rapier_colliders.collider_entity(h1);
146 let e2 = rapier_colliders.collider_entity(h2);
147 match (e1, e2) {
148 (Some(e1), Some(e2)) => Some((e1, e2, inter)),
149 _ => None,
150 }
151 })
152 }
153}
154
155pub struct ContactManifoldView<'a> {
157 rigidbody_set: &'a RapierRigidBodySet,
158 pub raw: &'a ContactManifold,
160}
161
162impl ContactManifoldView<'_> {
163 pub fn num_points(&self) -> usize {
165 self.raw.points.len()
166 }
167
168 pub fn point(&self, i: usize) -> Option<ContactView<'_>> {
170 self.raw.points.get(i).map(|raw| ContactView { raw })
171 }
172
173 pub fn points(&self) -> impl ExactSizeIterator<Item = ContactView<'_>> {
175 self.raw.points.iter().map(|raw| ContactView { raw })
176 }
177
178 pub fn local_n1(&self) -> Vect {
180 self.raw.local_n1
181 }
182
183 pub fn local_n2(&self) -> Vect {
185 self.raw.local_n2
186 }
187
188 pub fn subshape1(&self) -> u32 {
192 self.raw.subshape1
193 }
194
195 pub fn subshape2(&self) -> u32 {
199 self.raw.subshape2
200 }
201
202 pub fn rigid_body1(&self) -> Option<Entity> {
204 self.raw
205 .data
206 .rigid_body1
207 .and_then(|h| self.rigidbody_set.rigid_body_entity(h))
208 }
209
210 pub fn rigid_body2(&self) -> Option<Entity> {
212 self.raw
213 .data
214 .rigid_body2
215 .and_then(|h| self.rigidbody_set.rigid_body_entity(h))
216 }
217
218 pub fn solver_flags(&self) -> SolverFlags {
220 self.raw.data.solver_flags
221 }
222
223 pub fn normal(&self) -> Vect {
225 self.raw.data.normal
226 }
227
228 pub fn num_solver_contacts(&self) -> usize {
230 self.raw.data.solver_contacts.len()
231 }
232
233 pub fn solver_contact(&self, i: usize) -> Option<SolverContactView<'_>> {
235 self.raw
236 .data
237 .solver_contacts
238 .get(i)
239 .map(|raw| SolverContactView {
240 rigidbody_set: self.rigidbody_set,
241 manifold_data: &self.raw.data,
242 raw,
243 })
244 }
245
246 pub fn solver_contacts(&self) -> impl ExactSizeIterator<Item = SolverContactView<'_>> {
248 self.raw
249 .data
250 .solver_contacts
251 .iter()
252 .map(|raw| SolverContactView {
253 rigidbody_set: self.rigidbody_set,
254 manifold_data: &self.raw.data,
255 raw,
256 })
257 }
258
259 pub fn relative_dominance(&self) -> i16 {
261 self.raw.data.relative_dominance
262 }
263
264 pub fn user_data(&self) -> u32 {
266 self.raw.data.user_data
267 }
268
269 pub fn friction(&self) -> Real {
272 self.raw.data.friction
273 }
274
275 pub fn restitution(&self) -> Real {
278 self.raw.data.restitution
279 }
280
281 pub fn subshape_pose1(&self) -> Option<Transform> {
284 self.raw.subshape_pos1().map(iso_to_transform)
285 }
286
287 pub fn subshape_pose2(&self) -> Option<Transform> {
290 self.raw.subshape_pos2().map(iso_to_transform)
291 }
292}
293
294impl ContactManifoldView<'_> {
295 pub fn find_deepest_contact(&self) -> Option<ContactView<'_>> {
297 self.raw
298 .find_deepest_contact()
299 .map(|raw| ContactView { raw })
300 }
301}
302
303pub struct ContactView<'a> {
305 pub raw: &'a Contact,
307}
308
309impl ContactView<'_> {
310 pub fn local_p1(&self) -> Vect {
312 self.raw.local_p1
313 }
314
315 pub fn local_p2(&self) -> Vect {
317 self.raw.local_p2
318 }
319
320 pub fn dist(&self) -> Real {
322 self.raw.dist
323 }
324
325 pub fn fid1(&self) -> u32 {
327 self.raw.fid1.0
328 }
329
330 pub fn fid2(&self) -> u32 {
332 self.raw.fid2.0
333 }
334
335 pub fn impulse(&self) -> Real {
339 self.raw.data.impulse
340 }
341
342 #[cfg(feature = "dim2")]
345 pub fn tangent_impulse(&self) -> Real {
346 self.raw.data.tangent_impulse.x
347 }
348
349 #[cfg(feature = "dim3")]
352 pub fn tangent_impulse(&self) -> [Real; 2] {
353 self.raw.data.tangent_impulse.into()
354 }
355
356 pub fn warmstart_impulse(&self) -> Real {
358 self.raw.data.warmstart_impulse
359 }
360
361 #[cfg(feature = "dim2")]
363 pub fn warmstart_tangent_impulse(&self) -> Real {
364 self.raw.data.warmstart_tangent_impulse.x
365 }
366
367 #[cfg(feature = "dim3")]
369 pub fn warmstart_tangent_impulse(&self) -> [Real; 2] {
370 self.raw.data.warmstart_tangent_impulse.into()
371 }
372
373 #[cfg(feature = "dim3")]
375 pub fn warmstart_twist_impulse(&self) -> Real {
376 self.raw.data.warmstart_twist_impulse
377 }
378}
379
380pub struct SolverContactView<'a> {
382 rigidbody_set: &'a RapierRigidBodySet,
383 pub manifold_data: &'a ContactManifoldData,
385 pub raw: &'a SolverContact,
387}
388
389impl SolverContactView<'_> {
390 pub fn point(&self) -> Vect {
392 let (p1, p2) = self
393 .manifold_data
394 .solver_contact_world_points(self.raw, &self.rigidbody_set.bodies);
395 (p1 + p2) / 2.0
396 }
397 pub fn dist(&self) -> Real {
400 self.raw.dist
401 }
402 pub fn friction(&self) -> Real {
404 self.manifold_data.friction
405 }
406 pub fn restitution(&self) -> Real {
408 self.manifold_data.restitution
409 }
410 pub fn tangent_velocity(&self) -> Vect {
415 self.raw.tangent_velocity
416 }
417 pub fn is_new(&self) -> bool {
419 self.raw.contact_id[0] & NEW_CONTACT_BIT != 0
420 }
421 pub fn contact_id(&self) -> u32 {
426 self.raw.contact_indices()[0]
427 }
428 pub fn anchor1(&self) -> Vect {
434 self.raw.anchor1
435 }
436 pub fn anchor2(&self) -> Vect {
440 self.raw.anchor2
441 }
442 pub fn world_point1(&self) -> Vect {
444 self.manifold_data
445 .solver_contact_world_points(self.raw, &self.rigidbody_set.bodies)
446 .0
447 }
448 pub fn world_point2(&self) -> Vect {
450 self.manifold_data
451 .solver_contact_world_points(self.raw, &self.rigidbody_set.bodies)
452 .1
453 }
454}
455
456pub struct ContactPairView<'a> {
458 context_colliders: &'a RapierContextColliders,
459 rigidbody_set: &'a RapierRigidBodySet,
460 pub raw: &'a ContactPair,
462}
463
464impl ContactPairView<'_> {
465 pub fn collider1(&self) -> Option<Entity> {
467 self.context_colliders.collider_entity(self.raw.collider1)
468 }
469
470 pub fn collider2(&self) -> Option<Entity> {
472 self.context_colliders.collider_entity(self.raw.collider2)
473 }
474
475 pub fn manifolds_len(&self) -> usize {
477 self.raw.manifolds().len()
478 }
479
480 pub fn manifold(&self, i: usize) -> Option<ContactManifoldView<'_>> {
482 self.raw.manifolds().get(i).map(|raw| ContactManifoldView {
483 rigidbody_set: self.rigidbody_set,
484 raw,
485 })
486 }
487
488 pub fn manifolds(&self) -> impl ExactSizeIterator<Item = ContactManifoldView<'_>> {
490 self.raw.manifolds().iter().map(|raw| ContactManifoldView {
491 rigidbody_set: self.rigidbody_set,
492 raw,
493 })
494 }
495
496 pub fn has_any_active_contact(&self) -> bool {
498 self.raw.has_any_active_contact()
499 }
500
501 pub fn is_rigid(&self) -> bool {
503 self.raw.rigid().is_some()
504 }
505
506 pub fn is_soft(&self) -> bool {
511 self.raw.soft().is_some()
512 }
513
514 pub fn contacts(&self) -> &PairContacts {
516 &self.raw.contacts
517 }
518
519 pub fn soft_contacts(&self) -> Option<&SoftPairContacts> {
521 self.raw.soft()
522 }
523
524 pub fn soft_touching(&self) -> Option<bool> {
527 match &self.raw.contacts {
528 PairContacts::Soft { touching, .. } => Some(*touching),
529 PairContacts::Rigid(_) => None,
530 }
531 }
532
533 pub fn solver_manifolds_len(&self) -> usize {
535 self.raw.solver_manifolds().len()
536 }
537
538 pub fn solver_manifolds(&self) -> impl ExactSizeIterator<Item = ContactManifoldView<'_>> {
544 self.raw
545 .solver_manifolds()
546 .iter()
547 .map(|raw| ContactManifoldView {
548 rigidbody_set: self.rigidbody_set,
549 raw,
550 })
551 }
552
553 pub fn total_impulse(&self) -> Vect {
558 self.raw.total_impulse()
559 }
560
561 pub fn total_impulse_magnitude(&self) -> Real {
566 self.raw.total_impulse_magnitude()
567 }
568
569 pub fn max_impulse(&self) -> (Real, Vect) {
572 self.raw.max_impulse()
573 }
574
575 pub fn find_deepest_contact(&self) -> Option<(ContactManifoldView<'_>, ContactView<'_>)> {
583 self.raw.find_deepest_contact().map(|(manifold, contact)| {
584 (
585 ContactManifoldView {
586 rigidbody_set: self.rigidbody_set,
587 raw: manifold,
588 },
589 ContactView { raw: contact },
590 )
591 })
592 }
593}
594
595#[cfg(test)]
596mod test {
597 use crate::math::Real;
598 use crate::prelude::*;
599 use bevy::{
600 prelude::*,
601 time::{TimePlugin, TimeUpdateStrategy},
602 };
603
604 #[cfg(feature = "dim3")]
605 fn cuboid(hx: Real, hy: Real, hz: Real) -> Collider {
606 Collider::cuboid(hx, hy, hz)
607 }
608 #[cfg(feature = "dim2")]
609 fn cuboid(hx: Real, hy: Real, _hz: Real) -> Collider {
610 Collider::cuboid(hx, hy)
611 }
612
613 #[test]
614 fn resting_box_contact_impulses() {
615 let mut app = App::new();
616 app.add_plugins((
617 TransformPlugin,
618 TimePlugin,
619 RapierPhysicsPlugin::<NoUserData>::default(),
620 ))
621 .insert_resource(TimeUpdateStrategy::ManualDuration(
622 std::time::Duration::from_secs_f32(1f32 / 60f32),
623 ));
624 let ground = app
625 .world_mut()
626 .spawn((Transform::from_xyz(0.0, -1.0, 0.0), cuboid(4.0, 1.0, 4.0)))
627 .id();
628 let body = app
629 .world_mut()
630 .spawn((
631 Transform::from_xyz(0.0, 0.6, 0.0),
632 RigidBody::Dynamic,
633 cuboid(0.5, 0.5, 0.5),
634 Sleeping::disabled(),
636 ))
637 .id();
638 app.finish();
639 for _ in 0..60 {
640 app.update();
641 }
642
643 let mut query = app.world_mut().query::<(
644 &RapierContextSimulation,
645 &RapierContextColliders,
646 &RapierRigidBodySet,
647 )>();
648 let (simulation, colliders, bodies) = query.single(app.world()).unwrap();
649 let pair = simulation
650 .contact_pair(colliders, bodies, ground, body)
651 .unwrap();
652 assert!(pair.is_rigid());
653 assert!(!pair.is_soft());
654 assert!(pair.has_any_active_contact());
655 assert!(pair.solver_manifolds_len() > 0);
656 assert!(pair.total_impulse_magnitude() > 0.0);
657 assert!(pair.total_impulse().length() > 0.0);
658 let (max_impulse, max_dir) = pair.max_impulse();
659 assert!(max_impulse > 0.0);
660 assert!(max_dir.y.abs() > 0.9);
661
662 let manifold = pair.solver_manifolds().next().unwrap();
663 assert!(manifold.friction() > 0.0);
664 assert!(manifold.subshape_pose1().is_none());
665 assert!(manifold.points().any(|c| c.warmstart_impulse() > 0.0));
666 for solver_contact in manifold.solver_contacts() {
667 assert!((solver_contact.contact_id() as usize) < manifold.num_points());
668 let midpoint = (solver_contact.world_point1() + solver_contact.world_point2()) / 2.0;
669 assert!((midpoint - solver_contact.point()).length() < 1.0e-5);
670 }
671
672 assert!(simulation.contact_graph().interactions().count() > 0);
673 assert_eq!(simulation.intersection_graph().interactions().count(), 0);
674 }
675}