1
#ifndef GIM_BOX_COLLISION_H_INCLUDED
2
#define GIM_BOX_COLLISION_H_INCLUDED
4
/*! \file gim_box_collision.h
5
\author Francisco Leon Najera
8
-----------------------------------------------------------------------------
9
This source file is part of GIMPACT Library.
11
For the latest info, see http://gimpact.sourceforge.net/
13
Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
14
email: projectileman@yahoo.com
16
This library is free software; you can redistribute it and/or
17
modify it under the terms of EITHER:
18
(1) The GNU Lesser General Public License as published by the Free
19
Software Foundation; either version 2.1 of the License, or (at
20
your option) any later version. The text of the GNU Lesser
21
General Public License is included with this library in the
22
file GIMPACT-LICENSE-LGPL.TXT.
23
(2) The BSD-style license that is included with this library in
24
the file GIMPACT-LICENSE-BSD.TXT.
25
(3) The zlib/libpng license that is included with this library in
26
the file GIMPACT-LICENSE-ZLIB.TXT.
28
This library is distributed in the hope that it will be useful,
29
but WITHOUT ANY WARRANTY; without even the implied warranty of
30
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
31
GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
33
-----------------------------------------------------------------------------
35
#include "gim_basic_geometry_operations.h"
36
#include "LinearMath/btTransform.h"
40
//SIMD_FORCE_INLINE bool test_cross_edge_box(
41
// const btVector3 & edge,
42
// const btVector3 & absolute_edge,
43
// const btVector3 & pointa,
44
// const btVector3 & pointb, const btVector3 & extend,
47
// int component_index0,
48
// int component_index1)
50
// // dir coords are -z and y
52
// const btScalar dir0 = -edge[dir_index0];
53
// const btScalar dir1 = edge[dir_index1];
54
// btScalar pmin = pointa[component_index0]*dir0 + pointa[component_index1]*dir1;
55
// btScalar pmax = pointb[component_index0]*dir0 + pointb[component_index1]*dir1;
59
// GIM_SWAP_NUMBERS(pmin,pmax);
62
// const btScalar rad = extend[component_index0] * absolute_edge[dir_index0] +
63
// extend[component_index1] * absolute_edge[dir_index1];
65
// if(pmin>rad || -rad>pmax) return false;
69
//SIMD_FORCE_INLINE bool test_cross_edge_box_X_axis(
70
// const btVector3 & edge,
71
// const btVector3 & absolute_edge,
72
// const btVector3 & pointa,
73
// const btVector3 & pointb, btVector3 & extend)
76
// return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,2,1,1,2);
80
//SIMD_FORCE_INLINE bool test_cross_edge_box_Y_axis(
81
// const btVector3 & edge,
82
// const btVector3 & absolute_edge,
83
// const btVector3 & pointa,
84
// const btVector3 & pointb, btVector3 & extend)
87
// return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,0,2,2,0);
90
//SIMD_FORCE_INLINE bool test_cross_edge_box_Z_axis(
91
// const btVector3 & edge,
92
// const btVector3 & absolute_edge,
93
// const btVector3 & pointa,
94
// const btVector3 & pointb, btVector3 & extend)
97
// return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,1,0,0,1);
100
#define TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,i_dir_0,i_dir_1,i_comp_0,i_comp_1)\
102
const btScalar dir0 = -edge[i_dir_0];\
103
const btScalar dir1 = edge[i_dir_1];\
104
btScalar pmin = pointa[i_comp_0]*dir0 + pointa[i_comp_1]*dir1;\
105
btScalar pmax = pointb[i_comp_0]*dir0 + pointb[i_comp_1]*dir1;\
108
GIM_SWAP_NUMBERS(pmin,pmax); \
110
const btScalar abs_dir0 = absolute_edge[i_dir_0];\
111
const btScalar abs_dir1 = absolute_edge[i_dir_1];\
112
const btScalar rad = _extend[i_comp_0] * abs_dir0 + _extend[i_comp_1] * abs_dir1;\
113
if(pmin>rad || -rad>pmax) return false;\
117
#define TEST_CROSS_EDGE_BOX_X_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\
119
TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,2,1,1,2);\
122
#define TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\
124
TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,0,2,2,0);\
127
#define TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\
129
TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,1,0,0,1);\
134
//! Class for transforming a model1 to the space of model0
135
class GIM_BOX_BOX_TRANSFORM_CACHE
138
btVector3 m_T1to0;//!< Transforms translation of model1 to model 0
139
btMatrix3x3 m_R1to0;//!< Transforms Rotation of model1 to model 0, equal to R0' * R1
140
btMatrix3x3 m_AR;//!< Absolute value of m_R1to0
142
SIMD_FORCE_INLINE void calc_absolute_matrix()
144
static const btVector3 vepsi(1e-6f,1e-6f,1e-6f);
145
m_AR[0] = vepsi + m_R1to0[0].absolute();
146
m_AR[1] = vepsi + m_R1to0[1].absolute();
147
m_AR[2] = vepsi + m_R1to0[2].absolute();
150
GIM_BOX_BOX_TRANSFORM_CACHE()
155
GIM_BOX_BOX_TRANSFORM_CACHE(mat4f trans1_to_0)
157
COPY_MATRIX_3X3(m_R1to0,trans1_to_0)
158
MAT_GET_TRANSLATION(trans1_to_0,m_T1to0)
159
calc_absolute_matrix();
162
//! Calc the transformation relative 1 to 0. Inverts matrics by transposing
163
SIMD_FORCE_INLINE void calc_from_homogenic(const btTransform & trans0,const btTransform & trans1)
166
m_R1to0 = trans0.getBasis().transpose();
167
m_T1to0 = m_R1to0 * (-trans0.getOrigin());
169
m_T1to0 += m_R1to0*trans1.getOrigin();
170
m_R1to0 *= trans1.getBasis();
172
calc_absolute_matrix();
175
//! Calcs the full invertion of the matrices. Useful for scaling matrices
176
SIMD_FORCE_INLINE void calc_from_full_invert(const btTransform & trans0,const btTransform & trans1)
178
m_R1to0 = trans0.getBasis().inverse();
179
m_T1to0 = m_R1to0 * (-trans0.getOrigin());
181
m_T1to0 += m_R1to0*trans1.getOrigin();
182
m_R1to0 *= trans1.getBasis();
184
calc_absolute_matrix();
187
SIMD_FORCE_INLINE btVector3 transform(const btVector3 & point)
189
return btVector3(m_R1to0[0].dot(point) + m_T1to0.x(),
190
m_R1to0[1].dot(point) + m_T1to0.y(),
191
m_R1to0[2].dot(point) + m_T1to0.z());
196
#define BOX_PLANE_EPSILON 0.000001f
209
GIM_AABB(const btVector3 & V1,
210
const btVector3 & V2,
211
const btVector3 & V3)
213
m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]);
214
m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]);
215
m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]);
217
m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]);
218
m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]);
219
m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]);
222
GIM_AABB(const btVector3 & V1,
223
const btVector3 & V2,
224
const btVector3 & V3,
227
m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]);
228
m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]);
229
m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]);
231
m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]);
232
m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]);
233
m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]);
243
GIM_AABB(const GIM_AABB &other):
244
m_min(other.m_min),m_max(other.m_max)
248
GIM_AABB(const GIM_AABB &other,btScalar margin ):
249
m_min(other.m_min),m_max(other.m_max)
259
SIMD_FORCE_INLINE void invalidate()
261
m_min[0] = G_REAL_INFINITY;
262
m_min[1] = G_REAL_INFINITY;
263
m_min[2] = G_REAL_INFINITY;
264
m_max[0] = -G_REAL_INFINITY;
265
m_max[1] = -G_REAL_INFINITY;
266
m_max[2] = -G_REAL_INFINITY;
269
SIMD_FORCE_INLINE void increment_margin(btScalar margin)
279
SIMD_FORCE_INLINE void copy_with_margin(const GIM_AABB &other, btScalar margin)
281
m_min[0] = other.m_min[0] - margin;
282
m_min[1] = other.m_min[1] - margin;
283
m_min[2] = other.m_min[2] - margin;
285
m_max[0] = other.m_max[0] + margin;
286
m_max[1] = other.m_max[1] + margin;
287
m_max[2] = other.m_max[2] + margin;
290
template<typename CLASS_POINT>
291
SIMD_FORCE_INLINE void calc_from_triangle(
292
const CLASS_POINT & V1,
293
const CLASS_POINT & V2,
294
const CLASS_POINT & V3)
296
m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]);
297
m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]);
298
m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]);
300
m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]);
301
m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]);
302
m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]);
305
template<typename CLASS_POINT>
306
SIMD_FORCE_INLINE void calc_from_triangle_margin(
307
const CLASS_POINT & V1,
308
const CLASS_POINT & V2,
309
const CLASS_POINT & V3, btScalar margin)
311
m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]);
312
m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]);
313
m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]);
315
m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]);
316
m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]);
317
m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]);
327
//! Apply a transform to an AABB
328
SIMD_FORCE_INLINE void appy_transform(const btTransform & trans)
330
btVector3 center = (m_max+m_min)*0.5f;
331
btVector3 extends = m_max - center;
332
// Compute new center
333
center = trans(center);
335
btVector3 textends(extends.dot(trans.getBasis().getRow(0).absolute()),
336
extends.dot(trans.getBasis().getRow(1).absolute()),
337
extends.dot(trans.getBasis().getRow(2).absolute()));
339
m_min = center - textends;
340
m_max = center + textends;
344
SIMD_FORCE_INLINE void merge(const GIM_AABB & box)
346
m_min[0] = GIM_MIN(m_min[0],box.m_min[0]);
347
m_min[1] = GIM_MIN(m_min[1],box.m_min[1]);
348
m_min[2] = GIM_MIN(m_min[2],box.m_min[2]);
350
m_max[0] = GIM_MAX(m_max[0],box.m_max[0]);
351
m_max[1] = GIM_MAX(m_max[1],box.m_max[1]);
352
m_max[2] = GIM_MAX(m_max[2],box.m_max[2]);
356
template<typename CLASS_POINT>
357
SIMD_FORCE_INLINE void merge_point(const CLASS_POINT & point)
359
m_min[0] = GIM_MIN(m_min[0],point[0]);
360
m_min[1] = GIM_MIN(m_min[1],point[1]);
361
m_min[2] = GIM_MIN(m_min[2],point[2]);
363
m_max[0] = GIM_MAX(m_max[0],point[0]);
364
m_max[1] = GIM_MAX(m_max[1],point[1]);
365
m_max[2] = GIM_MAX(m_max[2],point[2]);
368
//! Gets the extend and center
369
SIMD_FORCE_INLINE void get_center_extend(btVector3 & center,btVector3 & extend) const
371
center = (m_max+m_min)*0.5f;
372
extend = m_max - center;
375
//! Finds the intersecting box between this box and the other.
376
SIMD_FORCE_INLINE void find_intersection(const GIM_AABB & other, GIM_AABB & intersection) const
378
intersection.m_min[0] = GIM_MAX(other.m_min[0],m_min[0]);
379
intersection.m_min[1] = GIM_MAX(other.m_min[1],m_min[1]);
380
intersection.m_min[2] = GIM_MAX(other.m_min[2],m_min[2]);
382
intersection.m_max[0] = GIM_MIN(other.m_max[0],m_max[0]);
383
intersection.m_max[1] = GIM_MIN(other.m_max[1],m_max[1]);
384
intersection.m_max[2] = GIM_MIN(other.m_max[2],m_max[2]);
388
SIMD_FORCE_INLINE bool has_collision(const GIM_AABB & other) const
390
if(m_min[0] > other.m_max[0] ||
391
m_max[0] < other.m_min[0] ||
392
m_min[1] > other.m_max[1] ||
393
m_max[1] < other.m_min[1] ||
394
m_min[2] > other.m_max[2] ||
395
m_max[2] < other.m_min[2])
402
/*! \brief Finds the Ray intersection parameter.
403
\param aabb Aligned box
404
\param vorigin A vec3f with the origin of the ray
405
\param vdir A vec3f with the direction of the ray
407
SIMD_FORCE_INLINE bool collide_ray(const btVector3 & vorigin,const btVector3 & vdir)
409
btVector3 extents,center;
410
this->get_center_extend(center,extents);;
412
btScalar Dx = vorigin[0] - center[0];
413
if(GIM_GREATER(Dx, extents[0]) && Dx*vdir[0]>=0.0f) return false;
414
btScalar Dy = vorigin[1] - center[1];
415
if(GIM_GREATER(Dy, extents[1]) && Dy*vdir[1]>=0.0f) return false;
416
btScalar Dz = vorigin[2] - center[2];
417
if(GIM_GREATER(Dz, extents[2]) && Dz*vdir[2]>=0.0f) return false;
420
btScalar f = vdir[1] * Dz - vdir[2] * Dy;
421
if(btFabs(f) > extents[1]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[1])) return false;
422
f = vdir[2] * Dx - vdir[0] * Dz;
423
if(btFabs(f) > extents[0]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[0]))return false;
424
f = vdir[0] * Dy - vdir[1] * Dx;
425
if(btFabs(f) > extents[0]*btFabs(vdir[1]) + extents[1]*btFabs(vdir[0]))return false;
430
SIMD_FORCE_INLINE void projection_interval(const btVector3 & direction, btScalar &vmin, btScalar &vmax) const
432
btVector3 center = (m_max+m_min)*0.5f;
433
btVector3 extend = m_max-center;
435
btScalar _fOrigin = direction.dot(center);
436
btScalar _fMaximumExtent = extend.dot(direction.absolute());
437
vmin = _fOrigin - _fMaximumExtent;
438
vmax = _fOrigin + _fMaximumExtent;
441
SIMD_FORCE_INLINE ePLANE_INTERSECTION_TYPE plane_classify(const btVector4 &plane) const
443
btScalar _fmin,_fmax;
444
this->projection_interval(plane,_fmin,_fmax);
446
if(plane[3] > _fmax + BOX_PLANE_EPSILON)
448
return G_BACK_PLANE; // 0
451
if(plane[3]+BOX_PLANE_EPSILON >=_fmin)
453
return G_COLLIDE_PLANE; //1
455
return G_FRONT_PLANE;//2
458
SIMD_FORCE_INLINE bool overlapping_trans_conservative(const GIM_AABB & box, btTransform & trans1_to_0)
461
tbox.appy_transform(trans1_to_0);
462
return has_collision(tbox);
465
//! transcache is the transformation cache from box to this AABB
466
SIMD_FORCE_INLINE bool overlapping_trans_cache(
467
const GIM_AABB & box,const GIM_BOX_BOX_TRANSFORM_CACHE & transcache, bool fulltest)
471
btVector3 ea,eb;//extends
472
btVector3 ca,cb;//extends
473
get_center_extend(ca,ea);
474
box.get_center_extend(cb,eb);
481
// Class I : A's basis vectors
484
T[i] = transcache.m_R1to0[i].dot(cb) + transcache.m_T1to0[i] - ca[i];
485
t = transcache.m_AR[i].dot(eb) + ea[i];
486
if(GIM_GREATER(T[i], t)) return false;
488
// Class II : B's basis vectors
491
t = MAT_DOT_COL(transcache.m_R1to0,T,i);
492
t2 = MAT_DOT_COL(transcache.m_AR,ea,i) + eb[i];
493
if(GIM_GREATER(t,t2)) return false;
495
// Class III : 9 cross products
509
t = T[n]*transcache.m_R1to0[m][j] - T[m]*transcache.m_R1to0[n][j];
510
t2 = ea[o]*transcache.m_AR[p][j] + ea[p]*transcache.m_AR[o][j] +
511
eb[r]*transcache.m_AR[i][q] + eb[q]*transcache.m_AR[i][r];
512
if(GIM_GREATER(t,t2)) return false;
519
//! Simple test for planes.
520
SIMD_FORCE_INLINE bool collide_plane(
521
const btVector4 & plane)
523
ePLANE_INTERSECTION_TYPE classify = plane_classify(plane);
524
return (classify == G_COLLIDE_PLANE);
527
//! test for a triangle, with edges
528
SIMD_FORCE_INLINE bool collide_triangle_exact(
529
const btVector3 & p1,
530
const btVector3 & p2,
531
const btVector3 & p3,
532
const btVector4 & triangle_plane)
534
if(!collide_plane(triangle_plane)) return false;
536
btVector3 center,extends;
537
this->get_center_extend(center,extends);
539
const btVector3 v1(p1 - center);
540
const btVector3 v2(p2 - center);
541
const btVector3 v3(p3 - center);
544
btVector3 diff(v2 - v1);
545
btVector3 abs_diff = diff.absolute();
547
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v1,v3,extends);
549
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v1,v3,extends);
551
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v1,v3,extends);
555
abs_diff = diff.absolute();
557
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v2,v1,extends);
559
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v2,v1,extends);
561
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v2,v1,extends);
564
abs_diff = diff.absolute();
566
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v3,v2,extends);
568
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v3,v2,extends);
570
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v3,v2,extends);
577
//! Compairison of transformation objects
578
SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform & t1,const btTransform & t2)
580
if(!(t1.getOrigin() == t2.getOrigin()) ) return false;
582
if(!(t1.getBasis().getRow(0) == t2.getBasis().getRow(0)) ) return false;
583
if(!(t1.getBasis().getRow(1) == t2.getBasis().getRow(1)) ) return false;
584
if(!(t1.getBasis().getRow(2) == t2.getBasis().getRow(2)) ) return false;
590
#endif // GIM_BOX_COLLISION_H_INCLUDED