forked from JuliaGeometry/GeometryBasics.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdistances.jl
137 lines (110 loc) · 3.87 KB
/
distances.jl
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#=
Functions to compute distances from points to primatives
=#
using LinearAlgebra: normalize,norm,⋅
"""
closest_point_to_tri(p, a, b, c)
This method from Ericson, "Real-time collision detection"
2005, doesn't require the normal or cross products.
"""
@fastmath function closest_point_to_tri(p,a,b,c)
# is point `a` closest?
ab,ac,ap = b-a,c-a,p-a
d1,d2 = ab ⋅ ap, ac ⋅ ap
d1 <= 0 && d2 <= 0 && return a
# is point `b` closest?
bp = p-b
d3,d4 = ab ⋅ bp, ac ⋅ bp
d3 >= 0 && d4 <= d3 && return b
# is point `c` closest?
cp = p-c
d5,d6 = ab ⋅ cp, ac ⋅ cp
d6 >= 0 && d5 <= d6 && return c
# is segment `ab` closest?
vc = d1*d4 - d3*d2
if (vc <= 0 && d1 >= 0 && d3 <= 0)
d1==d3 && @show d1,d3
return a + ab * d1 * inv(d1 - d3)
end
# is segment `ac` closest?
vb = d5*d2 - d1*d6
if (vb <= 0 && d2 >= 0 && d6 <= 0)
return a + ac * d2 * inv(d2 - d6)
end
# is segment `bc` closest?
va = d3*d6 - d5*d4
if (va <= 0 && d4 >= d3 && d5 >= d6)
return b + (c - b) * (d4 - d3) * inv(d4 - d3 + d5 - d6)
end
# closest is interior to `abc`
denom = inv(va + vb + vc)
v,w = vb * denom, vc * denom
return a + ab * v + ac * w
end
"""
closest(p,tri::Triangle)
Determine the closest point on triangle `tri` to point `p`.
"""
closest(p,tri::Triangle) = closest_point_to_tri(p,tri.points.data...)
"""
absolute_distance(p,tri::Triangle)
Determine the absolute distance from point `p` to the closest point on triangle `tri`.
"""
absolute_distance(p,tri::Triangle) = norm(p-closest(p,tri))
"""
signed_distance(p,tri::Triangle)
Determine the signed distance from point `p` to the plane defined by triangle `tri`.
Note that the sign depends on triangle point ordering and `d=0` only implies `p`
lies on the plane, not that it is within the triangle.
"""
signed_distance(p,tri::Triangle) = signed_distance_to_tri(p,tri.points.data...)
signed_distance_to_tri(p,a,b,c) = normalize(orthogonal_vector(a,b,c))⋅(p-a)
nonzero(mesh::AbstractMesh) = (i for i in mesh if sum(abs2,orthogonal_vector(i.points.data...))>0)
"""
absolute_distance(p, mesh::AbstractMesh)
Return the minimum absolute distance from point `p` to any Triangle in `mesh`.
"""
absolute_distance(p,mesh::AbstractMesh) = minimum(t->absolute_distance(p,t), nonzero(mesh))
"""
signed_distance(p, mesh::AbstractMesh)
Return the signed distance to the geometry defined by the union of planes
passing through each `mesh` face.
"""
signed_distance(p,mesh::AbstractMesh) = maximum(t->signed_distance(p,t), nonzero(mesh))
"""
signed_distance(p,s::HyperSphere)
Return the signed distance from `p` to `s`.
"""
signed_distance(p,s::HyperSphere) = norm(p-origin(s))-radius(s)
distance_to_corner(q) = norm(max.(q, 0.))+min(maximum(q),0.)
"""
signed_distance(p,r::Rect)
Return the signed distance from `p` to `r`.
"""
function signed_distance(p,r::Rect)
# Get vector relative to Rect corner
q = abs.(p-origin(r).-0.5*width(r)).-0.5*width(r)
return distance_to_corner(q)
end
"""
signed_distance(p,c::Cylinder)
Return the signed distance from `p` to `c`.
"""
function signed_distance(p,c::Cylinder)
e = (extremity(c)-origin(c))/2 # center to edge (defines length direction)
r = p-(extremity(c)+origin(c))/2 # center to point
e₁ = norm(e) # cylinder half-length
r₁ = abs(e ⋅ r) / e₁ # projected length to point
r₂ = √(r ⋅ r - r₁^2) # height to point
return distance_to_corner(Point(r₁-e₁,r₂-radius(c)))
end
"""
signed_distance(p,prim)
Fallback signed distance function.
"""
signed_distance(p,prim::GeometryPrimitive) = signed_distance(p,GeometryBasics.mesh(prim))
"""
absolute_distance(p,prim) = |signed_distance(p,prim)|
Fallback absolute distance function.
"""
absolute_distance(p,prim) = abs(signed_distance(p,prim))