From 64af4252273820b0fc3e264fed4747fecff4e368 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 2 Mar 2021 19:55:25 +0100 Subject: Add ability to set MassProperties for each ColliderBuilder Fix https://github.com/dimforge/rapier/issues/132 --- src/geometry/collider.rs | 52 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index b006f9e..68caf42 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -49,6 +49,7 @@ impl ColliderFlags { pub struct Collider { shape: SharedShape, density: Real, + mass_properties: MassProperties, pub(crate) flags: ColliderFlags, pub(crate) solver_flags: SolverFlags, pub(crate) parent: RigidBodyHandle, @@ -134,9 +135,9 @@ impl Collider { // aabb1.merged(&aabb2) // } - /// Compute the local-space mass properties of this collider. - pub fn mass_properties(&self) -> MassProperties { - self.shape.mass_properties(self.density) + /// Read the local-space mass properties of this collider. + pub fn mass_properties(&self) -> &MassProperties { + &self.mass_properties } } @@ -146,8 +147,11 @@ impl Collider { pub struct ColliderBuilder { /// The shape of the collider to be built. pub shape: SharedShape, - /// The density of the collider to be built. + /// The uniform density of the collider to be built. density: Option, + /// Overrides automatic computation of `MassProperties`. + /// If None, it will be computed based on shape and desnity. + mass_properties: Option, /// The friction coefficient of the collider to be built. pub friction: Real, /// The rule used to combine two friction coefficients. @@ -177,6 +181,7 @@ impl ColliderBuilder { Self { shape, density: None, + mass_properties: None, friction: Self::default_friction(), restitution: 0.0, delta: Isometry::identity(), @@ -456,6 +461,8 @@ impl ColliderBuilder { } /// Sets whether or not the collider built by this builder is a sensor. + /// Sensors will have a default density of zero, + /// but if you call [`Self::mass_properties`] you can assigna a mass to a sensor. pub fn sensor(mut self, is_sensor: bool) -> Self { self.is_sensor = is_sensor; self @@ -492,12 +499,22 @@ impl ColliderBuilder { self } - /// Sets the density of the collider this builder will build. + /// Sets the uniform density of the collider this builder will build. + /// This will be overridden by a call to [`Self::mass_properties`] so it only makes sense to call + /// either [`Self::density`] or [`Self::mass_properties`]. pub fn density(mut self, density: Real) -> Self { self.density = Some(density); self } + /// Sets the mass properties of the collider this builder will build. + /// If this is set, [`Self::density`] will be ignored, so it only makes sense to call + /// either [`Self::density`] or [`Self::mass_properties`]. + pub fn mass_properties(mut self, mass_properties: MassProperties) -> Self { + self.mass_properties = Some(mass_properties); + self + } + /// Sets the initial translation of the collider to be created, /// relative to the rigid-body it is attached to. #[cfg(feature = "dim2")] @@ -540,7 +557,21 @@ impl ColliderBuilder { /// Builds a new collider attached to the given rigid-body. pub fn build(&self) -> Collider { - let density = self.get_density(); + let (density, mass_properties); + if let Some(mp) = self.mass_properties { + mass_properties = mp; + + let volume = volume(&self.shape); + density = if volume == 0.0 || mp.inv_mass == 0.0 { + Real::INFINITY + } else { + mass(&mp) / volume + }; + } else { + density = self.get_density(); + mass_properties = self.shape.mass_properties(density); + } + let mut flags = ColliderFlags::empty(); flags.set(ColliderFlags::SENSOR, self.is_sensor); flags = flags @@ -555,6 +586,7 @@ impl ColliderBuilder { Collider { shape: self.shape.clone(), density, + mass_properties, friction: self.friction, restitution: self.restitution, delta: self.delta, @@ -570,3 +602,11 @@ impl ColliderBuilder { } } } + +fn volume(shape: &SharedShape) -> Real { + mass(&shape.mass_properties(1.0)) // TODO: add SharedShape::volume to parry +} + +fn mass(mp: &MassProperties) -> Real { + crate::utils::inv(mp.inv_mass) // TODO: add MassProperties::mass() to parry +} -- cgit From 0909077094774a58f2705120cec7aa0003178a03 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 5 Mar 2021 12:04:27 +0100 Subject: Use Box> instead to save on memory --- src/geometry/collider.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 68caf42..2691a1a 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -49,7 +49,8 @@ impl ColliderFlags { pub struct Collider { shape: SharedShape, density: Real, - mass_properties: MassProperties, + /// If None, use [`Self::density`] and [`SharedShape::mass_properties`]. + mass_properties: Option>, pub(crate) flags: ColliderFlags, pub(crate) solver_flags: SolverFlags, pub(crate) parent: RigidBodyHandle, @@ -135,9 +136,12 @@ impl Collider { // aabb1.merged(&aabb2) // } - /// Read the local-space mass properties of this collider. - pub fn mass_properties(&self) -> &MassProperties { - &self.mass_properties + /// Compute the local-space mass properties of this collider. + pub fn mass_properties(&self) -> MassProperties { + match &self.mass_properties { + Some(mass_properties) => **mass_properties, + None => self.shape.mass_properties(self.density), + } } } @@ -559,7 +563,7 @@ impl ColliderBuilder { pub fn build(&self) -> Collider { let (density, mass_properties); if let Some(mp) = self.mass_properties { - mass_properties = mp; + mass_properties = Some(Box::new(mp)); let volume = volume(&self.shape); density = if volume == 0.0 || mp.inv_mass == 0.0 { @@ -569,7 +573,7 @@ impl ColliderBuilder { }; } else { density = self.get_density(); - mass_properties = self.shape.mass_properties(density); + mass_properties = None; } let mut flags = ColliderFlags::empty(); -- cgit From 018cc236398ef5f6bc2022d1c9b145d76cfc88a4 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 8 Mar 2021 10:04:07 +0100 Subject: docstring/spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/collider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 2691a1a..c8d421b 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -154,7 +154,7 @@ pub struct ColliderBuilder { /// The uniform density of the collider to be built. density: Option, /// Overrides automatic computation of `MassProperties`. - /// If None, it will be computed based on shape and desnity. + /// If None, it will be computed based on shape and density. mass_properties: Option, /// The friction coefficient of the collider to be built. pub friction: Real, -- cgit From 51542331761e20fcc6ad6b9c11eaf3dad0ac9632 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 8 Mar 2021 10:04:13 +0100 Subject: docstring/spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/collider.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index c8d421b..0d42a05 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -465,8 +465,9 @@ impl ColliderBuilder { } /// Sets whether or not the collider built by this builder is a sensor. + /// /// Sensors will have a default density of zero, - /// but if you call [`Self::mass_properties`] you can assigna a mass to a sensor. + /// but if you call [`Self::mass_properties`] you can assign a mass to a sensor. pub fn sensor(mut self, is_sensor: bool) -> Self { self.is_sensor = is_sensor; self -- cgit From 22a402983cf26c2d937ee910508f448d434e9825 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 8 Mar 2021 10:04:21 +0100 Subject: docstring/spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/collider.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 0d42a05..78a6668 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -513,6 +513,7 @@ impl ColliderBuilder { } /// Sets the mass properties of the collider this builder will build. + /// /// If this is set, [`Self::density`] will be ignored, so it only makes sense to call /// either [`Self::density`] or [`Self::mass_properties`]. pub fn mass_properties(mut self, mass_properties: MassProperties) -> Self { -- cgit From 05614dc471c785fbaefeae061458694695d7b948 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 8 Mar 2021 10:04:28 +0100 Subject: docstring/spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/collider.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 78a6668..23b62fa 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -505,6 +505,7 @@ impl ColliderBuilder { } /// Sets the uniform density of the collider this builder will build. + /// /// This will be overridden by a call to [`Self::mass_properties`] so it only makes sense to call /// either [`Self::density`] or [`Self::mass_properties`]. pub fn density(mut self, density: Real) -> Self { -- cgit From 0370e7e37d2ed298561d7b9aa36ed2cbe651ea9d Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 8 Mar 2021 10:12:12 +0100 Subject: Store either density or mass properties but not both --- src/geometry/collider.rs | 63 +++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 38 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 23b62fa..593c53c 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -41,6 +41,14 @@ impl ColliderFlags { } } +#[derive(Clone)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +enum MassInfo { + /// `MassProperties` are computed with the help of [`SharedShape::mass_properties`]. + Density(Real), + MassProperties(Box), +} + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone)] /// A geometric entity that can be attached to a body so it can be affected by contacts and proximity queries. @@ -48,9 +56,7 @@ impl ColliderFlags { /// To build a new collider, use the `ColliderBuilder` structure. pub struct Collider { shape: SharedShape, - density: Real, - /// If None, use [`Self::density`] and [`SharedShape::mass_properties`]. - mass_properties: Option>, + mass_info: MassInfo, pub(crate) flags: ColliderFlags, pub(crate) solver_flags: SolverFlags, pub(crate) parent: RigidBodyHandle, @@ -115,9 +121,12 @@ impl Collider { self.solver_groups } - /// The density of this collider. - pub fn density(&self) -> Real { - self.density + /// The density of this collider, if set. + pub fn density(&self) -> Option { + match &self.mass_info { + MassInfo::Density(density) => Some(*density), + MassInfo::MassProperties(_) => None, + } } /// The geometric shape of this collider. @@ -138,9 +147,9 @@ impl Collider { /// Compute the local-space mass properties of this collider. pub fn mass_properties(&self) -> MassProperties { - match &self.mass_properties { - Some(mass_properties) => **mass_properties, - None => self.shape.mass_properties(self.density), + match &self.mass_info { + MassInfo::Density(density) => self.shape.mass_properties(*density), + MassInfo::MassProperties(mass_properties) => **mass_properties, } } } @@ -199,12 +208,6 @@ impl ColliderBuilder { } } - /// The density of the collider being built. - pub fn get_density(&self) -> Real { - let default_density = if self.is_sensor { 0.0 } else { 1.0 }; - self.density.unwrap_or(default_density) - } - /// Initialize a new collider builder with a compound shape. pub fn compound(shapes: Vec<(Isometry, SharedShape)>) -> Self { Self::new(SharedShape::compound(shapes)) @@ -564,20 +567,13 @@ impl ColliderBuilder { /// Builds a new collider attached to the given rigid-body. pub fn build(&self) -> Collider { - let (density, mass_properties); - if let Some(mp) = self.mass_properties { - mass_properties = Some(Box::new(mp)); - - let volume = volume(&self.shape); - density = if volume == 0.0 || mp.inv_mass == 0.0 { - Real::INFINITY - } else { - mass(&mp) / volume - }; + let mass_info = if let Some(mp) = self.mass_properties { + MassInfo::MassProperties(Box::new(mp)) } else { - density = self.get_density(); - mass_properties = None; - } + let default_density = if self.is_sensor { 0.0 } else { 1.0 }; + let density = self.density.unwrap_or(default_density); + MassInfo::Density(density) + }; let mut flags = ColliderFlags::empty(); flags.set(ColliderFlags::SENSOR, self.is_sensor); @@ -592,8 +588,7 @@ impl ColliderBuilder { Collider { shape: self.shape.clone(), - density, - mass_properties, + mass_info, friction: self.friction, restitution: self.restitution, delta: self.delta, @@ -609,11 +604,3 @@ impl ColliderBuilder { } } } - -fn volume(shape: &SharedShape) -> Real { - mass(&shape.mass_properties(1.0)) // TODO: add SharedShape::volume to parry -} - -fn mass(mp: &MassProperties) -> Real { - crate::utils::inv(mp.inv_mass) // TODO: add MassProperties::mass() to parry -} -- cgit