From 8c872dc0af9ece127a87b4adb112b0e1ed6ab249 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 09:20:40 +0100 Subject: Replace the Rounded type by a non-generic RoundCylinder type. --- src/geometry/collider.rs | 17 +-- .../contact_generator/pfm_pfm_contact_generator.rs | 18 ++-- src/geometry/mod.rs | 4 +- src/geometry/round_cylinder.rs | 108 +++++++++++++++++++ src/geometry/rounded.rs | 118 --------------------- src/geometry/shape.rs | 22 ++-- 6 files changed, 140 insertions(+), 147 deletions(-) create mode 100644 src/geometry/round_cylinder.rs delete mode 100644 src/geometry/rounded.rs (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index d4f685c..522f002 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -4,7 +4,7 @@ use crate::geometry::{ Segment, Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] -use crate::geometry::{Cone, Cylinder, Rounded}; +use crate::geometry::{Cone, Cylinder, RoundCylinder}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; use na::Point3; use ncollide::bounding_volume::AABB; @@ -39,10 +39,11 @@ impl ColliderShape { /// (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, round_radius: f32) -> Self { - ColliderShape(Arc::new(Rounded::new( - Cylinder::new(half_height, radius), - round_radius, + pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self { + ColliderShape(Arc::new(RoundCylinder::new( + half_height, + radius, + border_radius, ))) } @@ -170,7 +171,7 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { #[cfg(feature = "dim3")] Some(ShapeType::Cone) => deser::(&mut seq)?, #[cfg(feature = "dim3")] - Some(ShapeType::RoundCylinder) => deser::>(&mut seq)?, + Some(ShapeType::RoundCylinder) => deser::(&mut seq)?, None => { return Err(serde::de::Error::custom( "found invalid shape type to deserialize", @@ -332,11 +333,11 @@ impl ColliderBuilder { /// (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, round_radius: f32) -> Self { + pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self { Self::new(ColliderShape::round_cylinder( half_height, radius, - round_radius, + border_radius, )) } diff --git a/src/geometry/contact_generator/pfm_pfm_contact_generator.rs b/src/geometry/contact_generator/pfm_pfm_contact_generator.rs index 62a38ae..1dcae33 100644 --- a/src/geometry/contact_generator/pfm_pfm_contact_generator.rs +++ b/src/geometry/contact_generator/pfm_pfm_contact_generator.rs @@ -24,11 +24,11 @@ impl Default for PfmPfmContactManifoldGeneratorWorkspace { } pub fn generate_contacts_pfm_pfm(ctxt: &mut PrimitiveContactGenerationContext) { - if let (Some((pfm1, round_radius1)), Some((pfm2, round_radius2))) = ( + if let (Some((pfm1, border_radius1)), Some((pfm2, border_radius2))) = ( ctxt.shape1.as_polygonal_feature_map(), ctxt.shape2.as_polygonal_feature_map(), ) { - do_generate_contacts(pfm1, round_radius1, pfm2, round_radius2, ctxt); + do_generate_contacts(pfm1, border_radius1, pfm2, border_radius2, ctxt); ctxt.manifold.update_warmstart_multiplier(); ctxt.manifold.sort_contacts(ctxt.prediction_distance); } @@ -36,9 +36,9 @@ pub fn generate_contacts_pfm_pfm(ctxt: &mut PrimitiveContactGenerationContext) { fn do_generate_contacts( pfm1: &dyn PolygonalFeatureMap, - round_radius1: f32, + border_radius1: f32, pfm2: &dyn PolygonalFeatureMap, - round_radius2: f32, + border_radius2: f32, ctxt: &mut PrimitiveContactGenerationContext, ) { let pos12 = ctxt.position1.inverse() * ctxt.position2; @@ -61,7 +61,7 @@ fn do_generate_contacts( .downcast_mut() .expect("Invalid workspace type, expected a PfmPfmContactManifoldGeneratorWorkspace."); - let total_prediction = ctxt.prediction_distance + round_radius1 + round_radius2; + let total_prediction = ctxt.prediction_distance + border_radius1 + border_radius2; let contact = query::contact_support_map_support_map_with_params( &Isometry::identity(), pfm1, @@ -93,11 +93,11 @@ fn do_generate_contacts( ctxt.manifold, ); - if round_radius1 != 0.0 || round_radius2 != 0.0 { + if border_radius1 != 0.0 || border_radius2 != 0.0 { for contact in &mut ctxt.manifold.points { - contact.local_p1 += *normal1 * round_radius1; - contact.local_p2 += *normal2 * round_radius2; - contact.dist -= round_radius1 + round_radius2; + contact.local_p1 += *normal1 * border_radius1; + contact.local_p2 += *normal2 * border_radius2; + contact.dist -= border_radius1 + border_radius2; } } diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index a3423dd..2d8fc76 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -19,7 +19,7 @@ pub use self::narrow_phase::NarrowPhase; pub use self::polygon::Polygon; pub use self::proximity::ProximityPair; pub use self::proximity_detector::{DefaultProximityDispatcher, ProximityDispatcher}; -pub use self::rounded::{Roundable, Rounded}; +pub use self::round_cylinder::RoundCylinder; pub use self::trimesh::Trimesh; pub use ncollide::query::Proximity; @@ -98,5 +98,5 @@ mod wquadtree; mod capsule; #[cfg(feature = "dim3")] mod polygonal_feature_map; -mod rounded; +mod round_cylinder; mod shape; diff --git a/src/geometry/round_cylinder.rs b/src/geometry/round_cylinder.rs new file mode 100644 index 0000000..4e2afa7 --- /dev/null +++ b/src/geometry/round_cylinder.rs @@ -0,0 +1,108 @@ +#[cfg(feature = "dim3")] +use crate::geometry::Cylinder; +use crate::math::{Isometry, Point, Vector}; +use na::Unit; +use ncollide::query::{ + algorithms::VoronoiSimplex, PointProjection, PointQuery, Ray, RayCast, RayIntersection, +}; +use ncollide::shape::{FeatureId, SupportMap}; + +/// A rounded cylinder. +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug)] +pub struct RoundCylinder { + /// The cylinder being rounded. + pub cylinder: Cylinder, + /// The rounding radius. + pub border_radius: f32, +} + +impl RoundCylinder { + /// Create sa new cylinder where all its edges and vertices are rounded by a radius of `radius`. + /// + /// This is done by applying a dilation of the given radius to the cylinder. + pub fn new(half_height: f32, radius: f32, border_radius: f32) -> Self { + Self { + cylinder: Cylinder::new(half_height, radius), + border_radius, + } + } +} + +impl SupportMap for RoundCylinder { + fn local_support_point(&self, dir: &Vector) -> Point { + self.local_support_point_toward(&Unit::new_normalize(*dir)) + } + + fn local_support_point_toward(&self, dir: &Unit>) -> Point { + self.cylinder.local_support_point_toward(dir) + **dir * self.border_radius + } + + fn support_point(&self, transform: &Isometry, dir: &Vector) -> Point { + let local_dir = transform.inverse_transform_vector(dir); + transform * self.local_support_point(&local_dir) + } + + fn support_point_toward( + &self, + transform: &Isometry, + dir: &Unit>, + ) -> Point { + let local_dir = Unit::new_unchecked(transform.inverse_transform_vector(dir)); + transform * self.local_support_point_toward(&local_dir) + } +} + +impl RayCast for RoundCylinder { + fn toi_and_normal_with_ray( + &self, + m: &Isometry, + ray: &Ray, + max_toi: f32, + solid: bool, + ) -> Option> { + 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: if PointQuery had a `project_point_with_normal` method, we could just +// call this and adjust the projected point accordingly. +impl PointQuery for RoundCylinder { + #[inline] + fn project_point( + &self, + m: &Isometry, + point: &Point, + solid: bool, + ) -> PointProjection { + ncollide::query::point_projection_on_support_map( + m, + self, + &mut VoronoiSimplex::new(), + point, + solid, + ) + } + + #[inline] + fn project_point_with_feature( + &self, + m: &Isometry, + point: &Point, + ) -> (PointProjection, FeatureId) { + (self.project_point(m, point, false), FeatureId::Unknown) + } +} diff --git a/src/geometry/rounded.rs b/src/geometry/rounded.rs deleted file mode 100644 index bfbab3b..0000000 --- a/src/geometry/rounded.rs +++ /dev/null @@ -1,118 +0,0 @@ -#[cfg(feature = "dim3")] -use crate::geometry::Cylinder; -use crate::geometry::ShapeType; -use crate::math::{Isometry, Point, Vector}; -use na::Unit; -use ncollide::query::{ - algorithms::VoronoiSimplex, PointProjection, PointQuery, Ray, RayCast, RayIntersection, -}; -use ncollide::shape::{FeatureId, SupportMap}; - -/// A shape which corner can be rounded. -pub trait Roundable { - /// The ShapeType fo this shape after rounding its corners. - fn rounded_shape_type() -> ShapeType; -} - -#[cfg(feature = "dim3")] -impl Roundable for Cylinder { - fn rounded_shape_type() -> ShapeType { - ShapeType::RoundCylinder - } -} - -/// A rounded shape. -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -pub struct Rounded { - /// The shape being rounded. - pub shape: S, - /// The rounding radius. - pub radius: f32, -} - -impl Rounded { - /// Create sa new shape where all its edges and vertices are rounded by a radius of `radius`. - /// - /// This is done by applying a dilation of the given radius to the shape. - pub fn new(shape: S, radius: f32) -> Self { - Self { shape, radius } - } -} - -impl> SupportMap for Rounded { - fn local_support_point(&self, dir: &Vector) -> Point { - self.local_support_point_toward(&Unit::new_normalize(*dir)) - } - - fn local_support_point_toward(&self, dir: &Unit>) -> Point { - self.shape.local_support_point_toward(dir) + **dir * self.radius - } - - fn support_point(&self, transform: &Isometry, dir: &Vector) -> Point { - let local_dir = transform.inverse_transform_vector(dir); - transform * self.local_support_point(&local_dir) - } - - fn support_point_toward( - &self, - transform: &Isometry, - dir: &Unit>, - ) -> Point { - let local_dir = Unit::new_unchecked(transform.inverse_transform_vector(dir)); - transform * self.local_support_point_toward(&local_dir) - } -} - -impl> RayCast for Rounded { - fn toi_and_normal_with_ray( - &self, - m: &Isometry, - ray: &Ray, - max_toi: f32, - solid: bool, - ) -> Option> { - 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: if PointQuery had a `project_point_with_normal` method, we could just -// call this and adjust the projected point accordingly. -impl> PointQuery for Rounded { - #[inline] - fn project_point( - &self, - m: &Isometry, - point: &Point, - solid: bool, - ) -> PointProjection { - ncollide::query::point_projection_on_support_map( - m, - self, - &mut VoronoiSimplex::new(), - point, - solid, - ) - } - - #[inline] - fn project_point_with_feature( - &self, - m: &Isometry, - point: &Point, - ) -> (PointProjection, FeatureId) { - (self.project_point(m, point, false), FeatureId::Unknown) - } -} diff --git a/src/geometry/shape.rs b/src/geometry/shape.rs index 8f40fd4..982e484 100644 --- a/src/geometry/shape.rs +++ b/src/geometry/shape.rs @@ -1,6 +1,6 @@ use crate::dynamics::MassProperties; use crate::geometry::{ - Ball, Capsule, Cuboid, HeightField, Roundable, Rounded, Segment, Triangle, Trimesh, + Ball, Capsule, Cuboid, HeightField, RoundCylinder, Segment, Triangle, Trimesh, }; use crate::math::Isometry; use downcast_rs::{impl_downcast, DowncastSync}; @@ -132,11 +132,8 @@ impl dyn Shape { } /// Converts this abstract shape to a cone, if it is one. - pub fn as_rounded(&self) -> Option<&Rounded> - where - S: Roundable, - Rounded: Shape, - { + #[cfg(feature = "dim3")] + pub fn as_round_cylinder(&self) -> Option<&RoundCylinder> { self.downcast_ref() } } @@ -364,19 +361,21 @@ impl Shape for Cone { } #[cfg(feature = "dim3")] -impl Shape for Rounded { +impl Shape for RoundCylinder { #[cfg(feature = "serde-serialize")] fn as_serialize(&self) -> Option<&dyn Serialize> { Some(self as &dyn Serialize) } fn compute_aabb(&self, position: &Isometry) -> AABB { - self.shape.compute_aabb(position).loosened(self.radius) + self.cylinder + .compute_aabb(position) + .loosened(self.border_radius) } fn mass_properties(&self, density: f32) -> MassProperties { // We ignore the margin here. - self.shape.mass_properties(density) + self.cylinder.mass_properties(density) } fn shape_type(&self) -> ShapeType { @@ -385,6 +384,9 @@ impl Shape for Rounded { #[cfg(feature = "dim3")] fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, f32)> { - Some((&self.shape as &dyn PolygonalFeatureMap, self.radius)) + Some(( + &self.cylinder as &dyn PolygonalFeatureMap, + self.border_radius, + )) } } -- cgit