aboutsummaryrefslogtreecommitdiff
path: root/src/geometry
diff options
context:
space:
mode:
authorRobert Hrusecky <robert.hrusecky@utexas.edu>2020-10-29 18:09:41 -0500
committerRobert Hrusecky <robert.hrusecky@utexas.edu>2020-10-29 18:09:41 -0500
commitbcec54ef31d987cf20b493628a20777183a95f65 (patch)
treecee40c0467c04f1f02861342e20ce8223ca6d99b /src/geometry
parentdd8e25bc4756b8bd01d283b5d7e7c5daa9a1af3f (diff)
parent4b8242b9c267a9412c88793575db37f79c544ca2 (diff)
downloadrapier-bcec54ef31d987cf20b493628a20777183a95f65.tar.gz
rapier-bcec54ef31d987cf20b493628a20777183a95f65.tar.bz2
rapier-bcec54ef31d987cf20b493628a20777183a95f65.zip
Merge branch 'master' into infinite_fall_memory
Fix merge conflict resulting from "axii" spelling correction
Diffstat (limited to 'src/geometry')
-rw-r--r--src/geometry/broad_phase_multi_sap.rs16
-rw-r--r--src/geometry/capsule.rs86
-rw-r--r--src/geometry/collider.rs430
-rw-r--r--src/geometry/contact.rs50
-rw-r--r--src/geometry/contact_generator/ball_convex_contact_generator.rs23
-rw-r--r--src/geometry/contact_generator/capsule_capsule_contact_generator.rs39
-rw-r--r--src/geometry/contact_generator/contact_dispatcher.rs76
-rw-r--r--src/geometry/contact_generator/contact_generator.rs22
-rw-r--r--src/geometry/contact_generator/cuboid_capsule_contact_generator.rs11
-rw-r--r--src/geometry/contact_generator/cuboid_cuboid_contact_generator.rs4
-rw-r--r--src/geometry/contact_generator/cuboid_triangle_contact_generator.rs8
-rw-r--r--src/geometry/contact_generator/heightfield_shape_contact_generator.rs50
-rw-r--r--src/geometry/contact_generator/mod.rs13
-rw-r--r--src/geometry/contact_generator/pfm_pfm_contact_generator.rs119
-rw-r--r--src/geometry/contact_generator/polygon_polygon_contact_generator.rs35
-rw-r--r--src/geometry/contact_generator/trimesh_shape_contact_generator.rs12
-rw-r--r--src/geometry/interaction_groups.rs60
-rw-r--r--src/geometry/mod.rs33
-rw-r--r--src/geometry/narrow_phase.rs220
-rw-r--r--src/geometry/polygon.rs2
-rw-r--r--src/geometry/polygonal_feature_map.rs132
-rw-r--r--src/geometry/polyhedron_feature3d.rs155
-rw-r--r--src/geometry/proximity_detector/ball_convex_proximity_detector.rs20
-rw-r--r--src/geometry/proximity_detector/cuboid_cuboid_proximity_detector.rs4
-rw-r--r--src/geometry/proximity_detector/cuboid_triangle_proximity_detector.rs8
-rw-r--r--src/geometry/proximity_detector/polygon_polygon_proximity_detector.rs29
-rw-r--r--src/geometry/proximity_detector/proximity_detector.rs8
-rw-r--r--src/geometry/proximity_detector/proximity_dispatcher.rs40
-rw-r--r--src/geometry/proximity_detector/trimesh_shape_proximity_detector.rs11
-rw-r--r--src/geometry/round_cylinder.rs107
-rw-r--r--src/geometry/sat.rs105
-rw-r--r--src/geometry/shape.rs390
-rw-r--r--src/geometry/trimesh.rs45
-rw-r--r--src/geometry/user_callbacks.rs57
-rw-r--r--src/geometry/wquadtree.rs33
35 files changed, 1858 insertions, 595 deletions
diff --git a/src/geometry/broad_phase_multi_sap.rs b/src/geometry/broad_phase_multi_sap.rs
index db83fa3..d8a46ee 100644
--- a/src/geometry/broad_phase_multi_sap.rs
+++ b/src/geometry/broad_phase_multi_sap.rs
@@ -337,7 +337,7 @@ impl SAPAxis {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
struct SAPRegion {
- axii: [SAPAxis; DIM],
+ axes: [SAPAxis; DIM],
existing_proxies: BitVec,
#[cfg_attr(feature = "serde-serialize", serde(skip))]
to_insert: Vec<usize>, // Workspace
@@ -347,14 +347,14 @@ struct SAPRegion {
impl SAPRegion {
pub fn new(bounds: AABB<f32>) -> Self {
- let axii = [
+ let axes = [
SAPAxis::new(bounds.mins.x, bounds.maxs.x),
SAPAxis::new(bounds.mins.y, bounds.maxs.y),
#[cfg(feature = "dim3")]
SAPAxis::new(bounds.mins.z, bounds.maxs.z),
];
SAPRegion {
- axii,
+ axes,
existing_proxies: BitVec::new(),
to_insert: Vec::new(),
update_count: 0,
@@ -394,14 +394,14 @@ impl SAPRegion {
// Update endpoints.
let mut deleted = 0;
for dim in 0..DIM {
- self.axii[dim].update_endpoints(dim, proxies, reporting);
- deleted += self.axii[dim].delete_out_of_bounds_proxies(&mut self.existing_proxies);
+ self.axes[dim].update_endpoints(dim, proxies, reporting);
+ deleted += self.axes[dim].delete_out_of_bounds_proxies(&mut self.existing_proxies);
}
if deleted > 0 {
self.proxy_count -= deleted;
for dim in 0..DIM {
- self.axii[dim].delete_out_of_bounds_endpoints(&self.existing_proxies);
+ self.axes[dim].delete_out_of_bounds_endpoints(&self.existing_proxies);
}
}
@@ -411,9 +411,9 @@ impl SAPRegion {
if !self.to_insert.is_empty() {
// Insert new proxies.
for dim in 1..DIM {
- self.axii[dim].batch_insert(dim, &self.to_insert, proxies, None);
+ self.axes[dim].batch_insert(dim, &self.to_insert, proxies, None);
}
- self.axii[0].batch_insert(0, &self.to_insert, proxies, Some(reporting));
+ self.axes[0].batch_insert(0, &self.to_insert, proxies, Some(reporting));
self.to_insert.clear();
// In the rare event that all proxies leave this region in the next step, we need an
diff --git a/src/geometry/capsule.rs b/src/geometry/capsule.rs
index 0d754af..54736cc 100644
--- a/src/geometry/capsule.rs
+++ b/src/geometry/capsule.rs
@@ -1,18 +1,16 @@
-use crate::geometry::AABB;
+use crate::geometry::{Ray, RayIntersection, AABB};
use crate::math::{Isometry, Point, Rotation, Vector};
use approx::AbsDiffEq;
use na::Unit;
-use ncollide::query::{PointProjection, PointQuery};
-use ncollide::shape::{FeatureId, Segment};
+use ncollide::query::{algorithms::VoronoiSimplex, PointProjection, PointQuery, RayCast};
+use ncollide::shape::{FeatureId, Segment, SupportMap};
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
-/// A capsule shape defined as a segment with a radius.
+/// A capsule shape defined as a round segment.
pub struct Capsule {
- /// The first endpoint of the capsule.
- pub a: Point<f32>,
- /// The second enpdoint of the capsule.
- pub b: Point<f32>,
+ /// The axis and endpoint of the capsule.
+ pub segment: Segment<f32>,
/// The radius of the capsule.
pub radius: f32,
}
@@ -39,13 +37,14 @@ impl Capsule {
/// Creates a new capsule defined as the segment between `a` and `b` and with the given `radius`.
pub fn new(a: Point<f32>, b: Point<f32>, radius: f32) -> Self {
- Self { a, b, radius }
+ let segment = Segment::new(a, b);
+ Self { segment, radius }
}
/// The axis-aligned bounding box of this capsule.
pub fn aabb(&self, pos: &Isometry<f32>) -> AABB {
- let a = pos * self.a;
- let b = pos * self.b;
+ let a = pos * self.segment.a;
+ let b = pos * self.segment.b;
let mins = a.coords.inf(&b.coords) - Vector::repeat(self.radius);
let maxs = a.coords.sup(&b.coords) + Vector::repeat(self.radius);
AABB::new(mins.into(), maxs.into())
@@ -53,7 +52,7 @@ impl Capsule {
/// The height of this capsule.
pub fn height(&self) -> f32 {
- (self.b - self.a).norm()
+ (self.segment.b - self.segment.a).norm()
}
/// The half-height of this capsule.
@@ -63,17 +62,17 @@ impl Capsule {
/// The center of this capsule.
pub fn center(&self) -> Point<f32> {
- na::center(&self.a, &self.b)
+ na::center(&self.segment.a, &self.segment.b)
}
/// Creates a new capsule equal to `self` with all its endpoints transformed by `pos`.
pub fn transform_by(&self, pos: &Isometry<f32>) -> Self {
- Self::new(pos * self.a, pos * self.b, self.radius)
+ Self::new(pos * self.segment.a, pos * self.segment.b, self.radius)
}
/// The rotation `r` such that `r * Y` is collinear with `b - a`.
pub fn rotation_wrt_y(&self) -> Rotation<f32> {
- let mut dir = self.b - self.a;
+ let mut dir = self.segment.b - self.segment.a;
if dir.y < 0.0 {
dir = -dir;
}
@@ -96,24 +95,49 @@ impl Capsule {
}
}
-// impl SupportMap<f32> for Capsule {
-// fn local_support_point(&self, dir: &Vector) -> Point {
-// let dir = Unit::try_new(dir, 0.0).unwrap_or(Vector::y_axis());
-// self.local_support_point_toward(&dir)
-// }
-//
-// fn local_support_point_toward(&self, dir: &Unit<Vector>) -> Point {
-// if dir.dot(&self.a.coords) > dir.dot(&self.b.coords) {
-// self.a + **dir * self.radius
-// } else {
-// self.b + **dir * self.radius
-// }
-// }
-// }
+impl SupportMap<f32> for Capsule {
+ fn local_support_point(&self, dir: &Vector<f32>) -> Point<f32> {
+ let dir = Unit::try_new(*dir, 0.0).unwrap_or(Vector::y_axis());
+ self.local_support_point_toward(&dir)
+ }
+
+ fn local_support_point_toward(&self, dir: &Unit<Vector<f32>>) -> Point<f32> {
+ if dir.dot(&self.segment.a.coords) > dir.dot(&self.segment.b.coords) {
+ self.segment.a + **dir * self.radius
+ } else {
+ self.segment.b + **dir * self.radius
+ }
+ }
+}
+
+impl RayCast<f32> for Capsule {
+ fn toi_and_normal_with_ray(
+ &self,
+ m: &Isometry<f32>,
+ ray: &Ray,
+ max_toi: f32,
+ solid: bool,
+ ) -> Option<RayIntersection> {
+ let ls_ray = ray.inverse_transform_by(m);
+
+ ncollide::query::ray_intersection_with_support_map_with_params(
+ &Isometry::identity(),
+ self,
+ &mut VoronoiSimplex::new(),
+ &ls_ray,
+ max_toi,
+ solid,
+ )
+ .map(|mut res| {
+ res.normal = m * res.normal;
+ res
+ })
+ }
+}
// TODO: this code has been extracted from ncollide and added here
// so we can modify it to fit with our new definition of capsule.
-// Wa should find a way to avoid this code duplication.
+// We should find a way to avoid this code duplication.
impl PointQuery<f32> for Capsule {
#[inline]
fn project_point(
@@ -122,7 +146,7 @@ impl PointQuery<f32> for Capsule {
pt: &Point<f32>,
solid: bool,
) -> PointProjection<f32> {
- let seg = Segment::new(self.a, self.b);
+ let seg = Segment::new(self.segment.a, self.segment.b);
let proj = seg.project_point(m, pt, solid);
let dproj = *pt - proj.point;
diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs
index 7c293b6..f53d75a 100644
--- a/src/geometry/collider.rs
+++ b/src/geometry/collider.rs
@@ -1,145 +1,189 @@
use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
use crate::geometry::{
- Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon,
- Proximity, Ray, RayIntersection, Triangle, Trimesh,
+ Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph,
+ InteractionGroups, Proximity, Segment, Shape, ShapeType, Triangle, Trimesh,
};
+#[cfg(feature = "dim3")]
+use crate::geometry::{Cone, Cylinder, RoundCylinder};
use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
use na::Point3;
-use ncollide::bounding_volume::{HasBoundingVolume, AABB};
-use ncollide::query::RayCast;
-use num::Zero;
+use ncollide::bounding_volume::AABB;
+use std::ops::Deref;
+use std::sync::Arc;
+/// The shape of a collider.
#[derive(Clone)]
-#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
-/// An enum grouping all the possible shape of a collider.
-pub enum Shape {
- /// A ball shape.
- Ball(Ball),
- /// A convex polygon shape.
- Polygon(Polygon),
- /// A cuboid shape.
- Cuboid(Cuboid),
- /// A capsule shape.
- Capsule(Capsule),
- /// A triangle shape.
- Triangle(Triangle),
- /// A triangle mesh shape.
- Trimesh(Trimesh),
- /// A heightfield shape.
- HeightField(HeightField),
+pub struct ColliderShape(pub Arc<dyn Shape>);
+
+impl Deref for ColliderShape {
+ type Target = dyn Shape;
+ fn deref(&self) -> &dyn Shape {
+ &*self.0
+ }
}
-impl Shape {
- /// Gets a reference to the underlying ball shape, if `self` is one.
- pub fn as_ball(&self) -> Option<&Ball> {
- match self {
- Shape::Ball(b) => Some(b),
- _ => None,
- }
+impl ColliderShape {
+ /// Initialize a ball shape defined by its radius.
+ pub fn ball(radius: f32) -> Self {
+ ColliderShape(Arc::new(Ball::new(radius)))
}
- /// Gets a reference to the underlying polygon shape, if `self` is one.
- pub fn as_polygon(&self) -> Option<&Polygon> {
- match self {
- Shape::Polygon(p) => Some(p),
- _ => None,
- }
+ /// Initialize a cylindrical shape defined by its half-height
+ /// (along along the y axis) and its radius.
+ #[cfg(feature = "dim3")]
+ pub fn cylinder(half_height: f32, radius: f32) -> Self {
+ ColliderShape(Arc::new(Cylinder::new(half_height, radius)))
}
- /// Gets a reference to the underlying cuboid shape, if `self` is one.
- pub fn as_cuboid(&self) -> Option<&Cuboid> {
- match self {
- Shape::Cuboid(c) => Some(c),
- _ => None,
- }
+ /// Initialize a rounded cylindrical shape defined by its half-height
+ /// (along along the y axis), its radius, and its roundedness (the
+ /// radius of the sphere used for dilating the cylinder).
+ #[cfg(feature = "dim3")]
+ pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self {
+ ColliderShape(Arc::new(RoundCylinder::new(
+ half_height,
+ radius,
+ border_radius,
+ )))
}
- /// Gets a reference to the underlying capsule shape, if `self` is one.
- pub fn as_capsule(&self) -> Option<&Capsule> {
- match self {
- Shape::Capsule(c) => Some(c),
- _ => None,
- }
+ /// Initialize a cone shape defined by its half-height
+ /// (along along the y axis) and its basis radius.
+ #[cfg(feature = "dim3")]
+ pub fn cone(half_height: f32, radius: f32) -> Self {
+ ColliderShape(Arc::new(Cone::new(half_height, radius)))
}
- /// Gets a reference to the underlying triangle mesh shape, if `self` is one.
- pub fn as_trimesh(&self) -> Option<&Trimesh> {
- match self {
- Shape::Trimesh(c) => Some(c),
- _ => None,
- }
+ /// Initialize a cuboid shape defined by its half-extents.
+ pub fn cuboid(half_extents: Vector<f32>) -> Self {
+ ColliderShape(Arc::new(Cuboid::new(half_extents)))
}
- /// Gets a reference to the underlying heightfield shape, if `self` is one.
- pub fn as_heightfield(&self) -> Option<&HeightField> {
- match self {
- Shape::HeightField(h) => Some(h),
- _ => None,
- }
+ /// Initialize a capsule shape from its endpoints and radius.
+ pub fn capsule(a: Point<f32>, b: Point<f32>, radius: f32) -> Self {
+ ColliderShape(Arc::new(Capsule::new(a, b, radius)))
}
- /// Gets a reference to the underlying triangle shape, if `self` is one.
- pub fn as_triangle(&self) -> Option<&Triangle> {
- match self {
- Shape::Triangle(c) => Some(c),
- _ => None,
- }
+ /// Initialize a segment shape from its endpoints.
+ pub fn segment(a: Point<f32>, b: Point<f32>) -> Self {
+ ColliderShape(Arc::new(Segment::new(a, b)))
+ }
+
+ /// Initializes a triangle shape.
+ pub fn triangle(a: Point<f32>, b: Point<f32>, c: Point<f32>) -> Self {
+ ColliderShape(Arc::new(Triangle::new(a, b, c)))
}
- /// Computes the axis-aligned bounding box of this shape.
- pub fn compute_aabb(&self, position: &Isometry<f32>) -> AABB<f32> {
- match self {
- Shape::Ball(ball) => ball.bounding_volume(position),
- Shape::Polygon(poly) => poly.aabb(position),
- Shape::Capsule(caps) => caps.aabb(position),
- Shape::Cuboid(cuboid) => cuboid.bounding_volume(position),
- Shape::Triangle(triangle) => triangle.bounding_volume(position),
- Shape::Trimesh(trimesh) => trimesh.aabb(position),
- Shape::HeightField(heightfield) => heightfield.bounding_volume(position),
+ /// Initializes a triangle mesh shape defined by its vertex and index buffers.
+ pub fn trimesh(vertices: Vec<Point<f32>>, indices: Vec<Point3<u32>>) -> Self {
+ ColliderShape(Arc::new(Trimesh::new(vertices, indices)))
+ }
+
+ /// Initializes an heightfield shape defined by its set of height and a scale
+ /// factor along each coordinate axis.
+ #[cfg(feature = "dim2")]
+ pub fn heightfield(heights: na::DVector<f32>, scale: Vector<f32>) -> Self {
+ ColliderShape(Arc::new(HeightField::new(heights, scale)))
+ }
+
+ /// Initializes an heightfield shape on the x-z plane defined by its set of height and a scale
+ /// factor along each coordinate axis.
+ #[cfg(feature = "dim3")]
+ pub fn heightfield(heights: na::DMatrix<f32>, scale: Vector<f32>) -> Self {
+ ColliderShape(Arc::new(HeightField::new(heights, scale)))
+ }
+}
+
+#[cfg(feature = "serde-serialize")]
+impl serde::Serialize for ColliderShape {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use crate::serde::ser::SerializeStruct;
+
+ if let Some(ser) = self.0.as_serialize() {
+ let typ = self.0.shape_type();
+ let mut state = serializer.serialize_struct("ColliderShape", 2)?;
+ state.serialize_field("tag", &(typ as i32))?;
+ state.serialize_field("inner", ser)?;
+ state.end()
+ } else {
+ Err(serde::ser::Error::custom(
+ "Found a non-serializable custom shape.",
+ ))
}
}
+}
- /// Computes the first intersection point between a ray in this collider.
- ///
- /// Some shapes are not supported yet and will always return `None`.
- ///
- /// # Parameters
- /// - `position`: the position of this shape.
- /// - `ray`: the ray to cast.
- /// - `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively
- /// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `f32::MAX` for an unbounded ray.
- pub fn cast_ray(
- &self,
- position: &Isometry<f32>,
- ray: &Ray,
- max_toi: f32,
- ) -> Option<RayIntersection> {
- match self {
- Shape::Ball(ball) => ball.toi_and_normal_with_ray(position, ray, max_toi, true),
- Shape::Polygon(_poly) => None,
- Shape::Capsule(caps) => {
- let pos = position * caps.transform_wrt_y();
- let caps = ncollide::shape::Capsule::new(caps.half_height(), caps.radius);
- caps.toi_and_normal_with_ray(&pos, ray, max_toi, true)
- }
- Shape::Cuboid(cuboid) => cuboid.toi_and_normal_with_ray(position, ray, max_toi, true),
- #[cfg(feature = "dim2")]
- Shape::Triangle(_) | Shape::Trimesh(_) => {
- // This is not implemented yet in 2D.
- None
+#[cfg(feature = "serde-serialize")]
+impl<'de> serde::Deserialize<'de> for ColliderShape {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct Visitor {};
+ impl<'de> serde::de::Visitor<'de> for Visitor {
+ type Value = ColliderShape;
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(formatter, "one shape type tag and the inner shape data")
}
- #[cfg(feature = "dim3")]
- Shape::Triangle(triangle) => {
- triangle.toi_and_normal_with_ray(position, ray, max_toi, true)
- }
- #[cfg(feature = "dim3")]
- Shape::Trimesh(trimesh) => {
- trimesh.toi_and_normal_with_ray(position, ray, max_toi, true)
- }
- Shape::HeightField(heightfield) => {
- heightfield.toi_and_normal_with_ray(position, ray, max_toi, true)
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: serde::de::SeqAccess<'de>,
+ {
+ use num::cast::FromPrimitive;
+
+ let tag: i32 = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+
+ fn deser<'de, A, S: Shape + serde::Deserialize<'de>>(
+ seq: &mut A,
+ ) -> Result<Arc<dyn Shape>, A::Error>
+ where
+ A: serde::de::SeqAccess<'de>,
+ {
+ let shape: S = seq.next_element()?.ok_or_else(|| {
+ serde::de::Error::custom("Failed to deserialize builtin shape.")
+ })?;
+ Ok(Arc::new(shape) as Arc<dyn Shape>)
+ }
+
+ let shape = match ShapeType::from_i32(tag) {
+ Some(ShapeType::Ball) => deser::<A, Ball>(&mut seq)?,
+ Some(ShapeType::Polygon) => {
+ unimplemented!()
+ // let shape: Polygon = seq
+ // .next_element()?
+ // .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ // Arc::new(shape) as Arc<dyn Shape>
+ }
+ Some(ShapeType::Cuboid) => deser::<A, Cuboid>(&mut seq)?,
+ Some(ShapeType::Capsule) => deser::<A, Capsule>(&mut seq)?,
+ Some(ShapeType::Triangle) => deser::<A, Triangle>(&mut seq)?,
+ Some(ShapeType::Segment) => deser::<A, Segment>(&mut seq)?,
+ Some(ShapeType::Trimesh) => deser::<A, Trimesh>(&mut seq)?,
+ Some(ShapeType::HeightField) => deser::<A, HeightField>(&mut seq)?,
+ #[cfg(feature = "dim3")]
+ Some(ShapeType::Cylinder) => deser::<A, Cylinder>(&mut seq)?,
+ #[cfg(feature = "dim3")]
+ Some(ShapeType::Cone) => deser::<A, Cone>(&mut seq)?,
+ #[cfg(feature = "dim3")]
+ Some(ShapeType::RoundCylinder) => deser::<A, RoundCylinder>(&mut seq)?,
+ None => {
+ return Err(serde::de::Error::custom(
+ "found invalid shape type to deserialize",
+ ))
+ }
+ };
+
+ Ok(ColliderShape(shape))
}
}
+
+ deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {})
}
}
@@ -148,7 +192,7 @@ impl Shape {
///
/// To build a new collider, use the `ColliderBuilder` structure.
pub struct Collider {
- shape: Shape,
+ shape: ColliderShape,
density: f32,
is_sensor: bool,
pub(crate) parent: RigidBodyHandle,
@@ -159,9 +203,13 @@ pub struct Collider {
pub friction: f32,
/// The restitution coefficient of this collider.
pub restitution: f32,
+ pub(crate) collision_groups: InteractionGroups,
+ pub(crate) solver_groups: InteractionGroups,
pub(crate) contact_graph_index: ColliderGraphIndex,
pub(crate) proximity_graph_index: ColliderGraphIndex,
pub(crate) proxy_index: usize,
+ /// User-defined data associated to this rigid-body.
+ pub user_data: u128,
}
impl Clone for Collider {
@@ -209,14 +257,24 @@ impl Collider {
&self.delta
}
+ /// The collision groups used by this collider.
+ pub fn collision_groups(&self) -> InteractionGroups {
+ self.collision_groups
+ }
+
+ /// The solver groups used by this collider.
+ pub fn solver_groups(&self) -> InteractionGroups {
+ self.solver_groups
+ }
+
/// The density of this collider.
pub fn density(&self) -> f32 {
self.density
}
/// The geometric shape of this collider.
- pub fn shape(&self) -> &Shape {
- &self.shape
+ pub fn shape(&self) -> &dyn Shape {
+ &*self.shape.0
}
/// Compute the axis-aligned bounding box of this collider.
@@ -232,20 +290,7 @@ impl Collider {
/// Compute the local-space mass properties of this collider.
pub fn mass_properties(&self) -> MassProperties {
- match &self.shape {
- Shape::Ball(ball) => MassProperties::from_ball(self.density, ball.radius),
- #[cfg(feature = "dim2")]
- Shape::Polygon(p) => MassProperties::from_polygon(self.density, p.vertices()),
- #[cfg(feature = "dim3")]
- Shape::Polygon(_p) => unimplemented!(),
- Shape::Cuboid(c) => MassProperties::from_cuboid(self.density, c.half_extents),
- Shape::Capsule(caps) => {
- MassProperties::from_capsule(self.density, caps.a, caps.b, caps.radius)
- }
- Shape::Triangle(_) => MassProperties::zero(),
- Shape::Trimesh(_) => MassProperties::zero(),
- Shape::HeightField(_) => MassProperties::zero(),
- }
+ self.shape.mass_properties(self.density)
}
}
@@ -254,7 +299,7 @@ impl Collider {
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ColliderBuilder {
/// The shape of the collider to be built.
- pub shape: Shape,
+ pub shape: ColliderShape,
/// The density of the collider to be built.
density: Option<f32>,
/// The friction coefficient of the collider to be built.
@@ -265,11 +310,17 @@ pub struct ColliderBuilder {
pub delta: Isometry<f32>,
/// Is this collider a sensor?
pub is_sensor: bool,
+ /// The user-data of the collider being built.
+ pub user_data: u128,
+ /// The collision groups for the collider being built.
+ pub collision_groups: InteractionGroups,
+ /// The solver groups for the collider being built.
+ pub solver_groups: InteractionGroups,
}
impl ColliderBuilder {
/// Initialize a new collider builder with the given shape.
- pub fn new(shape: Shape) -> Self {
+ pub fn new(shape: ColliderShape) -> Self {
Self {
shape,
density: None,
@@ -277,6 +328,9 @@ impl ColliderBuilder {
restitution: 0.0,
delta: Isometry::identity(),
is_sensor: false,
+ user_data: 0,
+ collision_groups: InteractionGroups::all(),
+ solver_groups: InteractionGroups::all(),
}
}
@@ -288,96 +342,93 @@ impl ColliderBuilder {
/// Initialize a new collider builder with a ball shape defined by its radius.
pub fn ball(radius: f32) -> Self {
- Self::new(Shape::Ball(Ball::new(radius)))
+ Self::new(ColliderShape::ball(radius))
}
- /// Initialize a new collider builder with a cuboid shape defined by its half-extents.
- #[cfg(feature = "dim2")]
- pub fn cuboid(hx: f32, hy: f32) -> Self {
- let cuboid = Cuboid {
- half_extents: Vector::new(hx, hy),
- };
+ /// Initialize a new collider builder with a cylindrical shape defined by its half-height
+ /// (along along the y axis) and its radius.
+ #[cfg(feature = "dim3")]
+ pub fn cylinder(half_height: f32, radius: f32) -> Self {
+ Self::new(ColliderShape::cylinder(half_height, radius))
+ }
- Self::new(Shape::Cuboid(cuboid))
+ /// Initialize a new collider builder with a rounded cylindrical shape defined by its half-height
+ /// (along along the y axis), its radius, and its roundedness (the
+ /// radius of the sphere used for dilating the cylinder).
+ #[cfg(feature = "dim3")]
+ pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self {
+ Self::new(ColliderShape::round_cylinder(
+ half_height,
+ radius,
+ border_radius,
+ ))