aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data/graph.rs10
-rw-r--r--src/data/hashmap.rs137
-rw-r--r--src/data/maybe_serializable_data.rs17
-rw-r--r--src/data/mod.rs4
-rw-r--r--src/data/pubsub.rs3
-rw-r--r--src/dynamics/joint/joint.rs1
-rw-r--r--src/dynamics/joint/joint_set.rs32
-rw-r--r--src/dynamics/mass_properties.rs23
-rw-r--r--src/dynamics/mass_properties_capsule.rs23
-rw-r--r--src/dynamics/mass_properties_cone.rs29
-rw-r--r--src/dynamics/mass_properties_cylinder.rs40
-rw-r--r--src/dynamics/mass_properties_polygon.rs2
-rw-r--r--src/dynamics/mod.rs3
-rw-r--r--src/dynamics/rigid_body.rs107
-rw-r--r--src/dynamics/rigid_body_set.rs7
-rw-r--r--src/dynamics/solver/velocity_constraint.rs9
-rw-r--r--src/dynamics/solver/velocity_constraint_wide.rs11
-rw-r--r--src/dynamics/solver/velocity_ground_constraint.rs12
-rw-r--r--src/dynamics/solver/velocity_ground_constraint_wide.rs12
-rw-r--r--src/geometry/broad_phase_multi_sap.rs150
-rw-r--r--src/geometry/capsule.rs86
-rw-r--r--src/geometry/collider.rs449
-rw-r--r--src/geometry/collider_set.rs5
-rw-r--r--src/geometry/contact.rs66
-rw-r--r--src/geometry/contact_generator/ball_ball_contact_generator.rs9
-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.rs106
-rw-r--r--src/geometry/contact_generator/contact_generator.rs30
-rw-r--r--src/geometry/contact_generator/contact_generator_workspace.rs104
-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.rs128
-rw-r--r--src/geometry/contact_generator/mod.rs18
-rw-r--r--src/geometry/contact_generator/pfm_pfm_contact_generator.rs144
-rw-r--r--src/geometry/contact_generator/polygon_polygon_contact_generator.rs35
-rw-r--r--src/geometry/contact_generator/serializable_workspace_tag.rs9
-rw-r--r--src/geometry/contact_generator/trimesh_shape_contact_generator.rs42
-rw-r--r--src/geometry/interaction_graph.rs1
-rw-r--r--src/geometry/interaction_groups.rs60
-rw-r--r--src/geometry/mod.rs33
-rw-r--r--src/geometry/narrow_phase.rs227
-rw-r--r--src/geometry/polygon.rs2
-rw-r--r--src/geometry/polygonal_feature_map.rs132
-rw-r--r--src/geometry/polyhedron_feature3d.rs169
-rw-r--r--src/geometry/proximity.rs12
-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
-rw-r--r--src/lib.rs1
-rw-r--r--src/pipeline/collision_pipeline.rs23
-rw-r--r--src/pipeline/physics_pipeline.rs11
-rw-r--r--src/pipeline/query_pipeline.rs36
-rw-r--r--src/utils.rs134
65 files changed, 2730 insertions, 916 deletions
diff --git a/src/data/graph.rs b/src/data/graph.rs
index ea27e03..de958c3 100644
--- a/src/data/graph.rs
+++ b/src/data/graph.rs
@@ -749,20 +749,12 @@ impl<N, E> IndexMut<EdgeIndex> for Graph<N, E> {
/// The walker does not borrow from the graph, so it lets you step through
/// neighbors or incident edges while also mutating graph weights, as
/// in the following example:
+#[derive(Clone)]
pub struct WalkNeighbors {
skip_start: NodeIndex,
next: [EdgeIndex; 2],
}
-impl Clone for WalkNeighbors {
- fn clone(&self) -> Self {
- WalkNeighbors {
- skip_start: self.skip_start,
- next: self.next,
- }
- }
-}
-
/// Reference to a `Graph` edge.
#[derive(Debug)]
pub struct EdgeReference<'a, E: 'a> {
diff --git a/src/data/hashmap.rs b/src/data/hashmap.rs
new file mode 100644
index 0000000..d2ea980
--- /dev/null
+++ b/src/data/hashmap.rs
@@ -0,0 +1,137 @@
+//! A hash-map that behaves deterministically when the
+//! `enhanced-determinism` feature is enabled.
+
+#[cfg(all(feature = "enhanced-determinism", feature = "serde-serialize"))]
+use indexmap::IndexMap as StdHashMap;
+#[cfg(all(not(feature = "enhanced-determinism"), feature = "serde-serialize"))]
+use std::collections::HashMap as StdHashMap;
+
+/// Serializes only the capacity of a hash-map instead of its actual content.
+#[cfg(feature = "serde-serialize")]
+pub fn serialize_hashmap_capacity<S: serde::Serializer, K, V, H: std::hash::BuildHasher>(
+ map: &StdHashMap<K, V, H>,
+ s: S,
+) -> Result<S::Ok, S::Error> {
+ s.serialize_u64(map.capacity() as u64)
+}
+
+/// Creates a new hash-map with its capacity deserialized from `d`.
+#[cfg(feature = "serde-serialize")]
+pub fn deserialize_hashmap_capacity<
+ 'de,
+ D: serde::Deserializer<'de>,
+ K,
+ V,
+ H: std::hash::BuildHasher + Default,
+>(
+ d: D,
+) -> Result<StdHashMap<K, V, H>, D::Error> {
+ struct CapacityVisitor;
+ impl<'de> serde::de::Visitor<'de> for CapacityVisitor {
+ type Value = u64;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(formatter, "an integer between 0 and 2^64")
+ }
+
+ fn visit_u64<E: serde::de::Error>(self, val: u64) -> Result<Self::Value, E> {
+ Ok(val)
+ }
+ }
+
+ let capacity = d.deserialize_u64(CapacityVisitor)? as usize;
+ Ok(StdHashMap::with_capacity_and_hasher(
+ capacity,
+ Default::default(),
+ ))
+}
+
+/*
+ * FxHasher taken from rustc_hash, except that it does not depend on the pointer size.
+ */
+#[cfg(feature = "enhanced-determinism")]
+pub type FxHashMap32<K, V> = indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<FxHasher32>>;
+#[cfg(feature = "enhanced-determinism")]
+pub use {self::FxHashMap32 as HashMap, indexmap::map::Entry};
+#[cfg(not(feature = "enhanced-determinism"))]
+pub use {rustc_hash::FxHashMap as HashMap, std::collections::hash_map::Entry};
+
+const K: u32 = 0x9e3779b9;
+
+// Same as FxHasher, but with the guarantee that the internal hash is
+// an u32 instead of something that depends on the platform.
+pub struct FxHasher32 {
+ hash: u32,
+}
+
+impl Default for FxHasher32 {
+ #[inline]
+ fn default() -> FxHasher32 {
+ FxHasher32 { hash: 0 }
+ }
+}
+
+impl FxHasher32 {
+ #[inline]
+ fn add_to_hash(&mut self, i: u32) {
+ use std::ops::BitXor;
+ self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K);
+ }
+}
+
+impl std::hash::Hasher for FxHasher32 {
+ #[inline]
+ fn write(&mut self, mut bytes: &[u8]) {
+ use std::convert::TryInto;
+ let read_u32 = |bytes: &[u8]| u32::from_ne_bytes(bytes[..4].try_into().unwrap());
+ let mut hash = FxHasher32 { hash: self.hash };
+ assert!(std::mem::size_of::<u32>() <= 8);
+ while bytes.len() >= std::mem::size_of::<u32>() {
+ hash.add_to_hash(read_u32(bytes) as u32);
+ bytes = &bytes[std::mem::size_of::<u32>()..];
+ }
+ if (std::mem::size_of::<u32>() > 4) && (bytes.len() >= 4) {
+ hash.add_to_hash(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as u32);
+ bytes = &bytes[4..];
+ }
+ if (std::mem::size_of::<u32>() > 2) && bytes.len() >= 2 {
+ hash.add_to_hash(u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as u32);
+ bytes = &bytes[2..];
+ }
+ if (std::mem::size_of::<u32>() > 1) && bytes.len() >= 1 {
+ hash.add_to_hash(bytes[0] as u32);
+ }
+ self.hash = hash.hash;
+ }
+
+ #[inline]
+ fn write_u8(&mut self, i: u8) {
+ self.add_to_hash(i as u32);
+ }
+
+ #[inline]
+ fn write_u16(&mut self, i: u16) {
+ self.add_to_hash(i as u32);
+ }
+
+ #[inline]
+ fn write_u32(&mut self, i: u32) {
+ self.add_to_hash(i as u32);
+ }
+
+ #[inline]
+ fn write_u64(&mut self, i: u64) {
+ self.add_to_hash(i as u32);
+ self.add_to_hash((i >> 32) as u32);
+ }
+
+ #[inline]
+ fn write_usize(&mut self, i: usize) {
+ self.add_to_hash(i as u32);
+ }
+
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.hash as u64
+ }
+}
diff --git a/src/data/maybe_serializable_data.rs b/src/data/maybe_serializable_data.rs
new file mode 100644
index 0000000..8b14e1a
--- /dev/null
+++ b/src/data/maybe_serializable_data.rs
@@ -0,0 +1,17 @@
+use downcast_rs::{impl_downcast, DowncastSync};
+#[cfg(feature = "serde-serialize")]
+use erased_serde::Serialize;
+
+/// Piece of data that may be serializable.
+pub trait MaybeSerializableData: DowncastSync {
+ /// Convert this shape as a serializable entity.
+ #[cfg(feature = "serde-serialize")]
+ fn as_serialize(&self) -> Option<(u32, &dyn Serialize)> {
+ None
+ }
+
+ /// Clones `self`.
+ fn clone_dyn(&self) -> Box<dyn MaybeSerializableData>;
+}
+
+impl_downcast!(sync MaybeSerializableData);
diff --git a/src/data/mod.rs b/src/data/mod.rs
index 5d3efa6..0e0459e 100644
--- a/src/data/mod.rs
+++ b/src/data/mod.rs
@@ -1,5 +1,9 @@
//! Data structures modified with guaranteed deterministic behavior after deserialization.
+pub use self::maybe_serializable_data::MaybeSerializableData;
+
pub mod arena;
pub(crate) mod graph;
+pub(crate) mod hashmap;
+mod maybe_serializable_data;
pub mod pubsub;
diff --git a/src/data/pubsub.rs b/src/data/pubsub.rs
index b2c9e27..80fb3a2 100644
--- a/src/data/pubsub.rs
+++ b/src/data/pubsub.rs
@@ -5,6 +5,7 @@ use std::marker::PhantomData;
/// A permanent subscription to a pub-sub queue.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+#[derive(Clone)]
pub struct Subscription<T> {
// Position on the cursor array.
id: u32,
@@ -12,6 +13,7 @@ pub struct Subscription<T> {
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+#[derive(Clone)]
struct PubSubCursor {
// Position on the offset array.
id: u32,
@@ -36,6 +38,7 @@ impl PubSubCursor {
/// A pub-sub queue.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+#[derive(Clone)]
pub struct PubSub<T> {
deleted_messages: u32,
deleted_offsets: u32,
diff --git a/src/dynamics/joint/joint.rs b/src/dynamics/joint/joint.rs
index 074f802..9fe6488 100644
--- a/src/dynamics/joint/joint.rs
+++ b/src/dynamics/joint/joint.rs
@@ -95,6 +95,7 @@ impl From<PrismaticJoint> for JointParams {
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
+#[derive(Clone)]
/// A joint attached to two bodies.
pub struct Joint {
/// Handle to the first body attached to this joint.
diff --git a/src/dynamics/joint/joint_set.rs b/src/dynamics/joint/joint_set.rs
index 2b1895f..5144d97 100644
--- a/src/dynamics/joint/joint_set.rs
+++ b/src/dynamics/joint/joint_set.rs
@@ -181,6 +181,38 @@ impl JointSet {
}
}
+ /// Removes a joint from this set.
+ ///
+ /// If `wake_up` is set to `true`, then the bodies attached to this joint will be
+ /// automatically woken up.
+ pub fn remove(
+ &mut self,
+ handle: JointHandle,
+ bodies: &mut RigidBodySet,
+ wake_up: bool,
+ ) -> Option<Joint> {
+ let id = self.joint_ids.remove(handle)?;
+ let endpoints = self.joint_graph.graph.edge_endpoints(id)?;
+
+ if wake_up {
+ // Wake-up the bodies attached to this joint.
+ if let Some(rb_handle) = self.joint_graph.graph.node_weight(endpoints.0) {
+ bodies.wake_up(*rb_handle, true);
+ }
+ if let Some(rb_handle) = self.joint_graph.graph.node_weight(endpoints.1) {
+ bodies.wake_up(*rb_handle, true);
+ }
+ }
+
+ let removed_joint = self.joint_graph.graph.remove_edge(id);
+
+ if let Some(edge) = self.joint_graph.graph.edge_weight(id) {
+ self.joint_ids[edge.handle] = id;
+ }
+
+ removed_joint
+ }
+
pub(crate) fn remove_rigid_body(
&mut self,
deleted_id: RigidBodyGraphIndex,
diff --git a/src/dynamics/mass_properties.rs b/src/dynamics/mass_properties.rs
index 22e7da5..73e9b0d 100644
--- a/src/dynamics/mass_properties.rs
+++ b/src/dynamics/mass_properties.rs
@@ -25,8 +25,11 @@ pub struct MassProperties {
}
impl MassProperties {
+ /// Initializes the mass properties with the given center-of-mass, mass, and angular inertia.
+ ///
+ /// The center-of-mass is specified in the local-space of the rigid-body.
#[cfg(feature = "dim2")]
- pub(crate) fn new(local_com: Point<f32>, mass: f32, principal_inertia: f32) -> Self {
+ pub fn new(local_com: Point<f32>, mass: f32, principal_inertia: f32) -> Self {
let inv_mass = utils::inv(mass);
let inv_principal_inertia_sqrt = utils::inv(principal_inertia.sqrt());
Self {
@@ -36,13 +39,23 @@ impl MassProperties {
}
}
+ /// Initializes the mass properties from the given center-of-mass, mass, and principal angular inertia.
+ ///
+ /// The center-of-mass is specified in the local-space of the rigid-body.
+ /// The principal angular inertia are the angular inertia along the coordinate axes in the local-space
+ /// of the rigid-body.
#[cfg(feature = "dim3")]
- pub(crate) fn new(local_com: Point<f32>, mass: f32, principal_inertia: AngVector<f32>) -> Self {
+ pub fn new(local_com: Point<f32>, mass: f32, principal_inertia: AngVector<f32>) -> Self {
Self::with_principal_inertia_frame(local_com, mass, principal_inertia, Rotation::identity())
}
+ /// Initializes the mass properties from the given center-of-mass, mass, and principal angular inertia.
+ ///
+ /// The center-of-mass is specified in the local-space of the rigid-body.
+ /// The principal angular inertia are the angular inertia along the coordinate axes defined by
+ /// the `principal_inertia_local_frame` expressed in the local-space of the rigid-body.
#[cfg(feature = "dim3")]
- pub(crate) fn with_principal_inertia_frame(
+ pub fn with_principal_inertia_frame(
local_com: Point<f32>,
mass: f32,
principal_inertia: AngVector<f32>,
@@ -91,7 +104,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 +116,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 5f08958..3b1b214 100644
--- a/src/dynamics/mass_properties_capsule.rs
+++ b/src/dynamics/mass_properties_capsule.rs
@@ -1,30 +1,9 @@
use crate::dynamics::MassProperties;
#[cfg(feature = "dim3")]
use crate::geometry::Capsule;
-use crate::math::{Point, PrincipalAngularInertia, Vector};
+use crate::math::Point;
impl MassProperties {
- fn cylinder_y_volume_unit_inertia(
- half_height: f32,
- radius: f32,
- ) -> (f32, PrincipalAngularInertia<f32>) {
- #[cfg(feature = "dim2")]
- {
- Self::cuboid_volume_unit_inertia(Vector::new(radius, half_height))
- }
-
- #[cfg(feature = "dim3")]
- {
- let volume = half_height * radius * radius * std::f32::consts::PI * 2.0;
- let sq_radius = radius * radius;
- let sq_height = half_height * half_height * 4.0;
- let off_principal = (sq_radius * 3.0 + sq_height) / 12.0;
-
- let inertia = Vector::new(off_principal, sq_radius / 2.0, off_principal);
- (volume, inertia)
- }
- }
-
pub(crate) fn from_capsule(density: f32, a: Point<f32>, b: Point<f32>, radius: f32) -> Self {
let half_height = (b - a).norm() / 2.0;
let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
diff --git a/src/dynamics/mass_properties_cone.rs b/src/dynamics/mass_properties_cone.rs
new file mode 100644
index 0000000..12f831f
--- /dev/null
+++ b/src/dynamics/mass_properties_cone.rs
@@ -0,0 +1,29 @@
+use crate::dynamics::MassProperties;
+use crate::math::{Point, PrincipalAngularInertia, Rotation, Vector};
+
+impl MassProperties {
+ pub(crate) fn cone_y_volume_unit_inertia(
+ half_height: f32,
+ radius: f32,
+ ) -> (f32, PrincipalAngularInertia<f32>) {
+ let volume = radius * radius * std::f32::consts::PI * half_height * 2.0 / 3.0;
+ let sq_radius = radius * radius;
+ let sq_height = half_height * half_height * 4.0;
+ let off_principal = sq_radius * 3.0 / 20.0 + sq_height * 3.0 / 5.0;
+ let principal = sq_radius * 3.0 / 10.0;
+
+ (volume, Vector::new(off_principal, principal, off_principal))
+ }
+
+ pub(crate) fn from_cone(density: f32