-
Notifications
You must be signed in to change notification settings - Fork 0
/
plane.h
399 lines (293 loc) · 8.98 KB
/
plane.h
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#pragma once
#include <math.h>
#include "vector.h"
#include "matrix.h"
#include "aabb.h"
#define Epsilon() 1e-6f
struct line;
struct plane;
struct line
{
line()
{
}
line(const vec3& a, const vec3& b)
{
p = a; n = normalize(b - a);
}
line(const vec3& p, const plane& pl);
vec3 p, n;
};
struct plane
{
plane()
{
}
plane(const plane& p): pl(p.pl)
{
}
plane(const vec3& n, float d): pl(n, d)
{
}
plane(const vec4& p): pl(p)
{
}
void from_triangle(const vec3& a, const vec3& b, const vec3& c)
{
pl = vec4(triangle_normal(a, b, c), 1.0);
pl = vec4(pl.xyz(), -dot(pl.xyz(), a));
}
void normalize()
{
float len = pl.normalize();
pl.w /= len;
}
vec4 pl;
};
inline line::line(const vec3& p, const plane& pl)
{
this->p = p;
this->n = normalize(pl.pl.xyz());
}
inline float distance_from_point(const line& l, const vec2& pt)
{
float n1 = (pt.x - l.p.x) * l.n.y - (pt.y - l.p.y) * l.n.x;
return fabsf(n1);
}
inline float distance_from_segment_to_point(const vec2& s, const vec2 &e, const vec2& pt)
{
vec2 dir = e - s;
float length = dir.normalize();
float f = dot(pt - s, dir);
if(f < 0.0f)
return (pt - s).length();
if(f > length)
return (pt - e).length();
float n1 = (pt.x - s.x) * dir.y - (pt.y - s.y) * dir.x;
return fabsf(n1);
}
inline float distance_from_point(const line& l, const vec3& pt)
{
float n1 = (pt.x - l.p.x) * l.n.y - (pt.y - l.p.y) * l.n.x;
float n2 = (pt.y - l.p.y) * l.n.z - (pt.z - l.p.z) * l.n.y;
float n3 = (pt.z - l.p.z) * l.n.x - (pt.x - l.p.x) * l.n.z;
return sqrtf(n1 * n1 + n2 * n2 + n3 * n3);
}
inline vec3 project_point_on_line(const line& l, const vec3& pt)
{
return l.p + l.n * dot(pt - l.p, l.n);
}
inline float distance_from_line(const line& l1, const line& l2)
{
mat3 detm(l1.p - l2.p, l1.n, l2.n);
float det = detm.det();
float n1 = l1.n.x * l2.n.y - l1.n.y * l2.n.x;
float n2 = l1.n.y * l2.n.z - l1.n.z * l2.n.y;
float n3 = l1.n.z * l2.n.x - l1.n.x * l2.n.z;
float zn = sqrtf(n1 * n1 + n2 * n2 + n3 * n3);
return det / zn;
}
inline bool line_intersects_line_2d(float s0x, float s0y, float t0x, float t0y, float s1x, float s1y, float t1x, float t1y)
{
float v0x = t0x - s0x;
float v0y = t0y - s0y;
float v1x = t1x - s1x;
float v1y = t1y - s1y;
float d = v1x * v0y - v0x * v1y;
float s = ((s0x - s1x) * v0y - (s0y - s1y) * v0x) / d;
if(s < 0.0f || s > 1.0f)
return false;
float t = -(-(s0x - s1x) * v1y + (s0y - s1y) * v1x) / d;
if(t < 0.0f || t > 1.0f)
return false;
return true;
}
inline bool line_intersects_line_2d(float s0x, float s0y, float t0x, float t0y, float s1x, float s1y, float t1x, float t1y, float &s, float &t)
{
float v0x = t0x - s0x;
float v0y = t0y - s0y;
float v1x = t1x - s1x;
float v1y = t1y - s1y;
float d = v1x * v0y - v0x * v1y;
s = ((s0x - s1x) * v0y - (s0y - s1y) * v0x) / d;
if(s < 0.0f || s > 1.0f)
return false;
t = -(-(s0x - s1x) * v1y + (s0y - s1y) * v1x) / d;
if(t < 0.0f || t > 1.0f)
return false;
return true;
}
// Returns false if parallel or if on plane
inline bool intersect_plane(const line& l, const plane& p, vec3& pt)
{
float a = dot(l.p, p.pl);
float b = dot(p.pl.xyz(), l.n);
if(fabsf(b) < Epsilon())
return false;
float phi = a / b;
pt = vec3(l.p.x - l.n.x * phi, l.p.y - l.n.y * phi, l.p.z - l.n.z * phi);
return true;
}
inline float cos_of_angle_between_lines(const line& l1, const line& l2)
{
vec3 l1xyz = l1.n;
vec3 l2xyz = l2.n;
return dot(l1xyz, l2xyz);
}
inline float angle_between_lines(const line& l1, const line& l2)
{
return acosf(cos_of_angle_between_lines(l1, l2));
}
inline float cos_of_angle_between_line_and_plane(const line& l, const plane& p)
{
vec3 lxyz = l.n;
vec3 pxyz = p.pl.xyz();
return dot(lxyz, pxyz) / sqrtf(dot(pxyz, pxyz) * dot(lxyz, lxyz));
}
// Returns false if parallel or if there is no intersection in one point
inline bool intersection_of_three_planes(const plane& p1, const plane& p2, const plane& p3, vec3& pt)
{
mat3 d1, dx, dy, dz;
d1 = mat3(p1.pl.xyz(), p2.pl.xyz(), p3.pl.xyz());
float dd = d1.det();
if(fabsf(dd) < Epsilon())
return false;
dx = mat3(vec3(p1.pl.w, p2.pl.w, p3.pl.w), vec3(p1.pl.y, p2.pl.y, p3.pl.y), vec3(p1.pl.z, p2.pl.z, p3.pl.z));
dy = mat3(vec3(p1.pl.x, p2.pl.x, p3.pl.x), vec3(p1.pl.w, p2.pl.w, p3.pl.w), vec3(p1.pl.z, p2.pl.z, p3.pl.z));
dz = mat3(vec3(p1.pl.x, p2.pl.x, p3.pl.x), vec3(p1.pl.y, p2.pl.y, p3.pl.y), vec3(p1.pl.w, p2.pl.w, p3.pl.w));
pt = vec3(-dx.det() / dd, -dy.det() / dd, -dz.det() / dd);
return true;
}
inline float cos_of_angle_between_planes(const plane& p1, const plane& p2)
{
vec3 p1xyz = p1.pl.xyz();
vec3 p2xyz = p2.pl.xyz();
return dot(p1xyz, p2xyz) / sqrtf(dot(p1xyz, p1xyz) * dot(p2xyz, p2xyz));
}
inline float angle_between_planes(const plane& p1, const plane& p2)
{
return acosf(cos_of_angle_between_planes(p1, p2));
}
// Returns furthest distance to the intersection of aabb planes or a negative value if there is no intersection
inline float line_intersects_aabb(const line& l, const aabb& box)
{
vec3 min = box.min_point();
vec3 max = box.max_point();
float dist = -1.0f;
vec3 intersection;
if(intersect_plane(l, plane(vec4(1, 0, 0, -min.x)), intersection))
{
if(intersection.y > min.y && intersection.y < max.y && intersection.z > min.z && intersection.z < max.z)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
if(intersect_plane(l, plane(vec4(0, 1, 0, -min.y)), intersection))
{
if(intersection.x > min.x && intersection.x < max.x && intersection.z > min.z && intersection.z < max.z)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
if(intersect_plane(l, plane(vec4(0, 0, 1, -min.z)), intersection))
{
if(intersection.x > min.x && intersection.x < max.x && intersection.y > min.y && intersection.y < max.y)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
if(intersect_plane(l, plane(vec4(1, 0, 0, -max.x)), intersection))
{
if(intersection.y > min.y && intersection.y < max.y && intersection.z > min.z && intersection.z < max.z)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
if(intersect_plane(l, plane(vec4(0, 1, 0, -max.y)), intersection))
{
if(intersection.x > min.x && intersection.x < max.x && intersection.z > min.z && intersection.z < max.z)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
if(intersect_plane(l, plane(vec4(0, 0, 1, -max.z)), intersection))
{
if(intersection.x > min.x && intersection.x < max.x && intersection.y > min.y && intersection.y < max.y)
{
float length = (l.p - intersection).length();
if(length > dist)
dist = length;
}
}
return dist;
}
inline float line_intersect_triangle_distance(const line& l, const vec3& a, const vec3& b, const vec3& c)
{
// http://en.wikipedia.org/wiki/Moller–Trumbore_intersection_algorithm
vec3 e1, e2;
vec3 p, q, t;
float det, invDet, u, v;
// Find vectors for two edges sharing V1
e1 = b - a;
e2 = c - a;
// Begin calculating determinant - also used to calculate u parameter
p = cross(l.n, e2);
// If determinant is near zero, ray lies in plane of triangle
det = dot(e1, p);
if(det > -Epsilon() && det < Epsilon())
return -1.0f;
invDet = 1.0f / det;
// Calculate distance from V1 to ray origin
t = l.p - a;
// Calculate u parameter and test bound
u = dot(t, p) * invDet;
// The intersection lies outside of the triangle
if(u < 0.0f || u > 1.0f)
return -1.0f;
// Prepare to test v parameter
q = cross(t, e1);
// Calculate V parameter and test bound
v = dot(l.n, q) * invDet;
// The intersection lies outside of the triangle
if(v < 0.0f || u + v > 1.0f)
return -1.0f;
float distance = dot(e2, q) * invDet;
if(distance > Epsilon())
return distance;
return -1.0f;
}
inline bool line_intersects_triangle(const line& l, const vec3& a, const vec3& b, const vec3& c)
{
return line_intersect_triangle_distance(l, a, b, c) >= 0.0f;
}
inline bool line_intersects_triangle(const line& l, const vec2& a, const vec2& b, const vec2& c)
{
float dx = l.p.x - a.x;
float dy = l.p.y - a.y;
bool sign = (b.x - a.x) * dy - (b.y - a.y) * dx > 0;
if((c.x - a.x) * dy - (c.y - a.y) * dx > 0 == sign)
return false;
if((c.x - b.x) * (l.p.y - b.y) - (c.y - b.y) * (l.p.x - b.x) > 0 != sign)
return false;
return true;
}
inline line unproject_ray(const mat4& m, vec2 point)
{
mat4 mi = m.inverse();
vec3 ptMin(point.x * 2.0f - 1.0f, point.y * 2.0f - 1.0f, 0.0);
vec3 ptMax(point.x * 2.0f - 1.0f, point.y * 2.0f - 1.0f, 1.0);
ptMin = mi * ptMin;
ptMax = mi * ptMax;
return line(ptMin, ptMax);
}
#undef Epsilon