/* 
 | 
 * 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.BulletGlobals; 
 | 
import com.bulletphysics.collision.broadphase.BroadphaseNativeType; 
 | 
import com.bulletphysics.linearmath.MatrixUtil; 
 | 
import com.bulletphysics.linearmath.Transform; 
 | 
import com.bulletphysics.linearmath.VectorUtil; 
 | 
import cz.advel.stack.Stack; 
 | 
import javax.vecmath.Matrix3f; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
/** 
 | 
 * CapsuleShape represents a capsule around the Y axis, there is also the 
 | 
 * {@link CapsuleShapeX} aligned around the X axis and {@link CapsuleShapeZ} around 
 | 
 * the Z axis.<p> 
 | 
 * 
 | 
 * The total height is height+2*radius, so the height is just the height between 
 | 
 * the center of each "sphere" of the capsule caps.<p> 
 | 
 * 
 | 
 * CapsuleShape is a convex hull of two spheres. The {@link MultiSphereShape} is 
 | 
 * a more general collision shape that takes the convex hull of multiple sphere, 
 | 
 * so it can also represent a capsule when just using two spheres. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class CapsuleShape extends ConvexInternalShape 
 | 
{ 
 | 
    static final long serialVersionUID = -4332693269206844011L; 
 | 
    protected int upAxis; 
 | 
    protected boolean anchor; 
 | 
  
 | 
    // only used for CapsuleShapeZ and CapsuleShapeX subclasses. 
 | 
    CapsuleShape() 
 | 
        { 
 | 
    } 
 | 
     
 | 
    public CapsuleShape(float radius, float height) 
 | 
        { 
 | 
            this(radius,height,true); 
 | 
    } 
 | 
  
 | 
    public CapsuleShape(float radius, float height, boolean anchor) 
 | 
        { 
 | 
        upAxis = 1; 
 | 
        implicitShapeDimensions.set(radius, 0.5f * height, radius); 
 | 
                this.anchor = anchor; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public Vector3f localGetSupportingVertexWithoutMargin(Vector3f vec0, Vector3f out) 
 | 
        { 
 | 
            return localGetSupportingVertexWithNorm(vec0,out,null,null); 
 | 
        } 
 | 
         
 | 
    public Vector3f localGetSupportingVertexWithNorm(Vector3f vec0, Vector3f out, Vector3f normvec0, Vector3f normout) 
 | 
        { 
 | 
        Vector3f supVec = out; 
 | 
        supVec.set(0f, 0f, 0f); 
 | 
  
 | 
//        float maxDot = -1e30f; 
 | 
  
 | 
        Vector3f vec = (Vector3f) Stack.alloc(vec0); 
 | 
        Vector3f norm = (Vector3f) Stack.alloc(normvec0); 
 | 
        //Vector3f vec = (Vector3f) Stack.alloc(vec0); 
 | 
        double lenSqr = vec.lengthSquared(); 
 | 
//        if (lenSqr < 0.0001f) { 
 | 
//            vec.set(1f, 0f, 0f); 
 | 
//        } 
 | 
//        else { 
 | 
            double rlen = 1 / Math.sqrt(lenSqr); 
 | 
            vec.scale((float)rlen); 
 | 
//        } 
 | 
  
 | 
//        Vector3f vtx = Stack.alloc(Vector3f.class); 
 | 
//        float newDot; 
 | 
  
 | 
        float radius = getRadius(); 
 | 
  
 | 
        Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f pos = Stack.alloc(Vector3f.class); 
 | 
  
 | 
                pos.set(0f, 0f, 0f); 
 | 
                VectorUtil.setCoord(pos, getUpAxis(), getHalfHeight()); 
 | 
  
 | 
                float factor = 1; 
 | 
                 
 | 
                if (pos.x == 0) 
 | 
                    factor = radius/2; 
 | 
                else 
 | 
                    factor = pos.x; 
 | 
                 
 | 
                vec.x *= factor; 
 | 
                if (norm != null) 
 | 
                    norm.x /= factor; 
 | 
                 
 | 
                if (pos.y == 0) 
 | 
                    factor = radius/2; 
 | 
                else 
 | 
                    factor = pos.y; 
 | 
                 
 | 
                vec.y *= factor; 
 | 
                if (norm != null) 
 | 
                    norm.y /= factor; 
 | 
                 
 | 
                if (pos.z == 0) 
 | 
                    factor = radius/2; 
 | 
                else 
 | 
                    factor = pos.z; 
 | 
                 
 | 
                vec.z *= factor; 
 | 
                if (norm != null) 
 | 
                    norm.z /= factor; 
 | 
                 
 | 
            tmp2.scale(getMargin(), vec); 
 | 
                 
 | 
                out.set(vec); 
 | 
                out.sub(tmp2); 
 | 
                 
 | 
                if (normout != null) 
 | 
                { 
 | 
                    normout.set(norm); 
 | 
                    normout.normalize(); 
 | 
                } 
 | 
//            VectorUtil.mul(tmp1, vec, localScaling); 
 | 
//            tmp1.scale(radius); 
 | 
//            tmp2.scale(getMargin(), vec); 
 | 
//            vtx.add(pos, tmp1); 
 | 
//            vtx.sub(tmp2); 
 | 
//            newDot = vec.dot(vtx); 
 | 
//            if (newDot > maxDot) { 
 | 
//                maxDot = newDot; 
 | 
//                supVec.set(vtx); 
 | 
//            } 
 | 
  
 | 
//            pos.set(0f, 0f, 0f); 
 | 
//            VectorUtil.setCoord(pos, getUpAxis(), -getHalfHeight()); 
 | 
//             
 | 
//            VectorUtil.mul(tmp1, vec, localScaling); 
 | 
//            tmp1.scale(radius); 
 | 
//            tmp2.scale(getMargin(), vec); 
 | 
//            vtx.add(pos, tmp1); 
 | 
//            vtx.sub(tmp2); 
 | 
//            newDot = vec.dot(vtx); 
 | 
//            if (newDot > maxDot) { 
 | 
//                maxDot = newDot; 
 | 
//                supVec.set(vtx); 
 | 
//            } 
 | 
  
 | 
        return out; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void batchedUnitVectorGetSupportingVertexWithoutMargin(Vector3f[] vectors, Vector3f[] supportVerticesOut, int numVectors) { 
 | 
        // TODO: implement 
 | 
        throw new UnsupportedOperationException("Not supported yet."); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void calculateLocalInertia(float mass, Vector3f inertia) { 
 | 
        // as an approximation, take the inertia of the box that bounds the spheres 
 | 
  
 | 
        Transform ident = Stack.alloc(Transform.class); 
 | 
        ident.setIdentity(); 
 | 
  
 | 
        float radius = getRadius(); 
 | 
  
 | 
        Vector3f halfExtents = Stack.alloc(Vector3f.class); 
 | 
        halfExtents.set(radius, radius, radius); 
 | 
        VectorUtil.setCoord(halfExtents, getUpAxis(), radius + getHalfHeight()); 
 | 
  
 | 
        float margin = BulletGlobals.CONVEX_DISTANCE_MARGIN; 
 | 
  
 | 
        float lx = 2f * (halfExtents.x + margin); 
 | 
        float ly = 2f * (halfExtents.y + margin); 
 | 
        float lz = 2f * (halfExtents.z + margin); 
 | 
        float x2 = lx * lx; 
 | 
        float y2 = ly * ly; 
 | 
        float z2 = lz * lz; 
 | 
        float scaledmass = mass * 0.08333333f; 
 | 
  
 | 
        inertia.x = scaledmass * (y2 + z2); 
 | 
        inertia.y = scaledmass * (x2 + z2); 
 | 
        inertia.z = scaledmass * (x2 + y2); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public BroadphaseNativeType getShapeType() { 
 | 
        return BroadphaseNativeType.CAPSULE_SHAPE_PROXYTYPE; 
 | 
    } 
 | 
     
 | 
    @Override 
 | 
    public void getAabb(Transform t, Vector3f aabbMin, Vector3f aabbMax) { 
 | 
        Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Vector3f halfExtents = Stack.alloc(Vector3f.class); 
 | 
        halfExtents.set(getRadius(), getRadius(), getRadius()); 
 | 
        VectorUtil.setCoord(halfExtents, upAxis, getRadius() + getHalfHeight()); 
 | 
  
 | 
        halfExtents.x += getMargin(); 
 | 
        halfExtents.y += getMargin(); 
 | 
        halfExtents.z += getMargin(); 
 | 
  
 | 
        Matrix3f abs_b = Stack.alloc(Matrix3f.class); 
 | 
        abs_b.set(t.basis); 
 | 
        MatrixUtil.absolute(abs_b); 
 | 
  
 | 
        Vector3f center = t.origin; 
 | 
        Vector3f extent = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        abs_b.getRow(0, tmp); 
 | 
        extent.x = tmp.dot(halfExtents); 
 | 
        abs_b.getRow(1, tmp); 
 | 
        extent.y = tmp.dot(halfExtents); 
 | 
        abs_b.getRow(2, tmp); 
 | 
        extent.z = tmp.dot(halfExtents); 
 | 
  
 | 
        aabbMin.sub(center, extent); 
 | 
        aabbMax.add(center, extent); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public String getName() { 
 | 
        return "CapsuleShape"; 
 | 
    } 
 | 
     
 | 
    public int getUpAxis() { 
 | 
        return upAxis; 
 | 
    } 
 | 
     
 | 
    public float getRadius() { 
 | 
        int radiusAxis = (upAxis + 2) % 3; 
 | 
        return VectorUtil.getCoord(implicitShapeDimensions, radiusAxis); 
 | 
    } 
 | 
  
 | 
    public float getHalfHeight() { 
 | 
        return VectorUtil.getCoord(implicitShapeDimensions, upAxis); 
 | 
    } 
 | 
  
 | 
} 
 |