diff options
| author | Crozet Sébastien <developer@crozet.re> | 2020-10-27 09:20:40 +0100 |
|---|---|---|
| committer | Crozet Sébastien <developer@crozet.re> | 2020-10-27 09:20:44 +0100 |
| commit | 8c872dc0af9ece127a87b4adb112b0e1ed6ab249 (patch) | |
| tree | 309c79a7cf538e47218c92a90784bd1a2c3c04d7 /src/geometry/round_cylinder.rs | |
| parent | dbdd797d5934ee76b0358b6cf845575ce0ef29af (diff) | |
| download | rapier-8c872dc0af9ece127a87b4adb112b0e1ed6ab249.tar.gz rapier-8c872dc0af9ece127a87b4adb112b0e1ed6ab249.tar.bz2 rapier-8c872dc0af9ece127a87b4adb112b0e1ed6ab249.zip | |
Replace the Rounded<S> type by a non-generic RoundCylinder type.
Diffstat (limited to 'src/geometry/round_cylinder.rs')
| -rw-r--r-- | src/geometry/round_cylinder.rs | 108 |
1 files changed, 108 insertions, 0 deletions
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<f32> for RoundCylinder { + fn local_support_point(&self, dir: &Vector<f32>) -> Point<f32> { + self.local_support_point_toward(&Unit::new_normalize(*dir)) + } + + fn local_support_point_toward(&self, dir: &Unit<Vector<f32>>) -> Point<f32> { + self.cylinder.local_support_point_toward(dir) + **dir * self.border_radius + } + + fn support_point(&self, transform: &Isometry<f32>, dir: &Vector<f32>) -> Point<f32> { + let local_dir = transform.inverse_transform_vector(dir); + transform * self.local_support_point(&local_dir) + } + + fn support_point_toward( + &self, + transform: &Isometry<f32>, + dir: &Unit<Vector<f32>>, + ) -> Point<f32> { + let local_dir = Unit::new_unchecked(transform.inverse_transform_vector(dir)); + transform * self.local_support_point_toward(&local_dir) + } +} + +impl RayCast<f32> for RoundCylinder { + fn toi_and_normal_with_ray( + &self, + m: &Isometry<f32>, + ray: &Ray<f32>, + max_toi: f32, + solid: bool, + ) -> Option<RayIntersection<f32>> { + 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<f32> for RoundCylinder { + #[inline] + fn project_point( + &self, + m: &Isometry<f32>, + point: &Point<f32>, + solid: bool, + ) -> PointProjection<f32> { + ncollide::query::point_projection_on_support_map( + m, + self, + &mut VoronoiSimplex::new(), + point, + solid, + ) + } + + #[inline] + fn project_point_with_feature( + &self, + m: &Isometry<f32>, + point: &Point<f32>, + ) -> (PointProjection<f32>, FeatureId) { + (self.project_point(m, point, false), FeatureId::Unknown) + } +} |
