use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle};
use crate::geometry::{InteractionGroups, SharedShape};
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
use crate::parry::transformation::vhacd::VHACDParameters;
use parry::bounding_volume::AABB;
use parry::shape::Shape;
bitflags::bitflags! {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub(crate) struct ColliderFlags: u8 {
const SENSOR = 1 << 0;
const FRICTION_COMBINE_RULE_01 = 1 << 1;
const FRICTION_COMBINE_RULE_10 = 1 << 2;
const RESTITUTION_COMBINE_RULE_01 = 1 << 3;
const RESTITUTION_COMBINE_RULE_10 = 1 << 4;
}
}
impl ColliderFlags {
pub fn is_sensor(self) -> bool {
self.contains(ColliderFlags::SENSOR)
}
pub fn friction_combine_rule_value(self) -> u8 {
(self.bits & 0b0000_0110) >> 1
}
pub fn restitution_combine_rule_value(self) -> u8 {
(self.bits & 0b0001_1000) >> 3
}
pub fn with_friction_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
self.bits = (self.bits & !0b0000_0110) | ((rule as u8) << 1);
self
}
pub fn with_restitution_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
self.bits = (self.bits & !0b0001_1000) | ((rule as u8) << 3);
self
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct Collider {
shape: SharedShape,
density: Real,
pub(crate) flags: ColliderFlags,
pub(crate) parent: RigidBodyHandle,
pub(crate) delta: Isometry<Real>,
pub(crate) position: Isometry<Real>,
pub(crate) predicted_position: Isometry<Real>,
pub friction: Real,
pub restitution: Real,
pub(crate) collision_groups: InteractionGroups,
pub(crate) solver_groups: InteractionGroups,
pub(crate) proxy_index: usize,
pub user_data: u128,
}
impl Collider {
pub(crate) fn reset_internal_references(&mut self) {
self.parent = RigidBodyHandle::invalid();
self.proxy_index = crate::INVALID_USIZE;
}
pub fn parent(&self) -> RigidBodyHandle {
self.parent
}
pub fn is_sensor(&self) -> bool {
self.flags.is_sensor()
}
#[doc(hidden)]
pub fn set_position_debug(&mut self, position: Isometry<Real>) {
self.position = position;
}
#[deprecated(note = "use `.position_wrt_parent()` instead.")]
pub fn delta(&self) -> &Isometry<Real> {
&self.delta
}
pub fn position(&self) -> &Isometry<Real> {
&self.position
}
pub fn position_wrt_parent(&self) -> &Isometry<Real> {
&self.delta
}
pub fn collision_groups(&self) -> InteractionGroups {
self.collision_groups
}
pub fn solver_groups(&self) -> InteractionGroups {
self.solver_groups
}
pub fn density(&self) -> Real {
self.density
}
pub fn shape(&self) -> &dyn Shape {
&*self.shape.0
}
pub fn compute_aabb(&self) -> AABB {
self.shape.compute_aabb(&self.position)
}
pub fn mass_properties(&self) -> MassProperties {
self.shape.mass_properties(self.density)
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ColliderBuilder {
pub shape: SharedShape,
density: Option<Real>,
pub friction: Real,
pub friction_combine_rule: CoefficientCombineRule,
pub restitution: Real,
pub restitution_combine_rule: CoefficientCombineRule,
pub delta: Isometry<Real>,
pub is_sensor: bool,
pub user_data: u128,
pub collision_groups: InteractionGroups,
pub solver_groups: InteractionGroups,
}
impl ColliderBuilder {
pub fn new(shape: SharedShape) -> Self {
Self {
shape,
density: None,
friction: Self::default_friction(),
restitution: 0.0,
delta: Isometry::identity(),
is_sensor: false,
user_data: 0,
collision_groups: InteractionGroups::all(),
solver_groups: InteractionGroups::all(),
friction_combine_rule: CoefficientCombineRule::Average,
restitution_combine_rule: CoefficientCombineRule::Average,
}
}
pub fn get_density(&self) -> Real {
let default_density = if self.is_sensor { 0.0 } else { 1.0 };
self.density.unwrap_or(default_density)
}
pub fn compound(shapes: Vec<(Isometry<Real>, SharedShape)>) -> Self {
Self::new(SharedShape::compound(shapes))
}
pub fn ball(radius: Real) -> Self {
Self::new(SharedShape::ball(radius))
}
#[cfg(feature = "dim3")]
pub fn cylinder(half_height: Real, radius: Real) -> Self {
Self::new(SharedShape::cylinder(half_height, radius))
}
#[cfg(feature = "dim3")]
pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
Self::new(SharedShape::round_cylinder(
half_height,
radius,
border_radius,
))
}
#[cfg(feature = "dim3")]
pub fn cone(half_height: Real, radius: Real) -> Self {
Self::new(SharedShape::cone(half_height, radius))
}
#[cfg(feature = "dim3")]
pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
Self::new(SharedShape::round_cone(half_height, radius, border_radius))
}
#[cfg(feature = "dim2")]
pub fn cuboid(hx: Real, hy: Real) -> Self {
Self::new(SharedShape::cuboid(hx, hy))
}
#[cfg(feature = "dim2")]
pub fn round_cuboid(hx: Real, hy: Real, border_radius: Real) -> Self {
Self::new(SharedShape::round_cuboid(hx, hy, border_radius))
}
pub fn capsule_x(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::x() * half_height);
Self::new(SharedShape::capsule(-p, p, radius))
}
pub fn capsule_y(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::y() * half_height);
Self::new(SharedShape::capsule(-p, p, radius))
}
#[cfg(feature = "dim3")]
pub fn capsule_z(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::z() * half_height);
Self::new(SharedShape::capsule(-p, p, radius))
}
#[cfg(feature = "dim3")]
pub fn cuboid(hx: Real, hy: Real, hz: Real) -> Self {
Self::new(SharedShape::cuboid(hx, hy, hz))
}
#[cfg(feature = "dim3")]
pub fn round_cuboid(hx: Real, hy: Real, hz: Real, border_radius: Real) -> Self {
Self::new(SharedShape::round_cuboid(hx, hy, hz, border_radius))
}
pub fn segment(a: Point<Real>, b: Point<Real>) -> Self {
Self::new(SharedShape::segment(a, b))
}
pub fn triangle(a: Point<Real>, b: Point<Real>, c: Point<Real>) -> Self {
Self::new(SharedShape::triangle(a, b, c))
}
pub fn round_triangle(
a: Point<Real>,
b: Point<Real>,
c: Point<Real>,
border_radius: Real,
) -> Self {
Self::new(SharedShape::round_triangle(a, b, c, border_radius))
}
pub fn polyline(vertices: Vec<Point<Real>>, indices: Option<Vec<[u32; 2]>>) -> Self {
Self::new(SharedShape::polyline(vertices, indices))
}
pub fn trimesh(vertices: Vec<Point<Real>>, indices: Vec<[u32; 3]>) -> Self {
Self::new(SharedShape::trimesh(vertices, indices))
}
pub fn convex_decomposition(vertices: &[Point<Real>], indices: &[[u32; DIM]]) -> Self {
Self::new(SharedShape::convex_decomposition(vertices, indices))
}
pub fn round_convex_decomposition(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
border_radius: Real,
) -> Self {
Self::new(SharedShape::round_convex_decomposition(
vertices,
indices,
border_radius,
))
}
pub fn convex_decomposition_with_params(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
params: &VHACDParameters,
) -> Self {
Self::new(SharedShape::convex_decomposition_with_params(
vertices, indices, params,
))
}
pub fn round_convex_decomposition_with_params(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
params: &VHACDParameters,
border_radius: Real,
) -> Self {
Self::new(SharedShape::round_convex_decomposition_with_params(
vertices,
indices,
params,
border_radius,
))
}
pub fn convex_hull(points: &[Point<Real>]) -> Option<Self> {
SharedShape::convex_hull(points).map(|cp| Self::new(cp))
}
pub fn round_convex_hull(points: &[Point<Real>], border_radius: Real) -> Option<Self> {
SharedShape::round_convex_hull(points, border_radius).map(|cp| Self::new(cp))
}
#[cfg(feature = "dim2")]
pub fn convex_polyline(points: Vec<Point<Real>>) -> Option<Self> {
SharedShape::convex_polyline(points).map(|cp| Self::new(cp))
}
#[cfg(feature = "dim2")]
pub fn round_convex_polyline(points: Vec<Point<Real>>, border_radius: Real) -> Option<Self> {
SharedShape::round_convex_polyline(points, border_radius).map(|cp| Self::new(cp))
}
#[cfg(feature = "dim3")]
pub fn convex_mesh(points: Vec<Point<Real>>, indices: &[[u32; 3]]) -> Option<Self> {
SharedShape::convex_mesh(points, indices).map(|cp| Self::new(cp))
}
#[cfg(feature = "dim3")]
pub fn round_convex_mesh(
points: Vec<Point<Real>>,
indices: &[[u32; 3]],
border_radius: Real,
) -> Option<Self> {
SharedShape::round_convex_mesh(points, indices, border_radius).map(|cp| Self::new(cp))
}
#[cfg(feature = "dim2")]
pub fn heightfield(heights: na::DVector<Real>, scale: Vector<Real>) -> Self {
Self::new(SharedShape::heightfield(heights, scale))
}
#[cfg(feature = "dim3")]
pub fn heightfield(heights: na::DMatrix<Real>, scale: Vector<Real>) -> Self {
Self::new(SharedShape::heightfield(heights, scale))
}
pub fn default_friction() -> Real {
0.5
}
pub fn user_data(mut self, data: u128) -> Self {
self.user_data = data;
self
}
pub fn collision_groups(mut self, groups: InteractionGroups) -> Self {
self.collision_groups = groups;
self
}
pub fn solver_groups(mut self, groups: InteractionGroups) -> Self {
self.solver_groups = groups;
self
}
pub fn sensor(mut self, is_sensor: bool) -> Self {
self.is_sensor = is_sensor;
self
}
pub fn friction(mut self, friction: Real) -> Self {
self.friction = friction;
self
}
pub fn friction_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
self.friction_combine_rule = rule;
self
}
pub fn restitution(mut self, restitution: Real) -> Self {
self.restitution = restitution;
self
}
pub fn restitution_combine_rule(mut self, rule: CoefficientCombineRule) -> Self {
self.restitution_combine_rule = rule;
self
}
pub fn density(mut self, density: Real) -> Self {
self.density = Some(density);
self
}
#[cfg(feature = "dim2")]
pub fn translation(mut self, x: Real, y: Real) -> Self {
self.delta.translation.x = x;
self.delta.translation.y = y;
self
}
#[cfg(feature = "dim3")]
pub fn translation(mut self, x: Real, y: Real, z: Real) -> Self {
self.delta.translation.x = x;
self.delta.translation.y = y;
self.delta.translation.z = z;
self
}
pub fn rotation(mut self, angle: AngVector<Real>) -> Self {
self.delta.rotation = Rotation::new(angle);
self
}
pub fn position(mut self, pos: Isometry<Real>) -> Self {
self.delta = pos;
self
}
#[deprecated(note = "Use `.position` instead.")]
pub fn delta(mut self, delta: Isometry<Real>) -> Self {
self.delta = delta;
self
}
pub fn build(&self) -> Collider {
let density = self.get_density();
let mut flags = ColliderFlags::empty();
flags.set(ColliderFlags::SENSOR, self.is_sensor);
flags = flags
.with_friction_combine_rule(self.friction_combine_rule)
.with_restitution_combine_rule(self.restitution_combine_rule);
Collider {
shape: self.shape.clone(),
density,
friction: self.friction,
restitution: self.restitution,
delta: self.delta,
flags,
parent: RigidBodyHandle::invalid(),
position: Isometry::identity(),
predicted_position: Isometry::identity(),
proxy_index: crate::INVALID_USIZE,
collision_groups: self.collision_groups,
solver_groups: self.solver_groups,
user_data: self.user_data,
}
}
}