From 64958470950cd9832a669b1bd5d70a2aeb6a85ef Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 15:57:54 +0200 Subject: Add rounded cylinder. --- src/geometry/rounded.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) (limited to 'src/geometry/rounded.rs') diff --git a/src/geometry/rounded.rs b/src/geometry/rounded.rs index 615d408..59c6a72 100644 --- a/src/geometry/rounded.rs +++ b/src/geometry/rounded.rs @@ -1,7 +1,115 @@ +use crate::geometry::{Cylinder, 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; +} + +impl Roundable for Cylinder { + fn rounded_shape_type() -> ShapeType { + ShapeType::RoundedCylinder + } +} + /// A rounded shape. -pub struct Rounded { +#[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) + } +} -- cgit