1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use na;
use shape::Segment;
use query::{PointQuery, PointProjection, RichPointQuery};
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
}
}
impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Segment<P> {
type ExtraInfo = P::Real;
#[inline]
fn project_point_with_extra_info(&self, m: &M, pt: &P, _: bool)
-> (PointProjection<P>, Self::ExtraInfo)
{
let ls_pt = m.inverse_transform_point(pt);
let ab = *self.b() - *self.a();
let ap = ls_pt - *self.a();
let ab_ap = na::dot(&ab, &ap);
let sqnab = na::norm_squared(&ab);
let proj;
let position_on_segment;
if ab_ap <= na::zero() {
position_on_segment = na::zero();
proj = m.transform_point(self.a());
}
else if ab_ap >= sqnab {
position_on_segment = na::one();
proj = m.transform_point(self.b());
}
else {
assert!(sqnab != na::zero());
position_on_segment = ab_ap / sqnab;
proj = m.transform_point(&(*self.a() + ab * position_on_segment));
}
let inside = relative_eq!(proj, *pt);
(PointProjection::new(inside, proj), position_on_segment)
}
}