diff --git a/ncollide_geometry/query/point_internal/point_mesh.rs b/ncollide_geometry/query/point_internal/point_mesh.rs index bd3dc0a36..5fa38b175 100644 --- a/ncollide_geometry/query/point_internal/point_mesh.rs +++ b/ncollide_geometry/query/point_internal/point_mesh.rs @@ -13,8 +13,7 @@ impl PointQuery for BaseMesh E: BaseMeshElement + PointQuery + RichPointQuery { #[inline] fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection

{ - let (projection, _) = self.project_point_with_extra_info(m, point, solid); - projection + self.project_point_with_extra_info(m, point, solid).0 } #[inline] @@ -152,8 +151,7 @@ impl> PointQuery for TriMesh

{ impl> PointQuery for Polyline

{ #[inline] fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection

{ - let (projection, _) = self.project_point_with_extra_info(m, point, solid); - projection + self.project_point_with_extra_info(m, point, solid).0 } #[inline] diff --git a/ncollide_geometry/query/point_internal/point_query.rs b/ncollide_geometry/query/point_internal/point_query.rs index edbab9913..0c3fcdee3 100644 --- a/ncollide_geometry/query/point_internal/point_query.rs +++ b/ncollide_geometry/query/point_internal/point_query.rs @@ -11,6 +11,7 @@ pub struct PointProjection { impl PointProjection

{ /// Initializes a new `PointProjection`. + #[inline] pub fn new(is_inside: bool, point: P) -> PointProjection

{ PointProjection { is_inside: is_inside, @@ -22,7 +23,6 @@ impl PointProjection

{ /// Trait of objects that can be tested for point inclusion and projection. pub trait PointQuery { /// Projects a point on `self` transformed by `m`. - #[inline] fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection

; /// Computes the minimal distance between a point and `self` transformed by `m`. @@ -70,7 +70,6 @@ pub trait RichPointQuery { type ExtraInfo; /// Projects a point on `self` transformed by `m`. - #[inline] fn project_point_with_extra_info(&self, m: &M, pt: &P, solid: bool) -> (PointProjection

, Self::ExtraInfo); } diff --git a/ncollide_geometry/query/point_internal/point_segment.rs b/ncollide_geometry/query/point_internal/point_segment.rs index d1293facb..c7e3291bb 100644 --- a/ncollide_geometry/query/point_internal/point_segment.rs +++ b/ncollide_geometry/query/point_internal/point_segment.rs @@ -7,8 +7,7 @@ use math::{Point, Isometry}; impl> PointQuery for Segment

{ #[inline] fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection

{ - let (projection, _) = self.project_point_with_extra_info(m, pt, solid); - projection + self.project_point_with_extra_info(m, pt, solid).0 } // NOTE: the default implementation of `.distance_to_point(...)` will return the error that was @@ -29,29 +28,29 @@ impl> RichPointQuery for Segment

{ let sqnab = na::norm_squared(&ab); let proj; - let position_on_segment; + let bcoords; if ab_ap <= na::zero() { // Voronoï region of vertex 'a'. - position_on_segment = na::zero(); - proj = m.transform_point(self.a()); + bcoords = na::zero(); + proj = m.transform_point(self.a()); } else if ab_ap >= sqnab { // Voronoï region of vertex 'b'. - position_on_segment = na::one(); - proj = m.transform_point(self.b()); + bcoords = na::one(); + proj = m.transform_point(self.b()); } else { assert!(sqnab != na::zero()); // Voronoï region of the segment interior. - position_on_segment = ab_ap / sqnab; - proj = m.transform_point(&(*self.a() + ab * position_on_segment)); + bcoords = ab_ap / sqnab; + proj = m.transform_point(&(*self.a() + ab * bcoords)); } // FIXME: is this acceptable? let inside = relative_eq!(proj, *pt); - (PointProjection::new(inside, proj), position_on_segment) + (PointProjection::new(inside, proj), bcoords) } } diff --git a/ncollide_geometry/query/point_internal/point_triangle.rs b/ncollide_geometry/query/point_internal/point_triangle.rs index 0e7c15ce3..0e63b73f1 100644 --- a/ncollide_geometry/query/point_internal/point_triangle.rs +++ b/ncollide_geometry/query/point_internal/point_triangle.rs @@ -1,4 +1,4 @@ -use na; +use na::{self, Vector3}; use shape::Triangle; use query::{PointQuery, PointProjection, RichPointQuery}; use math::{Point, Isometry}; @@ -30,12 +30,11 @@ impl> RichPointQuery for Triangle

{ // Implementing this trait while providing no projection info might seem // nonsensical, but it actually makes it possible to complete the // `RichPointQuery` implementation for `BaseMesh`. - type ExtraInfo = (); + type ExtraInfo = Vector3; #[inline] fn project_point_with_extra_info(&self, m: &M, pt: &P, solid: bool) - -> (PointProjection

, Self::ExtraInfo) - { + -> (PointProjection

, Self::ExtraInfo) { /* * This comes from the book `Real Time Collision Detection`. * This is actually a trivial Voronoï region based approach, except that great care has @@ -57,7 +56,7 @@ impl> RichPointQuery for Triangle

{ if d1 <= na::zero() && d2 <= na::zero() { // Voronoï region of `a`. - return (compute_result(pt, m.transform_point(&a)), ()); + return (compute_result(pt, m.transform_point(&a)), Vector3::x()); } let bp = p - b; @@ -66,14 +65,15 @@ impl> RichPointQuery for Triangle

{ if d3 >= na::zero() && d4 <= d3 { // Voronoï region of `b`. - return (compute_result(pt, m.transform_point(&b)), ()); + return (compute_result(pt, m.transform_point(&b)), Vector3::y()); } let vc = d1 * d4 - d3 * d2; if vc <= na::zero() && d1 >= na::zero() && d3 <= na::zero() { // Voronoï region of `ab`. let v = d1 / (d1 - d3); - return (compute_result(pt, m.transform_point(&(a + ab * v))), ()); + let bcoords = Vector3::new(na::one::() - v, v, na::zero()); + return (compute_result(pt, m.transform_point(&(a + ab * v))), bcoords); } let cp = p - c; @@ -82,7 +82,7 @@ impl> RichPointQuery for Triangle

{ if d6 >= na::zero() && d5 <= d6 { // Voronoï region of `c`. - return (compute_result(pt, m.transform_point(&c)), ()); + return (compute_result(pt, m.transform_point(&c)), Vector3::z()); } let vb = d5 * d2 - d1 * d6; @@ -90,68 +90,73 @@ impl> RichPointQuery for Triangle

{ if vb <= na::zero() && d2 >= na::zero() && d6 <= na::zero() { // Voronoï region of `ac`. let w = d2 / (d2 - d6); - return (compute_result(pt, m.transform_point(&(a + ac * w))), ()); + let bcoords = Vector3::new(na::one::() - w, na::zero(), w); + return (compute_result(pt, m.transform_point(&(a + ac * w))), bcoords); } let va = d3 * d6 - d5 * d4; if va <= na::zero() && d4 - d3 >= na::zero() && d5 - d6 >= na::zero() { // Voronoï region of `bc`. let w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); - return (compute_result(pt, m.transform_point(&(b + (c - b) * w))), ()); + let bcoords = Vector3::new(na::zero(), na::one::() - w, w); + return (compute_result(pt, m.transform_point(&(b + (c - b) * w))), bcoords); } // Voronoï region of the face. - if na::dimension::() != 2 { + // If we work in 2d, we really are inside of the object. + if na::dimension::() != 2 || solid { let denom = na::one::() / (va + vb + vc); let v = vb * denom; let w = vc * denom; + let bcoords = Vector3::new(na::one::() - v - w, v, w); + let proj = m.transform_point(&(a + ab * v + ac * w)); + let inside = na::dimension::() == 2 || relative_eq!(proj, *pt); - return (compute_result(pt, m.transform_point(&(a + ab * v + ac * w))), ()); + (PointProjection::new(inside, proj), bcoords) } else { - // Special treatement if we work in 2d because in this case we really are inside of the - // object. - if solid { - (PointProjection::new(true, *pt), ()) + // Not-solid 2D projection. + // We have to project on the closest edge. + + // FIXME: this might be optimizable. + let v = d1 / (d1 - d3); // proj on ab = a + ab * v + let w = d2 / (d2 - d6); // proj on ac = a + ac * w + let u = (d4 - d3) / ((d4 - d3) + (d5 - d6)); // proj on bc = b + bc * u + + let bc = c - b; + let d_ab = na::norm_squared(&ap) - (na::norm_squared(&ab) * v * v); + let d_ac = na::norm_squared(&ap) - (na::norm_squared(&ac) * u * u); + let d_bc = na::norm_squared(&bp) - (na::norm_squared(&bc) * w * w); + + let proj; + let bcoords; + + if d_ab < d_ac { + if d_ab < d_bc { + // ab + proj = m.transform_point(&(a + ab * v)); + bcoords = Vector3::new(na::one::() - v, v, na::zero()); + } + else { + // bc + proj = m.transform_point(&(b + bc * u)); + bcoords = Vector3::new(na::zero(), na::one::() - v, v); + } } else { - // We have to project on the closest edge. - - // FIXME: this might be optimizable. - let v = d1 / (d1 - d3); // proj on ab = a + ab * v - let w = d2 / (d2 - d6); // proj on ac = a + ac * w - let u = (d4 - d3) / ((d4 - d3) + (d5 - d6)); // proj on bc = b + bc * u - - let bc = c - b; - let d_ab = na::norm_squared(&ap) - (na::norm_squared(&ab) * v * v); - let d_ac = na::norm_squared(&ap) - (na::norm_squared(&ac) * u * u); - let d_bc = na::norm_squared(&bp) - (na::norm_squared(&bc) * w * w); - - let proj; - - if d_ab < d_ac { - if d_ab < d_bc { - // ab - proj = m.transform_point(&(a + ab * v)); - } - else { - // bc - proj = m.transform_point(&(b + bc * u)); - } + if d_ac < d_bc { + // ac + proj = m.transform_point(&(a + ac * w)); + bcoords = Vector3::new(na::one::() - w, na::zero(), w); } else { - if d_ac < d_bc { - // ac - proj = m.transform_point(&(a + ac * w)); - } - else { - // bc - proj = m.transform_point(&(b + bc * u)); - } + // bc + proj = m.transform_point(&(b + bc * u)); + bcoords = Vector3::new(na::zero(), na::one::() - u, u); } - - (PointProjection::new(true, proj), ()) } + + (PointProjection::new(true, proj), bcoords) } } }