Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions ncollide_geometry/query/point_internal/point_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ impl<P, M, I, E> PointQuery<P, M> for BaseMesh<P, I, E>
E: BaseMeshElement<I, P> + PointQuery<P, Id> + RichPointQuery<P, Id> {
#[inline]
fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
let (projection, _) = self.project_point_with_extra_info(m, point, solid);
projection
self.project_point_with_extra_info(m, point, solid).0
}

#[inline]
Expand Down Expand Up @@ -152,8 +151,7 @@ impl<P: Point, M: Isometry<P>> PointQuery<P, M> for TriMesh<P> {
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Polyline<P> {
#[inline]
fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
let (projection, _) = self.project_point_with_extra_info(m, point, solid);
projection
self.project_point_with_extra_info(m, point, solid).0
}

#[inline]
Expand Down
3 changes: 1 addition & 2 deletions ncollide_geometry/query/point_internal/point_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct PointProjection<P: Point> {

impl<P: Point> PointProjection<P> {
/// Initializes a new `PointProjection`.
#[inline]
pub fn new(is_inside: bool, point: P) -> PointProjection<P> {
PointProjection {
is_inside: is_inside,
Expand All @@ -22,7 +23,6 @@ impl<P: Point> PointProjection<P> {
/// Trait of objects that can be tested for point inclusion and projection.
pub trait PointQuery<P: Point, M> {
/// Projects a point on `self` transformed by `m`.
#[inline]
fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P>;

/// Computes the minimal distance between a point and `self` transformed by `m`.
Expand Down Expand Up @@ -70,7 +70,6 @@ pub trait RichPointQuery<P: Point, M> {
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<P>, Self::ExtraInfo);
}
19 changes: 9 additions & 10 deletions ncollide_geometry/query/point_internal/point_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use math::{Point, Isometry};
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Segment<P> {
#[inline]
fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P> {
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
Expand All @@ -29,29 +28,29 @@ impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Segment<P> {
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)
}
}
103 changes: 54 additions & 49 deletions ncollide_geometry/query/point_internal/point_triangle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use na;
use na::{self, Vector3};
use shape::Triangle;
use query::{PointQuery, PointProjection, RichPointQuery};
use math::{Point, Isometry};
Expand Down Expand Up @@ -30,12 +30,11 @@ impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Triangle<P> {
// 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<P::Real>;

#[inline]
fn project_point_with_extra_info(&self, m: &M, pt: &P, solid: bool)
-> (PointProjection<P>, Self::ExtraInfo)
{
-> (PointProjection<P>, 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
Expand All @@ -57,7 +56,7 @@ impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Triangle<P> {

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;
Expand All @@ -66,14 +65,15 @@ impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Triangle<P> {

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::<P::Real>() - v, v, na::zero());
return (compute_result(pt, m.transform_point(&(a + ab * v))), bcoords);
}

let cp = p - c;
Expand All @@ -82,76 +82,81 @@ impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Triangle<P> {

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;

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::<P::Real>() - 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::<P::Real>() - w, w);
return (compute_result(pt, m.transform_point(&(b + (c - b) * w))), bcoords);
}

// Voronoï region of the face.
if na::dimension::<P::Vector>() != 2 {
// If we work in 2d, we really are inside of the object.
if na::dimension::<P::Vector>() != 2 || solid {
let denom = na::one::<P::Real>() / (va + vb + vc);
let v = vb * denom;
let w = vc * denom;
let bcoords = Vector3::new(na::one::<P::Real>() - v - w, v, w);
let proj = m.transform_point(&(a + ab * v + ac * w));
let inside = na::dimension::<P::Vector>() == 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::<P::Real>() - v, v, na::zero());
}
else {
// bc
proj = m.transform_point(&(b + bc * u));
bcoords = Vector3::new(na::zero(), na::one::<P::Real>() - 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::<P::Real>() - 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::<P::Real>() - u, u);
}

(PointProjection::new(true, proj), ())
}

(PointProjection::new(true, proj), bcoords)
}
}
}