aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/rapier2d/Cargo.toml5
-rw-r--r--build/rapier3d/Cargo.toml6
-rw-r--r--src/dynamics/mass_properties.rs4
-rw-r--r--src/dynamics/mass_properties_capsule.rs11
-rw-r--r--src/geometry/broad_phase_multi_sap.rs16
-rw-r--r--src/geometry/collider.rs367
-rw-r--r--src/geometry/contact_generator/ball_convex_contact_generator.rs23
-rw-r--r--src/geometry/contact_generator/capsule_capsule_contact_generator.rs15
-rw-r--r--src/geometry/contact_generator/contact_dispatcher.rs78
-rw-r--r--src/geometry/contact_generator/cuboid_capsule_contact_generator.rs8
-rw-r--r--src/geometry/contact_generator/cuboid_cuboid_contact_generator.rs2
-rw-r--r--src/geometry/contact_generator/cuboid_triangle_contact_generator.rs6
-rw-r--r--src/geometry/contact_generator/heightfield_shape_contact_generator.rs35
-rw-r--r--src/geometry/contact_generator/mod.rs2
-rw-r--r--src/geometry/contact_generator/polygon_polygon_contact_generator.rs29
-rw-r--r--src/geometry/contact_generator/trimesh_shape_contact_generator.rs11
-rw-r--r--src/geometry/mod.rs12
-rw-r--r--src/geometry/narrow_phase.rs12
-rw-r--r--src/geometry/proximity_detector/ball_convex_proximity_detector.rs18
-rw-r--r--src/geometry/proximity_detector/cuboid_cuboid_proximity_detector.rs2
-rw-r--r--src/geometry/proximity_detector/cuboid_triangle_proximity_detector.rs6
-rw-r--r--src/geometry/proximity_detector/polygon_polygon_proximity_detector.rs23
-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/rounded.rs7
-rw-r--r--src/geometry/sat.rs20
-rw-r--r--src/geometry/shape.rs275
-rw-r--r--src/geometry/trimesh.rs45
-rw-r--r--src/pipeline/query_pipeline.rs12
-rw-r--r--src/utils.rs26
-rw-r--r--src_testbed/engine.rs65
31 files changed, 768 insertions, 424 deletions
diff --git a/build/rapier2d/Cargo.toml b/build/rapier2d/Cargo.toml
index 03ccd98..44038e6 100644
--- a/build/rapier2d/Cargo.toml
+++ b/build/rapier2d/Cargo.toml
@@ -22,7 +22,7 @@ simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
# enabled with the "simd-stable" or "simd-nightly" feature.
simd-is-enabled = [ ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
-serde-serialize = [ "nalgebra/serde-serialize", "ncollide2d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde", "arrayvec/serde" ]
+serde-serialize = [ "erased-serde", "nalgebra/serde-serialize", "ncollide2d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde", "arrayvec/serde" ]
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
[lib]
@@ -46,7 +46,10 @@ arrayvec = "0.5"
bit-vec = "0.6"
rustc-hash = "1"
serde = { version = "1", features = [ "derive" ], optional = true }
+erased-serde = { version = "0.3", optional = true }
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
+downcast-rs = "1.2"
+num-derive = "0.3"
[dev-dependencies]
bincode = "1"
diff --git a/build/rapier3d/Cargo.toml b/build/rapier3d/Cargo.toml
index 7a0139e..adc453c 100644
--- a/build/rapier3d/Cargo.toml
+++ b/build/rapier3d/Cargo.toml
@@ -22,7 +22,7 @@ simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
# enabled with the "simd-stable" or "simd-nightly" feature.
simd-is-enabled = [ ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
-serde-serialize = [ "nalgebra/serde-serialize", "ncollide3d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde" ]
+serde-serialize = [ "erased-serde", "nalgebra/serde-serialize", "ncollide3d/serde-serialize", "serde", "generational-arena/serde", "bit-vec/serde" ]
enhanced-determinism = [ "simba/libm_force", "indexmap" ]
[lib]
@@ -46,7 +46,11 @@ arrayvec = "0.5"
bit-vec = "0.6"
rustc-hash = "1"
serde = { version = "1", features = [ "derive" ], optional = true }
+erased-serde = { version = "0.3", optional = true }
indexmap = { version = "1", features = [ "serde-1" ], optional = true }
+downcast-rs = "1.2"
+num-derive = "0.3"
+
[dev-dependencies]
bincode = "1"
diff --git a/src/dynamics/mass_properties.rs b/src/dynamics/mass_properties.rs
index 22e7da5..d64839c 100644
--- a/src/dynamics/mass_properties.rs
+++ b/src/dynamics/mass_properties.rs
@@ -91,7 +91,7 @@ impl MassProperties {
}
#[cfg(feature = "dim3")]
- /// Reconstructs the inverse angular inertia tensor of the rigid body from its principal inertia values and axii.
+ /// Reconstructs the inverse angular inertia tensor of the rigid body from its principal inertia values and axes.
pub fn reconstruct_inverse_inertia_matrix(&self) -> Matrix3<f32> {
let inv_principal_inertia = self.inv_principal_inertia_sqrt.map(|e| e * e);
self.principal_inertia_local_frame.to_rotation_matrix()
@@ -103,7 +103,7 @@ impl MassProperties {
}
#[cfg(feature = "dim3")]
- /// Reconstructs the angular inertia tensor of the rigid body from its principal inertia values and axii.
+ /// Reconstructs the angular inertia tensor of the rigid body from its principal inertia values and axes.
pub fn reconstruct_inertia_matrix(&self) -> Matrix3<f32> {
let principal_inertia = self.inv_principal_inertia_sqrt.map(|e| utils::inv(e * e));
self.principal_inertia_local_frame.to_rotation_matrix()
diff --git a/src/dynamics/mass_properties_capsule.rs b/src/dynamics/mass_properties_capsule.rs
index 647cfc7..c4e039c 100644
--- a/src/dynamics/mass_properties_capsule.rs
+++ b/src/dynamics/mass_properties_capsule.rs
@@ -4,21 +4,19 @@ use crate::geometry::Capsule;
use crate::math::{Point, PrincipalAngularInertia, Rotation, Vector};
impl MassProperties {
- pub(crate) fn from_capsule(density: f32, a: Point<f32>, b: Point<f32>, radius: f32) -> Self {
- let half_height = (b - a).norm() / 2.0;
+ pub(crate) fn from_capsule(density: f32, half_height: f32, radius: f32) -> Self {
let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
let (ball_vol, ball_unit_i) = Self::ball_volume_unit_angular_inertia(radius);
let cap_vol = cyl_vol + ball_vol;
let cap_mass = cap_vol * density;
let mut cap_unit_i = cyl_unit_i + ball_unit_i;
- let local_com = na::center(&a, &b);
#[cfg(feature = "dim2")]
{
let h = half_height * 2.0;
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
cap_unit_i += extra;
- Self::new(local_com, cap_mass, cap_unit_i * cap_mass)
+ Self::new(Point::origin(), cap_mass, cap_unit_i * cap_mass)
}
#[cfg(feature = "dim3")]
@@ -27,12 +25,11 @@ impl MassProperties {
let extra = h * h * 0.5 + h * radius * 3.0 / 8.0;
cap_unit_i.x += extra;
cap_unit_i.z += extra;
- let local_frame = Capsule::new(a, b, radius).rotation_wrt_y();
Self::with_principal_inertia_frame(
- local_com,
+ Point::origin(),
cap_mass,
cap_unit_i * cap_mass,
- local_frame,
+ Rotation::identity(),
)
}
}
diff --git a/src/geometry/broad_phase_multi_sap.rs b/src/geometry/broad_phase_multi_sap.rs
index 8e69d24..3562c2e 100644
--- a/src/geometry/broad_phase_multi_sap.rs
+++ b/src/geometry/broad_phase_multi_sap.rs
@@ -335,7 +335,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
@@ -344,14 +344,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(),
need_update: false,
@@ -386,15 +386,15 @@ impl SAPRegion {
// Update endpoints.
let mut deleted_any = false;
for dim in 0..DIM {
- self.axii[dim].update_endpoints(dim, proxies, reporting);
- deleted_any = self.axii[dim]
+ self.axes[dim].update_endpoints(dim, proxies, reporting);
+ deleted_any = self.axes[dim]
.delete_out_of_bounds_proxies(&mut self.existing_proxies)
|| deleted_any;
}
if deleted_any {
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);
}
}
@@ -404,9 +404,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();
}
}
diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs
index fe42bd7..c6cf6d0 100644
--- a/src/geometry/collider.rs
+++ b/src/geometry/collider.rs
@@ -3,172 +3,186 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
use crate::geometry::PolygonalFeatureMap;
use crate::geometry::{
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph,
- Polygon, Proximity, Ray, RayIntersection, Triangle, Trimesh,
+ Polygon, Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh,
};
use crate::math::{AngVector, Isometry, Point, Rotation, Vector};
+use downcast_rs::{impl_downcast, DowncastSync};
+use erased_serde::Serialize;
use na::Point3;
use ncollide::bounding_volume::{HasBoundingVolume, AABB};
use ncollide::query::RayCast;
use num::Zero;
+use std::any::Any;
+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),
- #[cfg(feature = "dim3")]
- /// A cylindrical shape.
- Cylinder(Cylinder),
-}
+pub struct ColliderShape(pub Arc<dyn Shape>);
-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 Deref for ColliderShape {
+ type Target = Shape;
+ fn deref(&self) -> &Shape {
+ &*self.0
}
+}
- /// 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,
- }
+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 cuboid shape, if `self` is one.
- pub fn as_cuboid(&self) -> Option<&Cuboid> {
- match self {
- Shape::Cuboid(c) => Some(c),
- _ => 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 capsule shape, if `self` is one.
- pub fn as_capsule(&self) -> Option<&Capsule> {
- match self {
- Shape::Capsule(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 triangle mesh shape, if `self` is one.
- pub fn as_trimesh(&self) -> Option<&Trimesh> {
- match self {
- Shape::Trimesh(c) => Some(c),
- _ => None,
- }
+ /// Initialize a capsule shape aligned with the `y` axis.
+ pub fn capsule(half_height: f32, radius: f32) -> Self {
+ ColliderShape(Arc::new(Capsule::new(half_height, radius)))
}
- /// 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,
- }
+ /// 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)))
}
- /// 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,
- }
+ /// 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)))
}
- /// Gets a reference to the underlying cylindrical shape, if `self` is one.
- pub fn as_cylinder(&self) -> Option<&Cylinder> {
- match self {
- Shape::Cylinder(c) => Some(c),
- _ => None,
- }
+ /// 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)))
}
- /// gets a reference to this shape seen as a PolygonalFeatureMap.
+ /// 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 as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> {
- match self {
- Shape::Triangle(t) => Some(t),
- Shape::Cuboid(c) => Some(c),
- Shape::Cylinder(c) => Some(c),
- _ => None,
- }
+ pub fn heightfield(heights: na::DMatrix<f32>, scale: Vector<f32>) -> Self {
+ ColliderShape(Arc::new(HeightField::new(heights, scale)))
}
+}
- /// 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),
- Shape::Cylinder(cylinder) => cylinder.bounding_volume(position),
+#[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)
+#[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")
}
- 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 = "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)
- }
- #[cfg(feature = "dim3")]
- Shape::Cylinder(cylinder) => {
- cylinder.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))?;
+
+ let shape = match ShapeType::from_i32(tag) {
+ Some(ShapeType::Ball) => {
+ let shape: Ball = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ 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) => {
+ let shape: Cuboid = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ Some(ShapeType::Capsule) => {
+ let shape: Capsule = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ Some(ShapeType::Triangle) => {
+ let shape: Triangle = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ Some(ShapeType::Trimesh) => {
+ let shape: Trimesh = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ Some(ShapeType::HeightField) => {
+ let shape: HeightField = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ #[cfg(feature = "dim3")]
+ Some(ShapeType::Cylinder) => {
+ let shape: Cylinder = seq
+ .next_element()?
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
+ Arc::new(shape) as Arc<dyn Shape>
+ }
+ None => {
+ return Err(serde::de::Error::custom(
+ "found invalid shape type to deserialize",
+ ))
+ }
+ };
+
+ Ok(ColliderShape(shape))
}
}
+
+ deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {})
}
}
@@ -177,7 +191,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,
@@ -245,7 +259,7 @@ impl Collider {
/// The geometric shape of this collider.
pub fn shape(&self) -> &Shape {
- &self.shape
+ &*self.shape.0
}
/// Compute the axis-aligned bounding box of this collider.
@@ -261,23 +275,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(_) | Shape::Trimesh(_) | Shape::HeightField(_) => {
- MassProperties::zero()
- }
- Shape::Cylinder(c) => {
- MassProperties::from_cylinder(self.density, c.half_height, c.radius)
- }
- }
+ self.shape.mass_properties(self.density)
}
}
@@ -286,7 +284,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.
@@ -301,7 +299,7 @@ pub struct ColliderBuilder {
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,
@@ -320,102 +318,81 @@ 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 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(Shape::Cylinder(Cylinder::new(half_height, radius)))
+ Self::new(ColliderShape::cylinder(half_height, 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),
- };
-
- Self::new(Shape::Cuboid(cuboid))
-
- /*
- use crate::math::Point;
- let vertices = vec![
- Point::new(hx, -hy),
- Point::new(hx, hy),
- Point::new(-hx, hy),
- Point::new(-hx, -hy),
- ];
- let normals = vec![Vector::x(), Vector::y(), -Vector::x(), -Vector::y()];
- let polygon = Polygon::new(vertices, normals);
-
- Self::new(Shape::Polygon(polygon))
- */
+ Self::new(ColliderShape::cuboid(Vector::new(hx, hy)))
}
/// Initialize a new collider builder with a capsule shape aligned with the `x` axis.
pub fn capsule_x(half_height: f32, radius: f32) -> Self {
- let capsule = Capsule::new_x(half_height, radius);
- Self::new(Shape::Capsule(capsule))
+ #[cfg(feature = "dim2")]
+ let rot = -std::f32::consts::FRAC_PI_2;
+ #[cfg(feature = "dim3")]
+ let rot = Vector::z() * -std::f32::consts::FRAC_PI_2;
+ Self::new(ColliderShape::capsule(half_height, radius))
+ .position(Isometry::new(na::zero(), rot))
}
/// Initialize a new collider builder with a capsule shape aligned with the `y` axis.
pub fn capsule_y(half_height: f32, radius: f32) -> Self {
- let capsule = Capsule::new_y(half_height, radius);
- Self::new(Shape::Capsule(capsule))
+ Self::new(ColliderShape::capsule(half_height, radius))
}
/// Initialize a new collider builder with a capsule shape aligned with the `z` axis.
#[cfg(feature = "dim3")]
pub fn capsule_z(half_height: f32, radius: f32) -> Self {
- let capsule = Capsule::new_z(half_height, radius);
- Self::new(Shape::Capsule(capsule))
+ let rot = Vector::x() * std::f32::consts::FRAC_PI_2;
+ Self::new(ColliderShape::capsule(half_height, radius))
+ .position(Isometry::new(na::zero(), rot))
}
/// Initialize a new collider builder with a cuboid shape defined by its half-extents.
#[cfg(feature = "dim3")]
pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self {
- let cuboid = Cuboid {
- half_extents: Vector::new(hx, hy, hz),
- };
-
- Self::new(Shape::Cuboid(cuboid))
+ Self::new(ColliderShape::cuboid(Vector::new(hx, hy, hz)))
}
/// Initializes a collider builder with a segment shape.
///
/// A segment shape is modeled by a capsule with a 0 radius.
pub fn segment(a: Point<f32>, b: Point<f32>) -> Self {
- let capsule = Capsule::new(a, b, 0.0);
- Self::new(Shape::Capsule(capsule))
+ let (pos, half_height) = crate::utils::segment_to_capsule(&a, &b);
+ Self::new(ColliderShape::capsule(half_height, 0.0)).position(pos)
}
/// Initializes a collider builder with a triangle shape.
pub fn triangle(a: Point<f32>, b: Point<f32>, c: Point<f32>) -> Self {
- let triangle = Triangle::new(a, b, c);
- Self::new(Shape::Triangle(triangle))
+ Self::new(ColliderShape::triangle(a, b, c))
}
/// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers.
pub fn trimesh(vertices: Vec<Point<f32>>, indices: Vec<Point3<u32>>) -> Self {
- let trimesh = Trimesh::new(vertices, indices);
- Self::new(Shape::Trimesh(trimesh))
+ Self::new(ColliderShape::trimesh(vertices, indices))
}
/// Initializes a collider builder with a 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 {
- let heightfield = HeightField::new(heights, scale);
- Self::new(Shape::HeightField(heightfield))
+ Self::new(ColliderShape::heightfield(heights, scale))
}
/// Initializes a collider builder with a heightfield shape 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 {
- let heightfield = HeightField::new(heights, scale);
- Self::new(Shape::HeightField(heightfield))
+ Self::new(ColliderShape::heightfield(heights, scale))
}
/// The default friction coefficient used by the collider builder.
diff --git a/src/geometry/contact_generator/ball_convex_contact_generator.rs b/src/geometry/contact_generator/ball_convex_contact_generator.rs
index 0856029..62ebfab 100644
--- a/src/geometry/contact_generator/ball_convex_contact_generator.rs
+++ b/src/geometry/contact_generator/ball_convex_contact_generator.rs
@@ -5,30 +5,17 @@ use na::Unit;
use ncollide::query::PointQuery;
pub fn generate_contacts_ball_convex(ctxt: &mut PrimitiveContactGenerationContext) {
- if let Shape::Ball(ball1) = ctxt.shape1 {
+ if let Some(ball1) = ctxt.shap