/* 
 | 
 * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz> 
 | 
 * 
 | 
 * Bullet Continuous Collision Detection and Physics Library 
 | 
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/ 
 | 
 * 
 | 
 * 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.collision.shapes; 
 | 
  
 | 
import com.bulletphysics.collision.broadphase.BroadphaseNativeType; 
 | 
import com.bulletphysics.linearmath.MatrixUtil; 
 | 
import com.bulletphysics.linearmath.Transform; 
 | 
import com.bulletphysics.linearmath.VectorUtil; 
 | 
import com.bulletphysics.util.ObjectArrayList; 
 | 
import cz.advel.stack.Stack; 
 | 
import javax.vecmath.Matrix3f; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
// JAVA NOTE: CompoundShape from 2.71 
 | 
  
 | 
/** 
 | 
 * CompoundShape allows to store multiple other {@link CollisionShape}s. This allows 
 | 
 * for moving concave collision objects. This is more general than the {@link BvhTriangleMeshShape}. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class CompoundShape extends CollisionShape { 
 | 
  
 | 
    private final ObjectArrayList<CompoundShapeChild> children = new ObjectArrayList<CompoundShapeChild>(); 
 | 
    private final Vector3f localAabbMin = new Vector3f(1e30f, 1e30f, 1e30f); 
 | 
    private final Vector3f localAabbMax = new Vector3f(-1e30f, -1e30f, -1e30f); 
 | 
  
 | 
    private OptimizedBvh aabbTree = null; 
 | 
  
 | 
    private float collisionMargin = 0f; 
 | 
    protected final Vector3f localScaling = new Vector3f(1f, 1f, 1f); 
 | 
  
 | 
    public void addChildShape(Transform localTransform, CollisionShape shape) { 
 | 
        //m_childTransforms.push_back(localTransform); 
 | 
        //m_childShapes.push_back(shape); 
 | 
        CompoundShapeChild child = new CompoundShapeChild(); 
 | 
        child.transform.set(localTransform); 
 | 
        child.childShape = shape; 
 | 
        child.childShapeType = shape.getShapeType(); 
 | 
        child.childMargin = shape.getMargin(); 
 | 
  
 | 
        children.add(child); 
 | 
  
 | 
        // extend the local aabbMin/aabbMax 
 | 
        Vector3f _localAabbMin = Stack.alloc(Vector3f.class), _localAabbMax = Stack.alloc(Vector3f.class); 
 | 
        shape.getAabb(localTransform, _localAabbMin, _localAabbMax); 
 | 
  
 | 
        // JAVA NOTE: rewritten 
 | 
//        for (int i=0;i<3;i++) 
 | 
//        { 
 | 
//            if (this.localAabbMin[i] > _localAabbMin[i]) 
 | 
//            { 
 | 
//                this.localAabbMin[i] = _localAabbMin[i]; 
 | 
//            } 
 | 
//            if (this.localAabbMax[i] < _localAabbMax[i]) 
 | 
//            { 
 | 
//                this.localAabbMax[i] = _localAabbMax[i]; 
 | 
//            } 
 | 
//        } 
 | 
        VectorUtil.setMin(this.localAabbMin, _localAabbMin); 
 | 
        VectorUtil.setMax(this.localAabbMax, _localAabbMax); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Remove all children shapes that contain the specified shape. 
 | 
     */ 
 | 
    public void removeChildShape(CollisionShape shape) { 
 | 
        boolean done_removing; 
 | 
  
 | 
        // Find the children containing the shape specified, and remove those children. 
 | 
        do { 
 | 
            done_removing = true; 
 | 
  
 | 
            for (int i = 0; i < children.size(); i++) { 
 | 
                if (children.getQuick(i).childShape == shape) { 
 | 
                    children.removeQuick(i); 
 | 
                    done_removing = false;  // Do another iteration pass after removing from the vector 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        while (!done_removing); 
 | 
  
 | 
        recalculateLocalAabb(); 
 | 
    } 
 | 
     
 | 
    public int getNumChildShapes() { 
 | 
        return children.size(); 
 | 
    } 
 | 
  
 | 
    public CollisionShape getChildShape(int index) { 
 | 
        return children.getQuick(index).childShape; 
 | 
    } 
 | 
  
 | 
    public Transform getChildTransform(int index, Transform out) { 
 | 
        out.set(children.getQuick(index).transform); 
 | 
        return out; 
 | 
    } 
 | 
  
 | 
    public ObjectArrayList<CompoundShapeChild> getChildList() { 
 | 
        return children; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version. 
 | 
     */ 
 | 
    @Override 
 | 
    public void getAabb(Transform trans, Vector3f aabbMin, Vector3f aabbMax) { 
 | 
        Vector3f localHalfExtents = Stack.alloc(Vector3f.class); 
 | 
        localHalfExtents.sub(localAabbMax, localAabbMin); 
 | 
        localHalfExtents.scale(0.5f); 
 | 
        localHalfExtents.x += getMargin(); 
 | 
        localHalfExtents.y += getMargin(); 
 | 
        localHalfExtents.z += getMargin(); 
 | 
  
 | 
        Vector3f localCenter = Stack.alloc(Vector3f.class); 
 | 
        localCenter.add(localAabbMax, localAabbMin); 
 | 
        localCenter.scale(0.5f); 
 | 
  
 | 
        Matrix3f abs_b = (Matrix3f) Stack.alloc(trans.basis); 
 | 
        MatrixUtil.absolute(abs_b); 
 | 
  
 | 
        Vector3f center = (Vector3f) Stack.alloc(localCenter); 
 | 
        trans.transform(center); 
 | 
  
 | 
        Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Vector3f extent = Stack.alloc(Vector3f.class); 
 | 
        abs_b.getRow(0, tmp); 
 | 
        extent.x = tmp.dot(localHalfExtents); 
 | 
        abs_b.getRow(1, tmp); 
 | 
        extent.y = tmp.dot(localHalfExtents); 
 | 
        abs_b.getRow(2, tmp); 
 | 
        extent.z = tmp.dot(localHalfExtents); 
 | 
  
 | 
        aabbMin.sub(center, extent); 
 | 
        aabbMax.add(center, extent); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Re-calculate the local Aabb. Is called at the end of removeChildShapes. 
 | 
     * Use this yourself if you modify the children or their transforms. 
 | 
     */ 
 | 
    public void recalculateLocalAabb() { 
 | 
        // Recalculate the local aabb 
 | 
        // Brute force, it iterates over all the shapes left. 
 | 
        localAabbMin.set(1e30f, 1e30f, 1e30f); 
 | 
        localAabbMax.set(-1e30f, -1e30f, -1e30f); 
 | 
  
 | 
        Vector3f tmpLocalAabbMin = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmpLocalAabbMax = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        // extend the local aabbMin/aabbMax 
 | 
        for (int j = 0; j < children.size(); j++) { 
 | 
            children.getQuick(j).childShape.getAabb(children.getQuick(j).transform, tmpLocalAabbMin, tmpLocalAabbMax); 
 | 
             
 | 
            for (int i = 0; i < 3; i++) { 
 | 
                if (VectorUtil.getCoord(localAabbMin, i) > VectorUtil.getCoord(tmpLocalAabbMin, i)) { 
 | 
                    VectorUtil.setCoord(localAabbMin, i, VectorUtil.getCoord(tmpLocalAabbMin, i)); 
 | 
                } 
 | 
                if (VectorUtil.getCoord(localAabbMax, i) < VectorUtil.getCoord(tmpLocalAabbMax, i)) { 
 | 
                    VectorUtil.setCoord(localAabbMax, i, VectorUtil.getCoord(tmpLocalAabbMax, i)); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
     
 | 
    @Override 
 | 
    public void setLocalScaling(Vector3f scaling) { 
 | 
        localScaling.set(scaling); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public Vector3f getLocalScaling(Vector3f out) { 
 | 
        out.set(localScaling); 
 | 
        return out; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void calculateLocalInertia(float mass, Vector3f inertia) { 
 | 
        // approximation: take the inertia from the aabb for now 
 | 
        Transform ident = Stack.alloc(Transform.class); 
 | 
        ident.setIdentity(); 
 | 
        Vector3f aabbMin = Stack.alloc(Vector3f.class), aabbMax = Stack.alloc(Vector3f.class); 
 | 
        getAabb(ident, aabbMin, aabbMax); 
 | 
  
 | 
        Vector3f halfExtents = Stack.alloc(Vector3f.class); 
 | 
        halfExtents.sub(aabbMax, aabbMin); 
 | 
        halfExtents.scale(0.5f); 
 | 
  
 | 
        float lx = 2f * halfExtents.x; 
 | 
        float ly = 2f * halfExtents.y; 
 | 
        float lz = 2f * halfExtents.z; 
 | 
  
 | 
        inertia.x = (mass / 12f) * (ly * ly + lz * lz); 
 | 
        inertia.y = (mass / 12f) * (lx * lx + lz * lz); 
 | 
        inertia.z = (mass / 12f) * (lx * lx + ly * ly); 
 | 
    } 
 | 
     
 | 
    @Override 
 | 
    public BroadphaseNativeType getShapeType() { 
 | 
        return BroadphaseNativeType.COMPOUND_SHAPE_PROXYTYPE; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void setMargin(float margin) { 
 | 
        collisionMargin = margin; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public float getMargin() { 
 | 
        return collisionMargin; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public String getName() { 
 | 
        return "Compound"; 
 | 
    } 
 | 
  
 | 
    // this is optional, but should make collision queries faster, by culling non-overlapping nodes 
 | 
    // void    createAabbTreeFromChildren(); 
 | 
     
 | 
    public OptimizedBvh getAabbTree() { 
 | 
        return aabbTree; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Computes the exact moment of inertia and the transform from the coordinate 
 | 
     * system defined by the principal axes of the moment of inertia and the center 
 | 
     * of mass to the current coordinate system. "masses" points to an array 
 | 
     * of masses of the children. The resulting transform "principal" has to be 
 | 
     * applied inversely to all children transforms in order for the local coordinate 
 | 
     * system of the compound shape to be centered at the center of mass and to coincide 
 | 
     * with the principal axes. This also necessitates a correction of the world transform 
 | 
     * of the collision object by the principal transform. 
 | 
     */ 
 | 
    public void calculatePrincipalAxisTransform(float[] masses, Transform principal, Vector3f inertia) { 
 | 
        int n = children.size(); 
 | 
  
 | 
        float totalMass = 0; 
 | 
        Vector3f center = Stack.alloc(Vector3f.class); 
 | 
        center.set(0, 0, 0); 
 | 
        for (int k = 0; k < n; k++) { 
 | 
            center.scaleAdd(masses[k], children.getQuick(k).transform.origin, center); 
 | 
            totalMass += masses[k]; 
 | 
        } 
 | 
        center.scale(1f / totalMass); 
 | 
        principal.origin.set(center); 
 | 
  
 | 
        Matrix3f tensor = Stack.alloc(Matrix3f.class); 
 | 
        tensor.setZero(); 
 | 
  
 | 
        for (int k = 0; k < n; k++) { 
 | 
            Vector3f i = Stack.alloc(Vector3f.class); 
 | 
            children.getQuick(k).childShape.calculateLocalInertia(masses[k], i); 
 | 
  
 | 
            Transform t = children.getQuick(k).transform; 
 | 
            Vector3f o = Stack.alloc(Vector3f.class); 
 | 
            o.sub(t.origin, center); 
 | 
  
 | 
            // compute inertia tensor in coordinate system of compound shape 
 | 
            Matrix3f j = Stack.alloc(Matrix3f.class); 
 | 
            j.transpose(t.basis); 
 | 
  
 | 
            j.m00 *= i.x; 
 | 
            j.m01 *= i.x; 
 | 
            j.m02 *= i.x; 
 | 
            j.m10 *= i.y; 
 | 
            j.m11 *= i.y; 
 | 
            j.m12 *= i.y; 
 | 
            j.m20 *= i.z; 
 | 
            j.m21 *= i.z; 
 | 
            j.m22 *= i.z; 
 | 
  
 | 
            j.mul(t.basis, j); 
 | 
  
 | 
            // add inertia tensor 
 | 
            tensor.add(j); 
 | 
  
 | 
            // compute inertia tensor of pointmass at o 
 | 
            float o2 = o.lengthSquared(); 
 | 
            j.setRow(0, o2, 0, 0); 
 | 
            j.setRow(1, 0, o2, 0); 
 | 
            j.setRow(2, 0, 0, o2); 
 | 
            j.m00 += o.x * -o.x; 
 | 
            j.m01 += o.y * -o.x; 
 | 
            j.m02 += o.z * -o.x; 
 | 
            j.m10 += o.x * -o.y; 
 | 
            j.m11 += o.y * -o.y; 
 | 
            j.m12 += o.z * -o.y; 
 | 
            j.m20 += o.x * -o.z; 
 | 
            j.m21 += o.y * -o.z; 
 | 
            j.m22 += o.z * -o.z; 
 | 
  
 | 
            // add inertia tensor of pointmass 
 | 
            tensor.m00 += masses[k] * j.m00; 
 | 
            tensor.m01 += masses[k] * j.m01; 
 | 
            tensor.m02 += masses[k] * j.m02; 
 | 
            tensor.m10 += masses[k] * j.m10; 
 | 
            tensor.m11 += masses[k] * j.m11; 
 | 
            tensor.m12 += masses[k] * j.m12; 
 | 
            tensor.m20 += masses[k] * j.m20; 
 | 
            tensor.m21 += masses[k] * j.m21; 
 | 
            tensor.m22 += masses[k] * j.m22; 
 | 
        } 
 | 
  
 | 
        MatrixUtil.diagonalize(tensor, principal.basis, 0.00001f, 20); 
 | 
  
 | 
        inertia.set(tensor.m00, tensor.m11, tensor.m22); 
 | 
    } 
 | 
  
 | 
} 
 |