1
#include <collisionqueries.h>
2
#include <commonoptions.h>
6
void check_point_edge_proximity(bool update, const Vec3d &x0, const Vec3d &x1, const Vec3d &x2,
11
// find parameter value of closest point on segment
12
double s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
13
// and find the distance
15
distance=min(distance, dist(x0,s*x1+(1-s)*x2));
17
distance=dist(x0,s*x1+(1-s)*x2);
21
// normal is from 1-2 towards 0, unless normal_multiplier<0
22
void check_point_edge_proximity(bool update, const Vec3d &x0, const Vec3d &x1, const Vec3d &x2,
23
double &distance, double &s, Vec3d &normal, double normal_multiplier)
28
// find parameter value of closest point on segment
29
double this_s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
30
// and find the distance
31
Vec3d this_normal=x0-(this_s*x1+(1-this_s)*x2);
32
double this_distance=mag(this_normal);
33
if(this_distance<distance){
35
distance=this_distance;
36
normal=(normal_multiplier/(this_distance+1e-30))*this_normal;
39
// find parameter value of closest point on segment
40
s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
41
// and find the distance
42
normal=x0-(s*x1+(1-s)*x2);
44
normal*=normal_multiplier/(distance+1e-30);
48
void check_point_edge_proximity( bool update, const Vec2d &x0, const Vec2d &x1, const Vec2d &x2,
53
// find parameter value of closest point on segment
54
double s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
55
// and find the distance
57
distance=min(distance, dist(x0,s*x1+(1-s)*x2));
59
distance=dist(x0, s*x1+(1-s)*x2);
63
// normal is from 1-2 towards 0, unless normal_multiplier<0
64
void check_point_edge_proximity(bool update, const Vec2d &x0, const Vec2d &x1, const Vec2d &x2,
65
double &distance, double &s, Vec2d &normal, double normal_multiplier)
70
// find parameter value of closest point on segment
71
double this_s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
72
// and find the distance
73
Vec2d this_normal=x0-(this_s*x1+(1-this_s)*x2);
74
double this_distance=mag(this_normal);
75
if(this_distance<distance){
77
distance=this_distance;
78
normal=(normal_multiplier/(this_distance+1e-30))*this_normal;
81
// find parameter value of closest point on segment
82
s=clamp(dot(x2-x0, dx)/m2, 0., 1.);
83
// and find the distance
84
normal=x0-(s*x1+(1-s)*x2);
86
if ( distance < 1e-10 )
88
normal = normalized(perp(x2 - x1));
92
normal*=normal_multiplier/(distance+1e-30);
96
void check_edge_edge_proximity(const Vec3d &x0, const Vec3d &x1, const Vec3d &x2, const Vec3d &x3, double &distance)
98
// let's do it the QR way for added robustness
100
double r00=mag(x01)+1e-30;
103
double r01=dot(x32,x01);
105
double r11=mag(x32)+1e-30;
108
double s2=dot(x32,x31)/r11;
109
double s0=(dot(x01,x31)-r01*s2)/r00;
110
// check if we're in range
113
// check both x1 against 2-3 and 3 against 0-1
114
check_point_edge_proximity(false, x1, x2, x3, distance);
115
check_point_edge_proximity(true, x3, x0, x1, distance);
117
// check both x1 against 2-3 and 2 against 0-1
118
check_point_edge_proximity(false, x1, x2, x3, distance);
119
check_point_edge_proximity(true, x2, x0, x1, distance);
122
// check x1 against 2-3
123
check_point_edge_proximity(false, x1, x2, x3, distance);
127
// check both x0 against 2-3 and 3 against 0-1
128
check_point_edge_proximity(false, x0, x2, x3, distance);
129
check_point_edge_proximity(true, x3, x0, x1, distance);
131
// check both x0 against 2-3 and 2 against 0-1
132
check_point_edge_proximity(false, x0, x2, x3, distance);
133
check_point_edge_proximity(true, x2, x0, x1, distance);
136
// check x0 against 2-3
137
check_point_edge_proximity(false, x0, x2, x3, distance);
142
// check x3 against 0-1
143
check_point_edge_proximity(false, x3, x0, x1, distance);
146
// check x2 against 0-1
147
check_point_edge_proximity(false, x2, x0, x1, distance);
148
}else{ // we already got the closest points!
149
distance=dist(s2*x2+(1-s2)*x3, s0*x0+(1-s0)*x1);
154
// find distance between 0-1 and 2-3, with barycentric coordinates for closest points, and
155
// a normal that points from 0-1 towards 2-3 (unreliable if distance==0 or very small)
156
void check_edge_edge_proximity(const Vec3d &x0, const Vec3d &x1, const Vec3d &x2, const Vec3d &x3,
157
double &distance, double &s0, double &s2, Vec3d &normal)
159
// let's do it the QR way for added robustness
161
double r00=mag(x01)+1e-30;
164
double r01=dot(x32,x01);
166
double r11=mag(x32)+1e-30;
170
s0=(dot(x01,x31)-r01*s2)/r00;
171
// check if we're in range
174
// check both x1 against 2-3 and 3 against 0-1
175
check_point_edge_proximity(false, x1, x2, x3, distance, s2, normal, 1.);
176
check_point_edge_proximity(true, x3, x0, x1, distance, s0, normal, -1.);
178
// check both x1 against 2-3 and 2 against 0-1
179
check_point_edge_proximity(false, x1, x2, x3, distance, s2, normal, 1.);
180
check_point_edge_proximity(true, x2, x0, x1, distance, s0, normal, -1.);
183
// check x1 against 2-3
184
check_point_edge_proximity(false, x1, x2, x3, distance, s2, normal, 1.);
188
// check both x0 against 2-3 and 3 against 0-1
189
check_point_edge_proximity(false, x0, x2, x3, distance, s2, normal, 1.);
190
check_point_edge_proximity(true, x3, x0, x1, distance, s0, normal, -1.);
192
// check both x0 against 2-3 and 2 against 0-1
193
check_point_edge_proximity(false, x0, x2, x3, distance, s2, normal, 1.);
194
check_point_edge_proximity(true, x2, x0, x1, distance, s0, normal, -1.);
197
// check x0 against 2-3
198
check_point_edge_proximity(false, x0, x2, x3, distance, s2, normal, 1.);
203
// check x3 against 0-1
204
check_point_edge_proximity(false, x3, x0, x1, distance, s0, normal, -1.);
207
// check x2 against 0-1
208
check_point_edge_proximity(false, x2, x0, x1, distance, s0, normal, -1.);
209
}else{ // we already got the closest points!
210
normal=(s0*x0+(1-s0)*x1)-(s2*x2+(1-s2)*x3);
211
distance=mag(normal);
212
if(distance>0) normal/=distance;
214
normal=cross(x1-x0, x3-x2);
215
normal/=mag(normal)+1e-300;
221
void check_point_triangle_proximity(const Vec3d &x0, const Vec3d &x1, const Vec3d &x2, const Vec3d &x3,
224
// do it the QR way for added robustness
226
double r00=mag(x13)+1e-30;
229
double r01=dot(x23,x13);
231
double r11=mag(x23)+1e-30;
234
double s2=dot(x23,x03)/r11;
235
double s1=(dot(x13,x03)-r01*s2)/r00;
237
// check if we are in range
238
if(s1>=0 && s2>=0 && s3>=0){
239
distance=dist(x0, s1*x1+s2*x2+s3*x3);
241
if(s1>0){ // rules out edge 2-3
242
check_point_edge_proximity(false, x0, x1, x2, distance);
243
check_point_edge_proximity(true, x0, x1, x3, distance);
244
}else if(s2>0){ // rules out edge 1-3
245
check_point_edge_proximity(false, x0, x1, x2, distance);
246
check_point_edge_proximity(true, x0, x2, x3, distance);
247
}else{ // s3>0: rules out edge 1-2
248
check_point_edge_proximity(false, x0, x2, x3, distance);
249
check_point_edge_proximity(true, x0, x1, x3, distance);
254
// find distance between 0 and 1-2-3, with barycentric coordinates for closest point, and
255
// a normal that points from 1-2-3 towards 0 (unreliable if distance==0 or very small)
256
void check_point_triangle_proximity(const Vec3d &x0, const Vec3d &x1, const Vec3d &x2, const Vec3d &x3,
257
double &distance, double &s1, double &s2, double &s3, Vec3d &normal)
259
// do it the QR way for added robustness
261
double r00=mag(x13)+1e-30;
264
double r01=dot(x23,x13);
266
double r11=mag(x23)+1e-30;
270
s1=(dot(x13,x03)-r01*s2)/r00;
272
// check if we are in range
273
if(s1>=0 && s2>=0 && s3>=0){
274
normal=x0-(s1*x1+s2*x2+s3*x3);
275
distance=mag(normal);
276
if(distance>0) normal/=distance;
278
normal=cross(x2-x1, x3-x1);
279
normal/=mag(normal)+1e-300;
283
if(s1>0){ // rules out edge 2-3
284
check_point_edge_proximity(false, x0, x1, x2, distance, s, normal, 1.);
285
s1=s; s2=1-s; s3=0; d=distance;
286
check_point_edge_proximity(true, x0, x1, x3, distance, s, normal, 1.);
290
}else if(s2>0){ // rules out edge 1-3
291
check_point_edge_proximity(false, x0, x1, x2, distance, s, normal, 1.);
292
s1=s; s2=1-s; s3=0; d=distance;
293
check_point_edge_proximity(true, x0, x2, x3, distance, s, normal, 1.);
295
s1=0; s2=s; s3=1-s; d=distance;
297
}else{ // s3>0: rules out edge 1-2
298
check_point_edge_proximity(false, x0, x2, x3, distance, s, normal, 1.);
299
s1=0; s2=s; s3=1-s; d=distance;
300
check_point_edge_proximity(true, x0, x1, x3, distance, s, normal, 1.);
308
double signed_volume(const Vec3d &x0, const Vec3d &x1, const Vec3d &x2, const Vec3d &x3)
310
// Equivalent to triple(x1-x0, x2-x0, x3-x0), six times the signed volume of the tetrahedron.
311
// But, for robustness, we want the result (up to sign) to be independent of the ordering.
312
// And want it as accurate as possible...
313
// But all that stuff is hard, so let's just use the common assumption that all coordinates are >0,
314
// and do something reasonably accurate in fp.
316
// This formula does almost four times too much multiplication, but if the coordinates are non-negative
317
// it suffers in a minimal way from cancellation error.
318
return ( x0[0]*(x1[1]*x3[2]+x3[1]*x2[2]+x2[1]*x1[2])
319
+x1[0]*(x2[1]*x3[2]+x3[1]*x0[2]+x0[1]*x2[2])
320
+x2[0]*(x3[1]*x1[2]+x1[1]*x0[2]+x0[1]*x3[2])
321
+x3[0]*(x1[1]*x2[2]+x2[1]*x0[2]+x0[1]*x1[2]) )
323
- ( x0[0]*(x2[1]*x3[2]+x3[1]*x1[2]+x1[1]*x2[2])
324
+x1[0]*(x3[1]*x2[2]+x2[1]*x0[2]+x0[1]*x3[2])
325
+x2[0]*(x1[1]*x3[2]+x3[1]*x0[2]+x0[1]*x1[2])
326
+x3[0]*(x2[1]*x1[2]+x1[1]*x0[2]+x0[1]*x2[2]) );