use crate::dynamics::{RigidBodyHandle, RigidBodySet};
use crate::geometry::{ColliderHandle, ColliderSet, Contact, ContactManifold};
use crate::math::{Point, Real, Vector};
use crate::pipeline::EventHandler;
use crate::prelude::CollisionEventFlags;
use parry::query::ContactManifoldsWorkspace;
use super::CollisionEvent;
bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct SolverFlags: u32 {
const COMPUTE_IMPULSES = 0b001;
}
}
impl Default for SolverFlags {
fn default() -> Self {
SolverFlags::COMPUTE_IMPULSES
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ContactData {
pub impulse: Real,
#[cfg(feature = "dim2")]
pub tangent_impulse: Real,
#[cfg(feature = "dim3")]
pub tangent_impulse: na::Vector2<Real>,
}
impl Default for ContactData {
fn default() -> Self {
Self {
impulse: 0.0,
tangent_impulse: na::zero(),
}
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug)]
pub struct IntersectionPair {
pub intersecting: bool,
pub(crate) start_event_emited: bool,
}
impl IntersectionPair {
pub(crate) fn new() -> Self {
Self {
intersecting: false,
start_event_emited: false,
}
}
pub(crate) fn emit_start_event(
&mut self,
bodies: &RigidBodySet,
colliders: &ColliderSet,
collider1: ColliderHandle,
collider2: ColliderHandle,
events: &dyn EventHandler,
) {
self.start_event_emited = true;
events.handle_collision_event(
bodies,
colliders,
CollisionEvent::Started(collider1, collider2, CollisionEventFlags::SENSOR),
None,
);
}
pub(crate) fn emit_stop_event(
&mut self,
bodies: &RigidBodySet,
colliders: &ColliderSet,
collider1: ColliderHandle,
collider2: ColliderHandle,
events: &dyn EventHandler,
) {
self.start_event_emited = false;
events.handle_collision_event(
bodies,
colliders,
CollisionEvent::Stopped(collider1, collider2, CollisionEventFlags::SENSOR),
None,
);
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct ContactPair {
pub collider1: ColliderHandle,
pub collider2: ColliderHandle,
pub manifolds: Vec<ContactManifold>,
pub has_any_active_contact: bool,
pub(crate) start_event_emited: bool,
pub(crate) workspace: Option<ContactManifoldsWorkspace>,
}
impl ContactPair {
pub(crate) fn new(collider1: ColliderHandle, collider2: ColliderHandle) -> Self {
Self {
collider1,
collider2,
has_any_active_contact: false,
manifolds: Vec::new(),
start_event_emited: false,
workspace: None,
}
}
pub fn clear(&mut self) {
self.manifolds.clear();
self.has_any_active_contact = false;
self.workspace = None;
}
pub fn total_impulse(&self) -> Vector<Real> {
self.manifolds
.iter()
.map(|m| m.total_impulse() * m.data.normal)
.sum()
}
pub fn total_impulse_magnitude(&self) -> Real {
self.manifolds
.iter()
.fold(0.0, |a, m| a + m.total_impulse())
}
pub fn max_impulse(&self) -> (Real, Vector<Real>) {
let mut result = (0.0, Vector::zeros());
for m in &self.manifolds {
let impulse = m.total_impulse();
if impulse > result.0 {
result = (impulse, m.data.normal);
}
}
result
}
pub fn find_deepest_contact(&self) -> Option<(&ContactManifold, &Contact)> {
let mut deepest = None;
for m2 in &self.manifolds {
let deepest_candidate = m2.find_deepest_contact();
deepest = match (deepest, deepest_candidate) {
(_, None) => deepest,
(None, Some(c2)) => Some((m2, c2)),
(Some((m1, c1)), Some(c2)) => {
if c1.dist <= c2.dist {
Some((m1, c1))
} else {
Some((m2, c2))
}
}
}
}
deepest
}
pub(crate) fn emit_start_event(
&mut self,
bodies: &RigidBodySet,
colliders: &ColliderSet,
events: &dyn EventHandler,
) {
self.start_event_emited = true;
events.handle_collision_event(
bodies,
colliders,
CollisionEvent::Started(self.collider1, self.collider2, CollisionEventFlags::empty()),
Some(self),
);
}
pub(crate) fn emit_stop_event(
&mut self,
bodies: &RigidBodySet,
colliders: &ColliderSet,
events: &dyn EventHandler,
) {
self.start_event_emited = false;
events.handle_collision_event(
bodies,
colliders,
CollisionEvent::Stopped(self.collider1, self.collider2, CollisionEventFlags::empty()),
Some(self),
);
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ContactManifoldData {
pub rigid_body1: Option<RigidBodyHandle>,
pub rigid_body2: Option<RigidBodyHandle>,
pub solver_flags: SolverFlags,
pub normal: Vector<Real>,
pub solver_contacts: Vec<SolverContact>,
pub relative_dominance: i16,
pub user_data: u32,
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct SolverContact {
pub(crate) contact_id: u8,
pub point: Point<Real>,
pub dist: Real,
pub friction: Real,
pub restitution: Real,
pub tangent_velocity: Vector<Real>,
pub is_new: bool,
}
impl SolverContact {
pub fn is_bouncy(&self) -> bool {
if self.is_new {
self.restitution > 0.0
} else {
self.restitution >= 1.0
}
}
}
impl Default for ContactManifoldData {
fn default() -> Self {
Self::new(None, None, SolverFlags::empty())
}
}
impl ContactManifoldData {
pub(crate) fn new(
rigid_body1: Option<RigidBodyHandle>,
rigid_body2: Option<RigidBodyHandle>,
solver_flags: SolverFlags,
) -> ContactManifoldData {
Self {
rigid_body1,
rigid_body2,
solver_flags,
normal: Vector::zeros(),
solver_contacts: Vec::new(),
relative_dominance: 0,
user_data: 0,
}
}
#[inline]
pub fn num_active_contacts(&self) -> usize {
self.solver_contacts.len()
}
}
pub trait ContactManifoldExt {
fn total_impulse(&self) -> Real;
fn max_impulse(&self) -> Real;
}
impl ContactManifoldExt for ContactManifold {
fn total_impulse(&self) -> Real {
self.points.iter().map(|pt| pt.data.impulse).sum()
}
fn max_impulse(&self) -> Real {
self.points.iter().fold(0.0, |a, pt| a.max(pt.data.impulse))
}
}