Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/math/aabb.h
9896 views
1
/**************************************************************************/
2
/* aabb.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/math/plane.h"
34
#include "core/math/vector3.h"
35
36
/**
37
* AABB (Axis Aligned Bounding Box)
38
* This is implemented by a point (position) and the box size.
39
*/
40
41
class Variant;
42
43
struct [[nodiscard]] AABB {
44
Vector3 position;
45
Vector3 size;
46
47
real_t get_volume() const;
48
_FORCE_INLINE_ bool has_volume() const {
49
return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
50
}
51
52
_FORCE_INLINE_ bool has_surface() const {
53
return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
54
}
55
56
const Vector3 &get_position() const { return position; }
57
void set_position(const Vector3 &p_pos) { position = p_pos; }
58
const Vector3 &get_size() const { return size; }
59
void set_size(const Vector3 &p_size) { size = p_size; }
60
61
constexpr bool operator==(const AABB &p_rval) const {
62
return position == p_rval.position && size == p_rval.size;
63
}
64
constexpr bool operator!=(const AABB &p_rval) const {
65
return position != p_rval.position || size != p_rval.size;
66
}
67
68
bool is_equal_approx(const AABB &p_aabb) const;
69
bool is_same(const AABB &p_aabb) const;
70
bool is_finite() const;
71
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
72
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
73
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
74
75
AABB merge(const AABB &p_with) const;
76
void merge_with(const AABB &p_aabb); ///merge with another AABB
77
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
78
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const;
79
80
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
81
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir) const {
82
bool inside;
83
return find_intersects_ray(p_from, p_dir, inside);
84
}
85
bool find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool &r_inside, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
86
87
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
88
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
89
bool intersects_plane(const Plane &p_plane) const;
90
91
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
92
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_direction) const;
93
94
Vector3 get_longest_axis() const;
95
int get_longest_axis_index() const;
96
_FORCE_INLINE_ real_t get_longest_axis_size() const;
97
98
Vector3 get_shortest_axis() const;
99
int get_shortest_axis_index() const;
100
_FORCE_INLINE_ real_t get_shortest_axis_size() const;
101
102
AABB grow(real_t p_by) const;
103
_FORCE_INLINE_ void grow_by(real_t p_amount);
104
105
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
106
_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
107
108
AABB expand(const Vector3 &p_vector) const;
109
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
110
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
111
112
_FORCE_INLINE_ AABB abs() const {
113
return AABB(position + size.minf(0), size.abs());
114
}
115
116
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
117
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
118
119
_FORCE_INLINE_ void quantize(real_t p_unit);
120
_FORCE_INLINE_ AABB quantized(real_t p_unit) const;
121
122
_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
123
size = p_end - position;
124
}
125
126
_FORCE_INLINE_ Vector3 get_end() const {
127
return position + size;
128
}
129
130
_FORCE_INLINE_ Vector3 get_center() const {
131
return position + (size * 0.5f);
132
}
133
134
explicit operator String() const;
135
136
AABB() = default;
137
constexpr AABB(const Vector3 &p_pos, const Vector3 &p_size) :
138
position(p_pos),
139
size(p_size) {
140
}
141
};
142
143
inline bool AABB::intersects(const AABB &p_aabb) const {
144
#ifdef MATH_CHECKS
145
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
146
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
147
}
148
#endif
149
if (position.x >= (p_aabb.position.x + p_aabb.size.x)) {
150
return false;
151
}
152
if ((position.x + size.x) <= p_aabb.position.x) {
153
return false;
154
}
155
if (position.y >= (p_aabb.position.y + p_aabb.size.y)) {
156
return false;
157
}
158
if ((position.y + size.y) <= p_aabb.position.y) {
159
return false;
160
}
161
if (position.z >= (p_aabb.position.z + p_aabb.size.z)) {
162
return false;
163
}
164
if ((position.z + size.z) <= p_aabb.position.z) {
165
return false;
166
}
167
168
return true;
169
}
170
171
inline bool AABB::intersects_inclusive(const AABB &p_aabb) const {
172
#ifdef MATH_CHECKS
173
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
174
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
175
}
176
#endif
177
if (position.x > (p_aabb.position.x + p_aabb.size.x)) {
178
return false;
179
}
180
if ((position.x + size.x) < p_aabb.position.x) {
181
return false;
182
}
183
if (position.y > (p_aabb.position.y + p_aabb.size.y)) {
184
return false;
185
}
186
if ((position.y + size.y) < p_aabb.position.y) {
187
return false;
188
}
189
if (position.z > (p_aabb.position.z + p_aabb.size.z)) {
190
return false;
191
}
192
if ((position.z + size.z) < p_aabb.position.z) {
193
return false;
194
}
195
196
return true;
197
}
198
199
inline bool AABB::encloses(const AABB &p_aabb) const {
200
#ifdef MATH_CHECKS
201
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
202
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
203
}
204
#endif
205
Vector3 src_min = position;
206
Vector3 src_max = position + size;
207
Vector3 dst_min = p_aabb.position;
208
Vector3 dst_max = p_aabb.position + p_aabb.size;
209
210
return (
211
(src_min.x <= dst_min.x) &&
212
(src_max.x >= dst_max.x) &&
213
(src_min.y <= dst_min.y) &&
214
(src_max.y >= dst_max.y) &&
215
(src_min.z <= dst_min.z) &&
216
(src_max.z >= dst_max.z));
217
}
218
219
Vector3 AABB::get_support(const Vector3 &p_direction) const {
220
Vector3 support = position;
221
if (p_direction.x > 0.0f) {
222
support.x += size.x;
223
}
224
if (p_direction.y > 0.0f) {
225
support.y += size.y;
226
}
227
if (p_direction.z > 0.0f) {
228
support.z += size.z;
229
}
230
return support;
231
}
232
233
Vector3 AABB::get_endpoint(int p_point) const {
234
switch (p_point) {
235
case 0:
236
return Vector3(position.x, position.y, position.z);
237
case 1:
238
return Vector3(position.x, position.y, position.z + size.z);
239
case 2:
240
return Vector3(position.x, position.y + size.y, position.z);
241
case 3:
242
return Vector3(position.x, position.y + size.y, position.z + size.z);
243
case 4:
244
return Vector3(position.x + size.x, position.y, position.z);
245
case 5:
246
return Vector3(position.x + size.x, position.y, position.z + size.z);
247
case 6:
248
return Vector3(position.x + size.x, position.y + size.y, position.z);
249
case 7:
250
return Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
251
}
252
253
ERR_FAIL_V(Vector3());
254
}
255
256
bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
257
Vector3 half_extents = size * 0.5f;
258
Vector3 ofs = position + half_extents;
259
260
for (int i = 0; i < p_plane_count; i++) {
261
const Plane &p = p_planes[i];
262
Vector3 point(
263
(p.normal.x > 0) ? -half_extents.x : half_extents.x,
264
(p.normal.y > 0) ? -half_extents.y : half_extents.y,
265
(p.normal.z > 0) ? -half_extents.z : half_extents.z);
266
point += ofs;
267
if (p.is_point_over(point)) {
268
return false;
269
}
270
}
271
272
// Make sure all points in the shape aren't fully separated from the AABB on
273
// each axis.
274
int bad_point_counts_positive[3] = { 0 };
275
int bad_point_counts_negative[3] = { 0 };
276
277
for (int k = 0; k < 3; k++) {
278
for (int i = 0; i < p_point_count; i++) {
279
if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
280
bad_point_counts_positive[k]++;
281
}
282
if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
283
bad_point_counts_negative[k]++;
284
}
285
}
286
287
if (bad_point_counts_negative[k] == p_point_count) {
288
return false;
289
}
290
if (bad_point_counts_positive[k] == p_point_count) {
291
return false;
292
}
293
}
294
295
return true;
296
}
297
298
bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
299
Vector3 half_extents = size * 0.5f;
300
Vector3 ofs = position + half_extents;
301
302
for (int i = 0; i < p_plane_count; i++) {
303
const Plane &p = p_planes[i];
304
Vector3 point(
305
(p.normal.x < 0) ? -half_extents.x : half_extents.x,
306
(p.normal.y < 0) ? -half_extents.y : half_extents.y,
307
(p.normal.z < 0) ? -half_extents.z : half_extents.z);
308
point += ofs;
309
if (p.is_point_over(point)) {
310
return false;
311
}
312
}
313
314
return true;
315
}
316
317
bool AABB::has_point(const Vector3 &p_point) const {
318
#ifdef MATH_CHECKS
319
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
320
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
321
}
322
#endif
323
if (p_point.x < position.x) {
324
return false;
325
}
326
if (p_point.y < position.y) {
327
return false;
328
}
329
if (p_point.z < position.z) {
330
return false;
331
}
332
if (p_point.x > position.x + size.x) {
333
return false;
334
}
335
if (p_point.y > position.y + size.y) {
336
return false;
337
}
338
if (p_point.z > position.z + size.z) {
339
return false;
340
}
341
342
return true;
343
}
344
345
inline void AABB::expand_to(const Vector3 &p_vector) {
346
#ifdef MATH_CHECKS
347
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
348
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
349
}
350
#endif
351
Vector3 begin = position;
352
Vector3 end = position + size;
353
354
if (p_vector.x < begin.x) {
355
begin.x = p_vector.x;
356
}
357
if (p_vector.y < begin.y) {
358
begin.y = p_vector.y;
359
}
360
if (p_vector.z < begin.z) {
361
begin.z = p_vector.z;
362
}
363
364
if (p_vector.x > end.x) {
365
end.x = p_vector.x;
366
}
367
if (p_vector.y > end.y) {
368
end.y = p_vector.y;
369
}
370
if (p_vector.z > end.z) {
371
end.z = p_vector.z;
372
}
373
374
position = begin;
375
size = end - begin;
376
}
377
378
void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const {
379
Vector3 half_extents(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f);
380
Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z);
381
382
real_t length = p_plane.normal.abs().dot(half_extents);
383
real_t distance = p_plane.distance_to(center);
384
r_min = distance - length;
385
r_max = distance + length;
386
}
387
388
inline real_t AABB::get_longest_axis_size() const {
389
real_t max_size = size.x;
390
391
if (size.y > max_size) {
392
max_size = size.y;
393
}
394
395
if (size.z > max_size) {
396
max_size = size.z;
397
}
398
399
return max_size;
400
}
401
402
inline real_t AABB::get_shortest_axis_size() const {
403
real_t max_size = size.x;
404
405
if (size.y < max_size) {
406
max_size = size.y;
407
}
408
409
if (size.z < max_size) {
410
max_size = size.z;
411
}
412
413
return max_size;
414
}
415
416
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const {
417
#ifdef MATH_CHECKS
418
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
419
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
420
}
421
#endif
422
real_t divx = 1.0f / p_dir.x;
423
real_t divy = 1.0f / p_dir.y;
424
real_t divz = 1.0f / p_dir.z;
425
426
Vector3 upbound = position + size;
427
real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
428
if (p_dir.x >= 0) {
429
tmin = (position.x - p_from.x) * divx;
430
tmax = (upbound.x - p_from.x) * divx;
431
} else {
432
tmin = (upbound.x - p_from.x) * divx;
433
tmax = (position.x - p_from.x) * divx;
434
}
435
if (p_dir.y >= 0) {
436
tymin = (position.y - p_from.y) * divy;
437
tymax = (upbound.y - p_from.y) * divy;
438
} else {
439
tymin = (upbound.y - p_from.y) * divy;
440
tymax = (position.y - p_from.y) * divy;
441
}
442
if ((tmin > tymax) || (tymin > tmax)) {
443
return false;
444
}
445
if (tymin > tmin) {
446
tmin = tymin;
447
}
448
if (tymax < tmax) {
449
tmax = tymax;
450
}
451
if (p_dir.z >= 0) {
452
tzmin = (position.z - p_from.z) * divz;
453
tzmax = (upbound.z - p_from.z) * divz;
454
} else {
455
tzmin = (upbound.z - p_from.z) * divz;
456
tzmax = (position.z - p_from.z) * divz;
457
}
458
if ((tmin > tzmax) || (tzmin > tmax)) {
459
return false;
460
}
461
if (tzmin > tmin) {
462
tmin = tzmin;
463
}
464
if (tzmax < tmax) {
465
tmax = tzmax;
466
}
467
return ((tmin < p_t1) && (tmax > p_t0));
468
}
469
470
void AABB::grow_by(real_t p_amount) {
471
position.x -= p_amount;
472
position.y -= p_amount;
473
position.z -= p_amount;
474
size.x += 2.0f * p_amount;
475
size.y += 2.0f * p_amount;
476
size.z += 2.0f * p_amount;
477
}
478
479
void AABB::quantize(real_t p_unit) {
480
size += position;
481
482
position.x -= Math::fposmodp(position.x, p_unit);
483
position.y -= Math::fposmodp(position.y, p_unit);
484
position.z -= Math::fposmodp(position.z, p_unit);
485
486
size.x -= Math::fposmodp(size.x, p_unit);
487
size.y -= Math::fposmodp(size.y, p_unit);
488
size.z -= Math::fposmodp(size.z, p_unit);
489
490
size.x += p_unit;
491
size.y += p_unit;
492
size.z += p_unit;
493
494
size -= position;
495
}
496
497
AABB AABB::quantized(real_t p_unit) const {
498
AABB ret = *this;
499
ret.quantize(p_unit);
500
return ret;
501
}
502
503
template <>
504
struct is_zero_constructible<AABB> : std::true_type {};
505
506