com.bulletphysics.extras.gimpact.BoxCollision Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbullet Show documentation
Show all versions of jbullet Show documentation
JBullet - Java port of Bullet Physics Library
The newest version!
/*
* Java port of Bullet (c) 2008 Martin Dvorak
*
* This source file is part of GIMPACT Library.
*
* For the latest info, see http://gimpact.sourceforge.net/
*
* Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371.
* email: [email protected]
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package com.bulletphysics.extras.gimpact;
import com.bulletphysics.BulletGlobals;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.VectorUtil;
import cz.advel.stack.Stack;
import javax.vecmath.Matrix3f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
/**
*
* @author jezek2
*/
class BoxCollision {
public static final float BOX_PLANE_EPSILON = 0.000001f;
public static boolean BT_GREATER(float x, float y) {
return Math.abs(x) > y;
}
public static float BT_MAX3(float a, float b, float c) {
return Math.max(a, Math.max(b, c));
}
public static float BT_MIN3(float a, float b, float c) {
return Math.min(a, Math.min(b, c));
}
public static boolean TEST_CROSS_EDGE_BOX_MCR(Vector3f edge, Vector3f absolute_edge, Vector3f pointa, Vector3f pointb, Vector3f _extend, int i_dir_0, int i_dir_1, int i_comp_0, int i_comp_1) {
float dir0 = -VectorUtil.getCoord(edge, i_dir_0);
float dir1 = VectorUtil.getCoord(edge, i_dir_1);
float pmin = VectorUtil.getCoord(pointa, i_comp_0) * dir0 + VectorUtil.getCoord(pointa, i_comp_1) * dir1;
float pmax = VectorUtil.getCoord(pointb, i_comp_0) * dir0 + VectorUtil.getCoord(pointb, i_comp_1) * dir1;
if (pmin > pmax) {
//BT_SWAP_NUMBERS(pmin,pmax);
pmin = pmin + pmax;
pmax = pmin - pmax;
pmin = pmin - pmax;
}
float abs_dir0 = VectorUtil.getCoord(absolute_edge, i_dir_0);
float abs_dir1 = VectorUtil.getCoord(absolute_edge, i_dir_1);
float rad = VectorUtil.getCoord(_extend, i_comp_0) * abs_dir0 + VectorUtil.getCoord(_extend, i_comp_1) * abs_dir1;
if (pmin > rad || -rad > pmax) {
return false;
}
return true;
}
public static boolean TEST_CROSS_EDGE_BOX_X_AXIS_MCR(Vector3f edge, Vector3f absolute_edge, Vector3f pointa, Vector3f pointb, Vector3f _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 2, 1, 1, 2);
}
public static boolean TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(Vector3f edge, Vector3f absolute_edge, Vector3f pointa, Vector3f pointb, Vector3f _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 0, 2, 2, 0);
}
public static boolean TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(Vector3f edge, Vector3f absolute_edge, Vector3f pointa, Vector3f pointb, Vector3f _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 1, 0, 0, 1);
}
/**
* Returns the dot product between a vec3f and the col of a matrix.
*/
public static float bt_mat3_dot_col(Matrix3f mat, Vector3f vec3, int colindex) {
return vec3.x*mat.getElement(0, colindex) + vec3.y*mat.getElement(1, colindex) + vec3.z*mat.getElement(2, colindex);
}
/**
* Compairison of transformation objects.
*/
public static boolean compareTransformsEqual(Transform t1, Transform t2) {
return t1.equals(t2);
}
////////////////////////////////////////////////////////////////////////////
public static class BoxBoxTransformCache {
public final Vector3f T1to0 = new Vector3f(); // Transforms translation of model1 to model 0
public final Matrix3f R1to0 = new Matrix3f(); // Transforms Rotation of model1 to model 0, equal to R0' * R1
public final Matrix3f AR = new Matrix3f(); // Absolute value of m_R1to0
public void set(BoxBoxTransformCache cache) {
throw new UnsupportedOperationException();
}
public void calc_absolute_matrix() {
//static const btVector3 vepsi(1e-6f,1e-6f,1e-6f);
//m_AR[0] = vepsi + m_R1to0[0].absolute();
//m_AR[1] = vepsi + m_R1to0[1].absolute();
//m_AR[2] = vepsi + m_R1to0[2].absolute();
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
AR.setElement(i, j, 1e-6f + Math.abs(R1to0.getElement(i, j)));
}
}
}
/**
* Calc the transformation relative 1 to 0. Inverts matrics by transposing.
*/
public void calc_from_homogenic(Transform trans0, Transform trans1) {
Transform temp_trans = Stack.alloc(Transform.class);
temp_trans.inverse(trans0);
temp_trans.mul(trans1);
T1to0.set(temp_trans.origin);
R1to0.set(temp_trans.basis);
calc_absolute_matrix();
}
/**
* Calcs the full invertion of the matrices. Useful for scaling matrices.
*/
public void calc_from_full_invert(Transform trans0, Transform trans1) {
R1to0.invert(trans0.basis);
T1to0.negate(trans0.origin);
R1to0.transform(T1to0);
Vector3f tmp = Stack.alloc(Vector3f.class);
tmp.set(trans1.origin);
R1to0.transform(tmp);
T1to0.add(tmp);
R1to0.mul(trans1.basis);
calc_absolute_matrix();
}
public Vector3f transform(Vector3f point, Vector3f out) {
if (point == out) {
point = Stack.alloc(point);
}
Vector3f tmp = Stack.alloc(Vector3f.class);
R1to0.getRow(0, tmp);
out.x = tmp.dot(point) + T1to0.x;
R1to0.getRow(1, tmp);
out.y = tmp.dot(point) + T1to0.y;
R1to0.getRow(2, tmp);
out.z = tmp.dot(point) + T1to0.z;
return out;
}
}
////////////////////////////////////////////////////////////////////////////
public static class AABB {
public final Vector3f min = new Vector3f();
public final Vector3f max = new Vector3f();
public AABB() {
}
public AABB(Vector3f V1, Vector3f V2, Vector3f V3) {
calc_from_triangle(V1, V2, V3);
}
public AABB(Vector3f V1, Vector3f V2, Vector3f V3, float margin) {
calc_from_triangle_margin(V1, V2, V3, margin);
}
public AABB(AABB other) {
set(other);
}
public AABB(AABB other, float margin) {
this(other);
min.x -= margin;
min.y -= margin;
min.z -= margin;
max.x += margin;
max.y += margin;
max.z += margin;
}
public void init(Vector3f V1, Vector3f V2, Vector3f V3, float margin) {
calc_from_triangle_margin(V1, V2, V3, margin);
}
public void set(AABB other) {
min.set(other.min);
max.set(other.max);
}
public void invalidate() {
min.set(BulletGlobals.SIMD_INFINITY, BulletGlobals.SIMD_INFINITY, BulletGlobals.SIMD_INFINITY);
max.set(-BulletGlobals.SIMD_INFINITY, -BulletGlobals.SIMD_INFINITY, -BulletGlobals.SIMD_INFINITY);
}
public void increment_margin(float margin) {
min.x -= margin;
min.y -= margin;
min.z -= margin;
max.x += margin;
max.y += margin;
max.z += margin;
}
public void copy_with_margin(AABB other, float margin) {
min.x = other.min.x - margin;
min.y = other.min.y - margin;
min.z = other.min.z - margin;
max.x = other.max.x + margin;
max.y = other.max.y + margin;
max.z = other.max.z + margin;
}
public void calc_from_triangle(Vector3f V1, Vector3f V2, Vector3f V3) {
min.x = BT_MIN3(V1.x, V2.x, V3.x);
min.y = BT_MIN3(V1.y, V2.y, V3.y);
min.z = BT_MIN3(V1.z, V2.z, V3.z);
max.x = BT_MAX3(V1.x, V2.x, V3.x);
max.y = BT_MAX3(V1.y, V2.y, V3.y);
max.z = BT_MAX3(V1.z, V2.z, V3.z);
}
public void calc_from_triangle_margin(Vector3f V1, Vector3f V2, Vector3f V3, float margin) {
calc_from_triangle(V1, V2, V3);
min.x -= margin;
min.y -= margin;
min.z -= margin;
max.x += margin;
max.y += margin;
max.z += margin;
}
/**
* Apply a transform to an AABB.
*/
public void appy_transform(Transform trans) {
Vector3f tmp = Stack.alloc(Vector3f.class);
Vector3f center = Stack.alloc(Vector3f.class);
center.add(max, min);
center.scale(0.5f);
Vector3f extends_ = Stack.alloc(Vector3f.class);
extends_.sub(max, center);
// Compute new center
trans.transform(center);
Vector3f textends = Stack.alloc(Vector3f.class);
trans.basis.getRow(0, tmp);
tmp.absolute();
textends.x = extends_.dot(tmp);
trans.basis.getRow(1, tmp);
tmp.absolute();
textends.y = extends_.dot(tmp);
trans.basis.getRow(2, tmp);
tmp.absolute();
textends.z = extends_.dot(tmp);
min.sub(center, textends);
max.add(center, textends);
}
/**
* Apply a transform to an AABB.
*/
public void appy_transform_trans_cache(BoxBoxTransformCache trans) {
Vector3f tmp = Stack.alloc(Vector3f.class);
Vector3f center = Stack.alloc(Vector3f.class);
center.add(max, min);
center.scale(0.5f);
Vector3f extends_ = Stack.alloc(Vector3f.class);
extends_.sub(max, center);
// Compute new center
trans.transform(center, center);
Vector3f textends = Stack.alloc(Vector3f.class);
trans.R1to0.getRow(0, tmp);
tmp.absolute();
textends.x = extends_.dot(tmp);
trans.R1to0.getRow(1, tmp);
tmp.absolute();
textends.y = extends_.dot(tmp);
trans.R1to0.getRow(2, tmp);
tmp.absolute();
textends.z = extends_.dot(tmp);
min.sub(center, textends);
max.add(center, textends);
}
/**
* Merges a Box.
*/
public void merge(AABB box) {
min.x = Math.min(min.x, box.min.x);
min.y = Math.min(min.y, box.min.y);
min.z = Math.min(min.z, box.min.z);
max.x = Math.max(max.x, box.max.x);
max.y = Math.max(max.y, box.max.y);
max.z = Math.max(max.z, box.max.z);
}
/**
* Merges a point.
*/
public void merge_point(Vector3f point) {
min.x = Math.min(min.x, point.x);
min.y = Math.min(min.y, point.y);
min.z = Math.min(min.z, point.z);
max.x = Math.max(max.x, point.x);
max.y = Math.max(max.y, point.y);
max.z = Math.max(max.z, point.z);
}
/**
* Gets the extend and center.
*/
public void get_center_extend(Vector3f center, Vector3f extend) {
center.add(max, min);
center.scale(0.5f);
extend.sub(max, center);
}
/**
* Finds the intersecting box between this box and the other.
*/
public void find_intersection(AABB other, AABB intersection) {
intersection.min.x = Math.max(other.min.x, min.x);
intersection.min.y = Math.max(other.min.y, min.y);
intersection.min.z = Math.max(other.min.z, min.z);
intersection.max.x = Math.min(other.max.x, max.x);
intersection.max.y = Math.min(other.max.y, max.y);
intersection.max.z = Math.min(other.max.z, max.z);
}
public boolean has_collision(AABB other) {
if (min.x > other.max.x ||
max.x < other.min.x ||
min.y > other.max.y ||
max.y < other.min.y ||
min.z > other.max.z ||
max.z < other.min.z) {
return false;
}
return true;
}
/**
* Finds the Ray intersection parameter.
*
* @param aabb aligned box
* @param vorigin a vec3f with the origin of the ray
* @param vdir a vec3f with the direction of the ray
*/
public boolean collide_ray(Vector3f vorigin, Vector3f vdir) {
Vector3f extents = Stack.alloc(Vector3f.class), center = Stack.alloc(Vector3f.class);
get_center_extend(center, extents);
float Dx = vorigin.x - center.x;
if (BT_GREATER(Dx, extents.x) && Dx * vdir.x >= 0.0f) return false;
float Dy = vorigin.y - center.y;
if (BT_GREATER(Dy, extents.y) && Dy * vdir.y >= 0.0f) return false;
float Dz = vorigin.z - center.z;
if (BT_GREATER(Dz, extents.z) && Dz * vdir.z >= 0.0f) return false;
float f = vdir.y * Dz - vdir.z * Dy;
if (Math.abs(f) > extents.y * Math.abs(vdir.z) + extents.z * Math.abs(vdir.y)) return false;
f = vdir.z * Dx - vdir.x * Dz;
if (Math.abs(f) > extents.x * Math.abs(vdir.z) + extents.z * Math.abs(vdir.x)) return false;
f = vdir.x * Dy - vdir.y * Dx;
if (Math.abs(f) > extents.x * Math.abs(vdir.y) + extents.y * Math.abs(vdir.x)) return false;
return true;
}
public void projection_interval(Vector3f direction, float[] vmin, float[] vmax) {
Vector3f tmp = Stack.alloc(Vector3f.class);
Vector3f center = Stack.alloc(Vector3f.class);
Vector3f extend = Stack.alloc(Vector3f.class);
get_center_extend(center, extend);
float _fOrigin = direction.dot(center);
tmp.absolute(direction);
float _fMaximumExtent = extend.dot(tmp);
vmin[0] = _fOrigin - _fMaximumExtent;
vmax[0] = _fOrigin + _fMaximumExtent;
}
public PlaneIntersectionType plane_classify(Vector4f plane) {
Vector3f tmp = Stack.alloc(Vector3f.class);
float[] _fmin = new float[1], _fmax = new float[1];
tmp.set(plane.x, plane.y, plane.z);
projection_interval(tmp, _fmin, _fmax);
if (plane.w > _fmax[0] + BOX_PLANE_EPSILON) {
return PlaneIntersectionType.BACK_PLANE; // 0
}
if (plane.w + BOX_PLANE_EPSILON >= _fmin[0]) {
return PlaneIntersectionType.COLLIDE_PLANE; //1
}
return PlaneIntersectionType.FRONT_PLANE; //2
}
public boolean overlapping_trans_conservative(AABB box, Transform trans1_to_0) {
AABB tbox = Stack.alloc(box);
tbox.appy_transform(trans1_to_0);
return has_collision(tbox);
}
public boolean overlapping_trans_conservative2(AABB box, BoxBoxTransformCache trans1_to_0) {
AABB tbox = Stack.alloc(box);
tbox.appy_transform_trans_cache(trans1_to_0);
return has_collision(tbox);
}
/**
* transcache is the transformation cache from box to this AABB.
*/
public boolean overlapping_trans_cache(AABB box, BoxBoxTransformCache transcache, boolean fulltest) {
Vector3f tmp = Stack.alloc(Vector3f.class);
// Taken from OPCODE
Vector3f ea = Stack.alloc(Vector3f.class), eb = Stack.alloc(Vector3f.class); //extends
Vector3f ca = Stack.alloc(Vector3f.class), cb = Stack.alloc(Vector3f.class); //extends
get_center_extend(ca, ea);
box.get_center_extend(cb, eb);
Vector3f T = Stack.alloc(Vector3f.class);
float t, t2;
// Class I : A's basis vectors
for (int i=0; i<3; i++) {
transcache.R1to0.getRow(i, tmp);
VectorUtil.setCoord(T, i, tmp.dot(cb) + VectorUtil.getCoord(transcache.T1to0, i) - VectorUtil.getCoord(ca, i));
transcache.AR.getRow(i, tmp);
t = tmp.dot(eb) + VectorUtil.getCoord(ea, i);
if (BT_GREATER(VectorUtil.getCoord(T, i), t)) {
return false;
}
}
// Class II : B's basis vectors
for (int i=0; i<3; i++) {
t = bt_mat3_dot_col(transcache.R1to0, T, i);
t2 = bt_mat3_dot_col(transcache.AR, ea, i) + VectorUtil.getCoord(eb, i);
if (BT_GREATER(t, t2)) {
return false;
}
}
// Class III : 9 cross products
if (fulltest) {
int m, n, o, p, q, r;
for (int i = 0; i < 3; i++) {
m = (i+1) % 3;
n = (i+2) % 3;
o = (i == 0)? 1:0;
p = (i == 2)? 1:2;
for (int j=0; j<3; j++) {
q = j == 2 ? 1 : 2;
r = j == 0 ? 1 : 0;
t = VectorUtil.getCoord(T, n) * transcache.R1to0.getElement(m, j) - VectorUtil.getCoord(T, m) * transcache.R1to0.getElement(n, j);
t2 = VectorUtil.getCoord(ea, o) * transcache.AR.getElement(p, j) + VectorUtil.getCoord(ea, p) * transcache.AR.getElement(o, j) +
VectorUtil.getCoord(eb, r) * transcache.AR.getElement(i, q) + VectorUtil.getCoord(eb, q) * transcache.AR.getElement(i, r);
if (BT_GREATER(t, t2)) {
return false;
}
}
}
}
return true;
}
/**
* Simple test for planes.
*/
public boolean collide_plane(Vector4f plane) {
PlaneIntersectionType classify = plane_classify(plane);
return (classify == PlaneIntersectionType.COLLIDE_PLANE);
}
/**
* Test for a triangle, with edges.
*/
public boolean collide_triangle_exact(Vector3f p1, Vector3f p2, Vector3f p3, Vector4f triangle_plane) {
if (!collide_plane(triangle_plane)) {
return false;
}
Vector3f center = Stack.alloc(Vector3f.class), extends_ = Stack.alloc(Vector3f.class);
get_center_extend(center, extends_);
Vector3f v1 = Stack.alloc(Vector3f.class);
v1.sub(p1, center);
Vector3f v2 = Stack.alloc(Vector3f.class);
v2.sub(p2, center);
Vector3f v3 = Stack.alloc(Vector3f.class);
v3.sub(p3, center);
// First axis
Vector3f diff = Stack.alloc(Vector3f.class);
diff.sub(v2, v1);
Vector3f abs_diff = Stack.alloc(Vector3f.class);
abs_diff.absolute(diff);
// Test With X axis
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v1, v3, extends_);
// Test With Y axis
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v1, v3, extends_);
// Test With Z axis
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v1, v3, extends_);
diff.sub(v3, v2);
abs_diff.absolute(diff);
// Test With X axis
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v2, v1, extends_);
// Test With Y axis
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v2, v1, extends_);
// Test With Z axis
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v2, v1, extends_);
diff.sub(v1, v3);
abs_diff.absolute(diff);
// Test With X axis
TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v3, v2, extends_);
// Test With Y axis
TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v3, v2, extends_);
// Test With Z axis
TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v3, v2, extends_);
return true;
}
}
}