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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::math::{Isometry, Point};
use crate::query::{PointProjection, PointQuery, PointQueryWithLocation};
use crate::shape::{FeatureId, Segment, SegmentPointLocation};
use na::{self, RealField};
impl<N: RealField> PointQuery<N> for Segment<N> {
#[inline]
fn project_point(&self, m: &Isometry<N>, pt: &Point<N>, solid: bool) -> PointProjection<N> {
let (projection, _) = self.project_point_with_location(m, pt, solid);
projection
}
#[inline]
fn project_point_with_feature(
&self,
m: &Isometry<N>,
pt: &Point<N>,
) -> (PointProjection<N>, FeatureId) {
let (proj, loc) = self.project_point_with_location(m, pt, false);
let feature = match loc {
SegmentPointLocation::OnVertex(i) => FeatureId::Vertex(i),
SegmentPointLocation::OnEdge(..) => {
#[cfg(feature = "dim2")]
{
let dir = self.scaled_direction();
let dpt = *pt - proj.point;
if dpt.perp(&dir) >= na::zero() {
FeatureId::Face(0)
} else {
FeatureId::Face(1)
}
}
#[cfg(feature = "dim3")]
{
FeatureId::Edge(0)
}
}
};
(proj, feature)
}
}
impl<N: RealField> PointQueryWithLocation<N> for Segment<N> {
type Location = SegmentPointLocation<N>;
#[inline]
fn project_point_with_location(
&self,
m: &Isometry<N>,
pt: &Point<N>,
_: bool,
) -> (PointProjection<N>, Self::Location) {
let ls_pt = m.inverse_transform_point(pt);
let ab = *self.b() - *self.a();
let ap = ls_pt - *self.a();
let ab_ap = ab.dot(&ap);
let sqnab = ab.norm_squared();
let _1 = na::one::<N>();
let mut proj;
let location;
if ab_ap <= na::zero() {
location = SegmentPointLocation::OnVertex(0);
proj = m * self.a();
} else if ab_ap >= sqnab {
location = SegmentPointLocation::OnVertex(1);
proj = m * self.b();
} else {
assert!(sqnab != na::zero());
let u = ab_ap / sqnab;
let bcoords = [_1 - u, u];
location = SegmentPointLocation::OnEdge(bcoords);
proj = *self.a() + ab * u;
proj = m * proj;
}
let inside = relative_eq!(proj, *pt);
(PointProjection::new(inside, proj), location)
}
}