All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bulletphysics.extras.gimpact.BoxCollision Maven / Gradle / Ivy

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;
		}
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy