Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parry convenience query methods #434

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/geometry/collider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ impl<'a> From<&'a Collider> for &'a dyn Shape {
}
}

impl AsRef<dyn Shape> for Collider {
fn as_ref(&self) -> &dyn Shape {
&*self.raw
}
}

impl fmt::Debug for Collider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_typed_shape().fmt(f)
Expand Down
2 changes: 2 additions & 0 deletions src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use rapier::prelude::FeatureId;

mod collider;
mod collider_impl;
/// Wrappers around Parry shape queries.
pub mod query;
/// Wrappers around Rapier shapes to access their properties.
pub mod shape_views;

Expand Down
104 changes: 104 additions & 0 deletions src/geometry/query/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use crate::{
parry::{
self,
query::{Contact, Unsupported},
shape::Shape,
},
prelude::*,
utils::pos_rot_to_iso,
};

/// Results from [`closest_points`]
pub enum ClosestPoints {
/// The two objects are intersecting.
Intersecting,
/// The two objects are non-intersecting but closer than a given user-defined distance.
WithinMargin(Vect, Vect),
/// The two objects are non-intersecting and further than a given user-defined distance.
Disjoint,
}

use parry::query::closest_points::ClosestPoints as ParryClosestPoints;
impl From<ParryClosestPoints> for ClosestPoints {
fn from(parry: ParryClosestPoints) -> ClosestPoints {
match parry {
ParryClosestPoints::Intersecting => ClosestPoints::Intersecting,
ParryClosestPoints::Disjoint => ClosestPoints::Disjoint,
ParryClosestPoints::WithinMargin(p1, p2) => {
ClosestPoints::WithinMargin(p1.into(), p2.into())
}
}
}
}

/// Computes the pair of closest points between two shapes.
///
/// Returns `ClosestPoints::Disjoint` if the objects are separated by a distance greater than `max_dist`. The result points in `ClosestPoints::WithinMargin` are expressed in world-space.
pub fn closest_points(
pos1: Vect,
rot1: Rot,
shape1: &dyn Shape,
pos2: Vect,
rot2: Rot,
shape2: &dyn Shape,
max_dist: Real,
physics_scale: Real,
) -> Result<ClosestPoints, Unsupported> {
let iso1 = pos_rot_to_iso(pos1, rot1, physics_scale);
let iso2 = pos_rot_to_iso(pos2, rot2, physics_scale);

parry::query::closest_points(&iso1, shape1, &iso2, shape2, max_dist).map(|parry| parry.into())
}

/// Computes the minimum distance separating two shapes.
///
/// Returns 0.0 if the objects are touching or penetrating.
pub fn distance(
pos1: Vect,
rot1: Rot,
shape1: &dyn Shape,
pos2: Vect,
rot2: Rot,
shape2: &dyn Shape,
physics_scale: Real,
) -> Result<Real, Unsupported> {
let iso1 = pos_rot_to_iso(pos1, rot1, physics_scale);
let iso2 = pos_rot_to_iso(pos2, rot2, physics_scale);

parry::query::distance(&iso1, shape1, &iso2, shape2)
}

/// Computes one pair of contact points point between two shapes.
///
/// Returns None if the objects are separated by a distance greater than prediction. The result is given in world-space.
pub fn contact(
pos1: Vect,
rot1: Rot,
shape1: &dyn Shape,
pos2: Vect,
rot2: Rot,
shape2: &dyn Shape,
prediction: Real,
physics_scale: Real,
) -> Result<Option<Contact>, Unsupported> {
let iso1 = pos_rot_to_iso(pos1, rot1, physics_scale);
let iso2 = pos_rot_to_iso(pos2, rot2, physics_scale);

parry::query::contact(&iso1, shape1, &iso2, shape2, prediction)
}

/// Tests whether two shapes are intersecting.
pub fn intersection_test(
pos1: Vect,
rot1: Rot,
shape1: &dyn Shape,
pos2: Vect,
rot2: Rot,
shape2: &dyn Shape,
physics_scale: Real,
) -> Result<bool, Unsupported> {
let iso1 = pos_rot_to_iso(pos1, rot1, physics_scale);
let iso2 = pos_rot_to_iso(pos2, rot2, physics_scale);

parry::query::intersection_test(&iso1, shape1, &iso2, shape2)
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub mod render;
/// Miscellaneous helper functions.
pub mod utils;

pub use crate::geometry::query;

/// Groups the most often used types.
pub mod prelude {
pub use crate::control::*;
Expand Down
27 changes: 21 additions & 6 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::prelude::*;
use bevy::prelude::Transform;
use rapier::math::{Isometry, Real};

Expand Down Expand Up @@ -31,21 +32,35 @@ pub fn iso_to_transform(iso: &Isometry<Real>, physics_scale: Real) -> Transform
#[cfg(feature = "dim2")]
pub(crate) fn transform_to_iso(transform: &Transform, physics_scale: Real) -> Isometry<Real> {
use bevy::math::Vec3Swizzles;
Isometry::new(
(transform.translation / physics_scale).xy().into(),
pos_rot_to_iso(
transform.translation.xy(),
transform.rotation.to_scaled_axis().z,
physics_scale,
)
}

/// Converts a translation and rotation into a Rapier isometry.
///
/// The translation is divided by the `physics_scale`.
#[cfg(feature = "dim2")]
pub(crate) fn pos_rot_to_iso(pos: Vect, rot: Rot, physics_scale: Real) -> Isometry<Real> {
Isometry::new((pos / physics_scale).into(), rot)
}

/// Converts a Bevy transform to a Rapier isometry.
///
/// The translation is divided by the `physics_scale`.
#[cfg(feature = "dim3")]
pub(crate) fn transform_to_iso(transform: &Transform, physics_scale: Real) -> Isometry<Real> {
Isometry::from_parts(
(transform.translation / physics_scale).into(),
transform.rotation.into(),
)
pos_rot_to_iso(transform.translation, transform.rotation, physics_scale)
}

/// Converts a translation and rotation into a Rapier isometry.
///
/// The translation is divided by the `physics_scale`.
#[cfg(feature = "dim3")]
pub(crate) fn pos_rot_to_iso(pos: Vect, rot: Rot, physics_scale: Real) -> Isometry<Real> {
Isometry::from_parts((pos / physics_scale).into(), rot.into())
}

#[cfg(test)]
Expand Down
Loading