-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtry_EPA.m
More file actions
executable file
·236 lines (203 loc) · 6.36 KB
/
try_EPA.m
File metadata and controls
executable file
·236 lines (203 loc) · 6.36 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
function [a,b,c,d,flag] = try_EPA(shape1,shape2,iterations)
% GJK Gilbert-Johnson-Keerthi Collision detection implementation.
% Returns whether two convex shapes are are penetrating or not
% (true/false). Only works for CONVEX shapes.
%
% Inputs:
% shape1:
% must have fields for XData,YData,ZData, which are the x,y,z
% coordinates of the vertices. Can be the same as what comes out of a
% PATCH object. It isn't required that the points form faces like patch
% data. This algorithm will assume the convex hull of the x,y,z points
% given.
%
% shape2:
% Other shape to test collision against. Same info as shape1.
%
% iterations:
% The algorithm tries to construct a tetrahedron encompassing
% the origin. This proves the objects have collided. If we fail within a
% certain number of iterations, we give up and say the objects are not
% penetrating. Low iterations means a higher chance of false-NEGATIVES
% but faster computation. As the objects penetrate more, it takes fewer
% iterations anyway, so low iterations is not a huge disadvantage.
%
% Outputs:
% flag:
% true - objects collided
% false - objects not collided
%
%
% This video helped me a lot when making this: https://mollyrocket.com/849
% Not my video, but very useful.
%
% Matthew Sheen, 2016
%
%Point 1 and 2 selection (line segment)
v = [0.8 0.5 1];
[a,b] = pickLine(v,shape2,shape1);
%Point 3 selection (triangle)
[a,b,c,flag] = pickTriangle(a,b,shape2,shape1,iterations);
%Point 4 selection (tetrahedron)
% if flag == 1 %Only bother if we could find a viable triangle.
[a,b,c,d,flag] = pickTetrahedron(a,b,c,shape2,shape1,iterations);
% end
end
function [a,b] = pickLine(v,shape1,shape2)
%Construct the first line of the simplex
b = support(shape2,shape1,v);
dir_ori=-b;
a = support(shape2,shape1,dir_ori);
end
function [a,b,c,flag] = pickTriangle(a,b,shape1,shape2,IterationAllowed)
flag = 0; %So far, we don't have a successful triangle.
%First try:
ab = b-a;
ao = -a;
v = cross(cross(ab,ao),ab); % v is perpendicular to ab pointing in the general direction of the origin.
c = b;
b = a;
a = support(shape2,shape1,v);
for i = 1:IterationAllowed %iterations to see if we can draw a good triangle.
%Time to check if we got it:
ab = b-a;
ao = -a;
ac = c-a;
%Normal to face of triangle
abc = cross(ab,ac);
%Perpendicular to AB going away from triangle
abp = cross(ab,abc);
%Perpendicular to AC going away from triangle
acp = cross(abc,ac);
%First, make sure our triangle "contains" the origin in a 2d projection
%sense.
%Is origin above (outside) AB?
if dot(abp,ao) > 0
c = b; %Throw away the furthest point and grab a new one in the right direction
b = a;
v = abp; %cross(cross(ab,ao),ab);
%Is origin above (outside) AC?
elseif dot(acp, ao) > 0
b = a;
v = acp; %cross(cross(ac,ao),ac);
else
% flag = 1;
% break; %We got a good one.
end
a = support(shape2,shape1,v);
end
end
function [a,b,c,d,flag] = pickTetrahedron(a,b,c,shape1,shape2,IterationAllowed)
%Now, if we're here, we have a successful 2D simplex, and we need to check
%if the origin is inside a successful 3D simplex.
%So, is the origin above or below the triangle?
flag = 0;
ab = b-a;
ac = c-a;
%Normal to face of triangle
abc = cross(ab,ac);
ao = -a;
if dot(abc, ao) > 0 %Above
d = c;
c = b;
b = a;
v = abc;
a_new = support(shape2,shape1,v); %Tetrahedron new point
if ismember(a_new',[a;b;c;d]')
else
d = c;
c = b;
b = a;
a=a_new;
end
else %below
d = b;
b = a;
v = -abc;
a_new = support(shape2,shape1,v); %Tetrahedron new point
if ismember(a_new',[a;b;c;d]')
else
d = b;
b = a;
a=a_new;
end
end
for i = 1:IterationAllowed %Allowing 10 tries to make a good tetrahedron.
%Check the tetrahedron:
ab = b-a;
ao = -a;
ac = c-a;
ad = d-a;
%We KNOW that the origin is not under the base of the tetrahedron based on
%the way we picked a. So we need to check faces ABC, ABD, and ACD.
%Normal to face of triangle
abc = cross(ab,ac);
if dot(abc, ao) > 0 %Above triangle ABC
%No need to change anything, we'll just iterate again with this face as
%default.
else
acd = cross(ac,ad);%Normal to face of triangle
if dot(acd, ao) > 0 %Above triangle ACD
%Make this the new base triangle.
b = c;
c = d;
ab = ac;
ac = ad;
abc = acd;
elseif dot(acd, ao) < 0
adb = cross(ad,ab);%Normal to face of triangle
if dot(adb, ao) > 0 %Above triangle ADB
%Make this the new base triangle.
c = b;
b = d;
ac = ab;
ab = ad;
abc = adb;
else
flag = 1;
break; %It's inside the tetrahedron.
end
else %le point le plus proche est un des trois points du simplex
;
end
end
%try again:
if dot(abc, ao) > 0 %Above
v = abc;
a_new = support(shape2,shape1,v); %Tetrahedron new point
if ismember(a_new',[a;b;c;d]')
else
d = c;
c = b;
b = a;
a=a_new;
end
else %below
v = -abc;
a_new = support(shape2,shape1,v); %Tetrahedron new point
if ismember(a_new',[a;b;c;d]')
else
d = b;
b = a;
a=a_new;
end
end
end
end
function point = getFarthestInDir(shape, v)
%Find the furthest point in a given direction for a shape
XData = get(shape,'XData'); % Making it more compatible with previous MATLAB releases.
YData = get(shape,'YData');
ZData = get(shape,'ZData');
dotted = XData*v(1) + YData*v(2) + ZData*v(3);
[maxInCol,rowIdxSet] = max(dotted);
[maxInRow,colIdx] = max(maxInCol);
rowIdx = rowIdxSet(colIdx);
point = [XData(rowIdx,colIdx), YData(rowIdx,colIdx), ZData(rowIdx,colIdx)];
end
function point = support(shape1,shape2,v)
%Support function to get the Minkowski difference.
point1 = getFarthestInDir(shape1, v);
point2 = getFarthestInDir(shape2, -v);
point = point1 - point2;
end