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"
38 //SIMD_FORCE_INLINE bool test_cross_edge_box(
39 // const btVector3 & edge,
40 // const btVector3 & absolute_edge,
41 // const btVector3 & pointa,
42 // const btVector3 & pointb, const btVector3 & extend,
45 // int component_index0,
46 // int component_index1)
48 // // dir coords are -z and y
50 // const btScalar dir0 = -edge[dir_index0];
51 // const btScalar dir1 = edge[dir_index1];
52 // btScalar pmin = pointa[component_index0]*dir0 + pointa[component_index1]*dir1;
53 // btScalar pmax = pointb[component_index0]*dir0 + pointb[component_index1]*dir1;
57 // GIM_SWAP_NUMBERS(pmin,pmax);
60 // const btScalar rad = extend[component_index0] * absolute_edge[dir_index0] +
61 // extend[component_index1] * absolute_edge[dir_index1];
63 // if(pmin>rad || -rad>pmax) return false;
67 //SIMD_FORCE_INLINE bool test_cross_edge_box_X_axis(
68 // const btVector3 & edge,
69 // const btVector3 & absolute_edge,
70 // const btVector3 & pointa,
71 // const btVector3 & pointb, btVector3 & extend)
74 // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,2,1,1,2);
78 //SIMD_FORCE_INLINE bool test_cross_edge_box_Y_axis(
79 // const btVector3 & edge,
80 // const btVector3 & absolute_edge,
81 // const btVector3 & pointa,
82 // const btVector3 & pointb, btVector3 & extend)
85 // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,0,2,2,0);
88 //SIMD_FORCE_INLINE bool test_cross_edge_box_Z_axis(
89 // const btVector3 & edge,
90 // const btVector3 & absolute_edge,
91 // const btVector3 & pointa,
92 // const btVector3 & pointb, btVector3 & extend)
95 // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,1,0,0,1);
98 #ifndef TEST_CROSS_EDGE_BOX_MCR
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; \
118 #define TEST_CROSS_EDGE_BOX_X_AXIS_MCR(edge, absolute_edge, pointa, pointb, _extend) \
120 TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 2, 1, 1, 2); \
123 #define TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(edge, absolute_edge, pointa, pointb, _extend) \
125 TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 0, 2, 2, 0); \
128 #define TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(edge, absolute_edge, pointa, pointb, _extend) \
130 TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 1, 0, 0, 1); \
133 //! Class for transforming a model1 to the space of model0
134 class GIM_BOX_BOX_TRANSFORM_CACHE
137 btVector3 m_T1to0; //!< Transforms translation of model1 to model 0
138 btMatrix3x3 m_R1to0; //!< Transforms Rotation of model1 to model 0, equal to R0' * R1
139 btMatrix3x3 m_AR; //!< Absolute value of m_R1to0
141 SIMD_FORCE_INLINE void calc_absolute_matrix()
143 static const btVector3 vepsi(1e-6f, 1e-6f, 1e-6f);
144 m_AR[0] = vepsi + m_R1to0[0].absolute();
145 m_AR[1] = vepsi + m_R1to0[1].absolute();
146 m_AR[2] = vepsi + m_R1to0[2].absolute();
149 GIM_BOX_BOX_TRANSFORM_CACHE()
153 GIM_BOX_BOX_TRANSFORM_CACHE(mat4f trans1_to_0)
155 COPY_MATRIX_3X3(m_R1to0, trans1_to_0)
156 MAT_GET_TRANSLATION(trans1_to_0, m_T1to0)
157 calc_absolute_matrix();
160 //! Calc the transformation relative 1 to 0. Inverts matrics by transposing
161 SIMD_FORCE_INLINE void calc_from_homogenic(const btTransform &trans0, const btTransform &trans1)
163 m_R1to0 = trans0.getBasis().transpose();
164 m_T1to0 = m_R1to0 * (-trans0.getOrigin());
166 m_T1to0 += m_R1to0 * trans1.getOrigin();
167 m_R1to0 *= trans1.getBasis();
169 calc_absolute_matrix();
172 //! Calcs the full invertion of the matrices. Useful for scaling matrices
173 SIMD_FORCE_INLINE void calc_from_full_invert(const btTransform &trans0, const btTransform &trans1)
175 m_R1to0 = trans0.getBasis().inverse();
176 m_T1to0 = m_R1to0 * (-trans0.getOrigin());
178 m_T1to0 += m_R1to0 * trans1.getOrigin();
179 m_R1to0 *= trans1.getBasis();
181 calc_absolute_matrix();
184 SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point)
186 return point.dot3(m_R1to0[0], m_R1to0[1], m_R1to0[2]) + m_T1to0;
190 #ifndef BOX_PLANE_EPSILON
191 #define BOX_PLANE_EPSILON 0.000001f
205 GIM_AABB(const btVector3 &V1,
209 m_min[0] = GIM_MIN3(V1[0], V2[0], V3[0]);
210 m_min[1] = GIM_MIN3(V1[1], V2[1], V3[1]);
211 m_min[2] = GIM_MIN3(V1[2], V2[2], V3[2]);
213 m_max[0] = GIM_MAX3(V1[0], V2[0], V3[0]);
214 m_max[1] = GIM_MAX3(V1[1], V2[1], V3[1]);
215 m_max[2] = GIM_MAX3(V1[2], V2[2], V3[2]);
218 GIM_AABB(const btVector3 &V1,
223 m_min[0] = GIM_MIN3(V1[0], V2[0], V3[0]);
224 m_min[1] = GIM_MIN3(V1[1], V2[1], V3[1]);
225 m_min[2] = GIM_MIN3(V1[2], V2[2], V3[2]);
227 m_max[0] = GIM_MAX3(V1[0], V2[0], V3[0]);
228 m_max[1] = GIM_MAX3(V1[1], V2[1], V3[1]);
229 m_max[2] = GIM_MAX3(V1[2], V2[2], V3[2]);
239 GIM_AABB(const GIM_AABB &other) : m_min(other.m_min), m_max(other.m_max)
243 GIM_AABB(const GIM_AABB &other, btScalar margin) : m_min(other.m_min), m_max(other.m_max)
253 SIMD_FORCE_INLINE void invalidate()
255 m_min[0] = G_REAL_INFINITY;
256 m_min[1] = G_REAL_INFINITY;
257 m_min[2] = G_REAL_INFINITY;
258 m_max[0] = -G_REAL_INFINITY;
259 m_max[1] = -G_REAL_INFINITY;
260 m_max[2] = -G_REAL_INFINITY;
263 SIMD_FORCE_INLINE void increment_margin(btScalar margin)
273 SIMD_FORCE_INLINE void copy_with_margin(const GIM_AABB &other, btScalar margin)
275 m_min[0] = other.m_min[0] - margin;
276 m_min[1] = other.m_min[1] - margin;
277 m_min[2] = other.m_min[2] - margin;
279 m_max[0] = other.m_max[0] + margin;
280 m_max[1] = other.m_max[1] + margin;
281 m_max[2] = other.m_max[2] + margin;
284 template <typename CLASS_POINT>
285 SIMD_FORCE_INLINE void calc_from_triangle(
286 const CLASS_POINT &V1,
287 const CLASS_POINT &V2,
288 const CLASS_POINT &V3)
290 m_min[0] = GIM_MIN3(V1[0], V2[0], V3[0]);
291 m_min[1] = GIM_MIN3(V1[1], V2[1], V3[1]);
292 m_min[2] = GIM_MIN3(V1[2], V2[2], V3[2]);
294 m_max[0] = GIM_MAX3(V1[0], V2[0], V3[0]);
295 m_max[1] = GIM_MAX3(V1[1], V2[1], V3[1]);
296 m_max[2] = GIM_MAX3(V1[2], V2[2], V3[2]);
299 template <typename CLASS_POINT>
300 SIMD_FORCE_INLINE void calc_from_triangle_margin(
301 const CLASS_POINT &V1,
302 const CLASS_POINT &V2,
303 const CLASS_POINT &V3, btScalar margin)
305 m_min[0] = GIM_MIN3(V1[0], V2[0], V3[0]);
306 m_min[1] = GIM_MIN3(V1[1], V2[1], V3[1]);
307 m_min[2] = GIM_MIN3(V1[2], V2[2], V3[2]);
309 m_max[0] = GIM_MAX3(V1[0], V2[0], V3[0]);
310 m_max[1] = GIM_MAX3(V1[1], V2[1], V3[1]);
311 m_max[2] = GIM_MAX3(V1[2], V2[2], V3[2]);
321 //! Apply a transform to an AABB
322 SIMD_FORCE_INLINE void appy_transform(const btTransform &trans)
324 btVector3 center = (m_max + m_min) * 0.5f;
325 btVector3 extends = m_max - center;
326 // Compute new center
327 center = trans(center);
329 btVector3 textends = extends.dot3(trans.getBasis().getRow(0).absolute(),
330 trans.getBasis().getRow(1).absolute(),
331 trans.getBasis().getRow(2).absolute());
333 m_min = center - textends;
334 m_max = center + textends;
338 SIMD_FORCE_INLINE void merge(const GIM_AABB &box)
340 m_min[0] = GIM_MIN(m_min[0], box.m_min[0]);
341 m_min[1] = GIM_MIN(m_min[1], box.m_min[1]);
342 m_min[2] = GIM_MIN(m_min[2], box.m_min[2]);
344 m_max[0] = GIM_MAX(m_max[0], box.m_max[0]);
345 m_max[1] = GIM_MAX(m_max[1], box.m_max[1]);
346 m_max[2] = GIM_MAX(m_max[2], box.m_max[2]);
350 template <typename CLASS_POINT>
351 SIMD_FORCE_INLINE void merge_point(const CLASS_POINT &point)
353 m_min[0] = GIM_MIN(m_min[0], point[0]);
354 m_min[1] = GIM_MIN(m_min[1], point[1]);
355 m_min[2] = GIM_MIN(m_min[2], point[2]);
357 m_max[0] = GIM_MAX(m_max[0], point[0]);
358 m_max[1] = GIM_MAX(m_max[1], point[1]);
359 m_max[2] = GIM_MAX(m_max[2], point[2]);
362 //! Gets the extend and center
363 SIMD_FORCE_INLINE void get_center_extend(btVector3 ¢er, btVector3 &extend) const
365 center = (m_max + m_min) * 0.5f;
366 extend = m_max - center;
369 //! Finds the intersecting box between this box and the other.
370 SIMD_FORCE_INLINE void find_intersection(const GIM_AABB &other, GIM_AABB &intersection) const
372 intersection.m_min[0] = GIM_MAX(other.m_min[0], m_min[0]);
373 intersection.m_min[1] = GIM_MAX(other.m_min[1], m_min[1]);
374 intersection.m_min[2] = GIM_MAX(other.m_min[2], m_min[2]);
376 intersection.m_max[0] = GIM_MIN(other.m_max[0], m_max[0]);
377 intersection.m_max[1] = GIM_MIN(other.m_max[1], m_max[1]);
378 intersection.m_max[2] = GIM_MIN(other.m_max[2], m_max[2]);
381 SIMD_FORCE_INLINE bool has_collision(const GIM_AABB &other) const
383 if (m_min[0] > other.m_max[0] ||
384 m_max[0] < other.m_min[0] ||
385 m_min[1] > other.m_max[1] ||
386 m_max[1] < other.m_min[1] ||
387 m_min[2] > other.m_max[2] ||
388 m_max[2] < other.m_min[2])
395 /*! \brief Finds the Ray intersection parameter.
396 \param aabb Aligned box
397 \param vorigin A vec3f with the origin of the ray
398 \param vdir A vec3f with the direction of the ray
400 SIMD_FORCE_INLINE bool collide_ray(const btVector3 &vorigin, const btVector3 &vdir)
402 btVector3 extents, center;
403 this->get_center_extend(center, extents);
406 btScalar Dx = vorigin[0] - center[0];
407 if (GIM_GREATER(Dx, extents[0]) && Dx * vdir[0] >= 0.0f) return false;
408 btScalar Dy = vorigin[1] - center[1];
409 if (GIM_GREATER(Dy, extents[1]) && Dy * vdir[1] >= 0.0f) return false;
410 btScalar Dz = vorigin[2] - center[2];
411 if (GIM_GREATER(Dz, extents[2]) && Dz * vdir[2] >= 0.0f) return false;
413 btScalar f = vdir[1] * Dz - vdir[2] * Dy;
414 if (btFabs(f) > extents[1] * btFabs(vdir[2]) + extents[2] * btFabs(vdir[1])) return false;
415 f = vdir[2] * Dx - vdir[0] * Dz;
416 if (btFabs(f) > extents[0] * btFabs(vdir[2]) + extents[2] * btFabs(vdir[0])) return false;
417 f = vdir[0] * Dy - vdir[1] * Dx;
418 if (btFabs(f) > extents[0] * btFabs(vdir[1]) + extents[1] * btFabs(vdir[0])) return false;
422 SIMD_FORCE_INLINE void projection_interval(const btVector3 &direction, btScalar &vmin, btScalar &vmax) const
424 btVector3 center = (m_max + m_min) * 0.5f;
425 btVector3 extend = m_max - center;
427 btScalar _fOrigin = direction.dot(center);
428 btScalar _fMaximumExtent = extend.dot(direction.absolute());
429 vmin = _fOrigin - _fMaximumExtent;
430 vmax = _fOrigin + _fMaximumExtent;
433 SIMD_FORCE_INLINE ePLANE_INTERSECTION_TYPE plane_classify(const btVector4 &plane) const
435 btScalar _fmin, _fmax;
436 this->projection_interval(plane, _fmin, _fmax);
438 if (plane[3] > _fmax + BOX_PLANE_EPSILON)
440 return G_BACK_PLANE; // 0
443 if (plane[3] + BOX_PLANE_EPSILON >= _fmin)
445 return G_COLLIDE_PLANE; //1
447 return G_FRONT_PLANE; //2
450 SIMD_FORCE_INLINE bool overlapping_trans_conservative(const GIM_AABB &box, btTransform &trans1_to_0)
453 tbox.appy_transform(trans1_to_0);
454 return has_collision(tbox);
457 //! transcache is the transformation cache from box to this AABB
458 SIMD_FORCE_INLINE bool overlapping_trans_cache(
459 const GIM_AABB &box, const GIM_BOX_BOX_TRANSFORM_CACHE &transcache, bool fulltest)
462 btVector3 ea, eb; //extends
463 btVector3 ca, cb; //extends
464 get_center_extend(ca, ea);
465 box.get_center_extend(cb, eb);
471 // Class I : A's basis vectors
472 for (i = 0; i < 3; i++)
474 T[i] = transcache.m_R1to0[i].dot(cb) + transcache.m_T1to0[i] - ca[i];
475 t = transcache.m_AR[i].dot(eb) + ea[i];
476 if (GIM_GREATER(T[i], t)) return false;
478 // Class II : B's basis vectors
479 for (i = 0; i < 3; i++)
481 t = MAT_DOT_COL(transcache.m_R1to0, T, i);
482 t2 = MAT_DOT_COL(transcache.m_AR, ea, i) + eb[i];
483 if (GIM_GREATER(t, t2)) return false;
485 // Class III : 9 cross products
488 int j, m, n, o, p, q, r;
489 for (i = 0; i < 3; i++)
495 for (j = 0; j < 3; j++)
499 t = T[n] * transcache.m_R1to0[m][j] - T[m] * transcache.m_R1to0[n][j];
500 t2 = ea[o] * transcache.m_AR[p][j] + ea[p] * transcache.m_AR[o][j] +
501 eb[r] * transcache.m_AR[i][q] + eb[q] * transcache.m_AR[i][r];
502 if (GIM_GREATER(t, t2)) return false;
509 //! Simple test for planes.
510 SIMD_FORCE_INLINE bool collide_plane(
511 const btVector4 &plane)
513 ePLANE_INTERSECTION_TYPE classify = plane_classify(plane);
514 return (classify == G_COLLIDE_PLANE);
517 //! test for a triangle, with edges
518 SIMD_FORCE_INLINE bool collide_triangle_exact(
522 const btVector4 &triangle_plane)
524 if (!collide_plane(triangle_plane)) return false;
526 btVector3 center, extends;
527 this->get_center_extend(center, extends);
529 const btVector3 v1(p1 - center);
530 const btVector3 v2(p2 - center);
531 const btVector3 v3(p3 - center);
534 btVector3 diff(v2 - v1);
535 btVector3 abs_diff = diff.absolute();
537 TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v1, v3, extends);
539 TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v1, v3, extends);
541 TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v1, v3, extends);
544 abs_diff = diff.absolute();
546 TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v2, v1, extends);
548 TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v2, v1, extends);
550 TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v2, v1, extends);
553 abs_diff = diff.absolute();
555 TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v3, v2, extends);
557 TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v3, v2, extends);
559 TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v3, v2, extends);
565 #ifndef BT_BOX_COLLISION_H_INCLUDED
566 //! Compairison of transformation objects
567 SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform &t1, const btTransform &t2)
569 if (!(t1.getOrigin() == t2.getOrigin())) return false;
571 if (!(t1.getBasis().getRow(0) == t2.getBasis().getRow(0))) return false;
572 if (!(t1.getBasis().getRow(1) == t2.getBasis().getRow(1))) return false;
573 if (!(t1.getBasis().getRow(2) == t2.getBasis().getRow(2))) return false;
578 #endif // GIM_BOX_COLLISION_H_INCLUDED