use num::Zero; use alga::general::Id; use na; use query::algorithms::gjk; use query::algorithms::{Simplex, JohnsonSimplex, VoronoiSimplex2, VoronoiSimplex3}; use query::{Ray, RayCast, RayIntersection}; use shape::{Capsule, Cone, ConvexHull, Cylinder, MinkowskiSum, Segment, SupportMap}; use math::{Isometry, Point}; /// Cast a ray on a shape using the GJK algorithm. pub fn implicit_toi_and_normal_with_ray( m: &M, shape: &G, simplex: &mut S, ray: &Ray

, solid: bool, ) -> Option> where P: Point, M: Isometry

, S: Simplex

, G: SupportMap, { let inter = gjk::cast_ray(m, shape, simplex, ray); if !solid { match inter { None => None, Some((toi, normal)) => { if toi.is_zero() { // the ray is inside of the shape. let ndir = na::normalize(&ray.dir); let supp = shape.support_point(m, &ndir); let shift = na::dot(&(supp - ray.origin), &ndir) + na::convert(0.001f64); let new_ray = Ray::new(ray.origin + ndir * shift, -ray.dir); // FIXME: replace by? : simplex.translate_by(&(ray.origin - new_ray.origin)); simplex.reset(supp + (-new_ray.origin.coordinates())); gjk::cast_ray(m, shape, simplex, &new_ray) .map(|(toi, normal)| RayIntersection::new(shift - toi, normal)) } else { Some(RayIntersection::new(toi, normal)) } } } } else { inter.map(|(toi, normal)| RayIntersection::new(toi, normal)) } } impl RayCast for Cylinder where P: Point, M: Isometry

, { fn toi_and_normal_with_ray( &self, m: &M, ray: &Ray

, solid: bool, ) -> Option> { let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } } impl RayCast for Cone where P: Point, M: Isometry

, { fn toi_and_normal_with_ray( &self, m: &M, ray: &Ray

, solid: bool, ) -> Option> { let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } } impl RayCast for Capsule where P: Point, M: Isometry

, { fn toi_and_normal_with_ray( &self, m: &M, ray: &Ray

, solid: bool, ) -> Option> { let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } } impl RayCast for ConvexHull

where P: Point, M: Isometry

, { fn toi_and_normal_with_ray( &self, m: &M, ray: &Ray

, solid: bool, ) -> Option> { let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } } impl RayCast for Segment

where P: Point, M: Isometry

, { fn toi_and_normal_with_ray( &self, m: &M, ray: &Ray

, solid: bool, ) -> Option> { // XXX: optimize if na::dimension::

() == 2 let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } } impl<'a, P, M, M2, G1: ?Sized, G2: ?Sized> RayCast for MinkowskiSum<'a, M, G1, G2> where P: Point, M2: Isometry

, G1: SupportMap, G2: SupportMap, { fn toi_and_normal_with_ray( &self, m: &M2, ray: &Ray

, solid: bool, ) -> Option> { let ls_ray = ray.inverse_transform_by(m); if na::dimension::() == 2 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex2::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else if na::dimension::() == 3 { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut VoronoiSimplex3::

::new(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } else { implicit_toi_and_normal_with_ray( &Id::new(), self, &mut JohnsonSimplex::

::new_w_tls(), &ls_ray, solid, ).map(|mut res| { res.normal = m.rotate_vector(&res.normal); res }) } } }