/* 
 | 
 * 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.narrowphase; 
 | 
  
 | 
import com.bulletphysics.util.ObjectPool; 
 | 
import com.bulletphysics.linearmath.VectorUtil; 
 | 
import cz.advel.stack.Stack; 
 | 
import cz.advel.stack.StaticAlloc; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
/** 
 | 
 * VoronoiSimplexSolver is an implementation of the closest point distance algorithm 
 | 
 * from a 1-4 points simplex to the origin. Can be used with GJK, as an alternative 
 | 
 * to Johnson distance algorithm. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class VoronoiSimplexSolver extends SimplexSolverInterface { 
 | 
  
 | 
    //protected final BulletStack stack = BulletStack.get(); 
 | 
    protected final ObjectPool<SubSimplexClosestResult> subsimplexResultsPool = ObjectPool.get(SubSimplexClosestResult.class); 
 | 
     
 | 
    private static final int VORONOI_SIMPLEX_MAX_VERTS = 5; 
 | 
     
 | 
    private static final int VERTA = 0; 
 | 
    private static final int VERTB = 1; 
 | 
    private static final int VERTC = 2; 
 | 
    private static final int VERTD = 3; 
 | 
  
 | 
    public int numVertices; 
 | 
  
 | 
    public final Vector3f[] simplexVectorW = new Vector3f[VORONOI_SIMPLEX_MAX_VERTS]; 
 | 
    public final Vector3f[] simplexPointsP = new Vector3f[VORONOI_SIMPLEX_MAX_VERTS]; 
 | 
    public final Vector3f[] simplexPointsQ = new Vector3f[VORONOI_SIMPLEX_MAX_VERTS]; 
 | 
  
 | 
    public final Vector3f cachedP1 = new Vector3f(); 
 | 
    public final Vector3f cachedP2 = new Vector3f(); 
 | 
    public final Vector3f cachedV = new Vector3f(); 
 | 
    public final Vector3f lastW = new Vector3f(); 
 | 
    public boolean cachedValidClosest; 
 | 
  
 | 
    public final SubSimplexClosestResult cachedBC = new SubSimplexClosestResult(); 
 | 
  
 | 
    public boolean needsUpdate; 
 | 
     
 | 
    { 
 | 
        for (int i=0; i<VORONOI_SIMPLEX_MAX_VERTS; i++) { 
 | 
            simplexVectorW[i] = new Vector3f(); 
 | 
            simplexPointsP[i] = new Vector3f(); 
 | 
            simplexPointsQ[i] = new Vector3f(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public void removeVertex(int index) { 
 | 
        assert(numVertices>0); 
 | 
        numVertices--; 
 | 
        simplexVectorW[index].set(simplexVectorW[numVertices]); 
 | 
        simplexPointsP[index].set(simplexPointsP[numVertices]); 
 | 
        simplexPointsQ[index].set(simplexPointsQ[numVertices]); 
 | 
    } 
 | 
     
 | 
    public void    reduceVertices(UsageBitfield usedVerts) { 
 | 
        if ((numVertices() >= 4) && (!usedVerts.usedVertexD)) 
 | 
            removeVertex(3); 
 | 
  
 | 
        if ((numVertices() >= 3) && (!usedVerts.usedVertexC)) 
 | 
            removeVertex(2); 
 | 
  
 | 
        if ((numVertices() >= 2) && (!usedVerts.usedVertexB)) 
 | 
            removeVertex(1); 
 | 
  
 | 
        if ((numVertices() >= 1) && (!usedVerts.usedVertexA)) 
 | 
            removeVertex(0); 
 | 
    } 
 | 
     
 | 
    @StaticAlloc 
 | 
    public boolean updateClosestVectorAndPoints() { 
 | 
        if (needsUpdate) 
 | 
        { 
 | 
            cachedBC.reset(); 
 | 
  
 | 
            needsUpdate = false; 
 | 
  
 | 
            switch (numVertices()) 
 | 
            { 
 | 
            case 0: 
 | 
                    cachedValidClosest = false; 
 | 
                    break; 
 | 
            case 1: 
 | 
                { 
 | 
                    cachedP1.set(simplexPointsP[0]); 
 | 
                    cachedP2.set(simplexPointsQ[0]); 
 | 
                    cachedV.sub(cachedP1, cachedP2); //== m_simplexVectorW[0] 
 | 
                    cachedBC.reset(); 
 | 
                    cachedBC.setBarycentricCoordinates(1f, 0f, 0f, 0f); 
 | 
                    cachedValidClosest = cachedBC.isValid(); 
 | 
                    break; 
 | 
                } 
 | 
            case 2: 
 | 
                { 
 | 
                    Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
                     
 | 
                    //closest point origin from line segment 
 | 
                    Vector3f from = simplexVectorW[0]; 
 | 
                    Vector3f to = simplexVectorW[1]; 
 | 
                    Vector3f nearest = Stack.alloc(Vector3f.class); 
 | 
  
 | 
                    Vector3f p = Stack.alloc(Vector3f.class); 
 | 
                    p.set(0f, 0f, 0f); 
 | 
                    Vector3f diff = Stack.alloc(Vector3f.class); 
 | 
                    diff.sub(p, from); 
 | 
  
 | 
                    Vector3f v = Stack.alloc(Vector3f.class); 
 | 
                    v.sub(to, from); 
 | 
  
 | 
                    float t = v.dot(diff); 
 | 
  
 | 
                    if (t > 0) { 
 | 
                        float dotVV = v.dot(v); 
 | 
                        if (t < dotVV) { 
 | 
                            t /= dotVV; 
 | 
                            tmp.scale(t, v); 
 | 
                            diff.sub(tmp); 
 | 
                            cachedBC.usedVertices.usedVertexA = true; 
 | 
                            cachedBC.usedVertices.usedVertexB = true; 
 | 
                        } else { 
 | 
                            t = 1; 
 | 
                            diff.sub(v); 
 | 
                            // reduce to 1 point 
 | 
                            cachedBC.usedVertices.usedVertexB = true; 
 | 
                        } 
 | 
                    } else 
 | 
                    { 
 | 
                        t = 0; 
 | 
                        //reduce to 1 point 
 | 
                        cachedBC.usedVertices.usedVertexA = true; 
 | 
                    } 
 | 
                    cachedBC.setBarycentricCoordinates(1f-t, t, 0f, 0f); 
 | 
                     
 | 
                    tmp.scale(t, v); 
 | 
                    nearest.add(from, tmp); 
 | 
  
 | 
                    tmp.sub(simplexPointsP[1], simplexPointsP[0]); 
 | 
                    tmp.scale(t); 
 | 
                    cachedP1.add(simplexPointsP[0], tmp); 
 | 
  
 | 
                    tmp.sub(simplexPointsQ[1], simplexPointsQ[0]); 
 | 
                    tmp.scale(t); 
 | 
                    cachedP2.add(simplexPointsQ[0], tmp); 
 | 
  
 | 
                    cachedV.sub(cachedP1, cachedP2); 
 | 
  
 | 
                    reduceVertices(cachedBC.usedVertices); 
 | 
  
 | 
                    cachedValidClosest = cachedBC.isValid(); 
 | 
                    break; 
 | 
                } 
 | 
            case 3:  
 | 
                {  
 | 
                    Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
                    Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
                    Vector3f tmp3 = Stack.alloc(Vector3f.class); 
 | 
                     
 | 
                    // closest point origin from triangle  
 | 
                    Vector3f p = Stack.alloc(Vector3f.class); 
 | 
                    p.set(0f, 0f, 0f); 
 | 
  
 | 
                    Vector3f a = simplexVectorW[0];  
 | 
                    Vector3f b = simplexVectorW[1];  
 | 
                    Vector3f c = simplexVectorW[2];  
 | 
  
 | 
                    closestPtPointTriangle(p,a,b,c,cachedBC); 
 | 
  
 | 
                    tmp1.scale(cachedBC.barycentricCoords[0], simplexPointsP[0]); 
 | 
                    tmp2.scale(cachedBC.barycentricCoords[1], simplexPointsP[1]); 
 | 
                    tmp3.scale(cachedBC.barycentricCoords[2], simplexPointsP[2]); 
 | 
                    VectorUtil.add(cachedP1, tmp1, tmp2, tmp3); 
 | 
  
 | 
                    tmp1.scale(cachedBC.barycentricCoords[0], simplexPointsQ[0]); 
 | 
                    tmp2.scale(cachedBC.barycentricCoords[1], simplexPointsQ[1]); 
 | 
                    tmp3.scale(cachedBC.barycentricCoords[2], simplexPointsQ[2]); 
 | 
                    VectorUtil.add(cachedP2, tmp1, tmp2, tmp3); 
 | 
  
 | 
                    cachedV.sub(cachedP1, cachedP2); 
 | 
  
 | 
                    reduceVertices(cachedBC.usedVertices); 
 | 
                    cachedValidClosest = cachedBC.isValid();  
 | 
  
 | 
                    break;  
 | 
                } 
 | 
            case 4: 
 | 
                { 
 | 
                    Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
                    Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
                    Vector3f tmp3 = Stack.alloc(Vector3f.class); 
 | 
                    Vector3f tmp4 = Stack.alloc(Vector3f.class); 
 | 
                     
 | 
                    Vector3f p = Stack.alloc(Vector3f.class); 
 | 
                    p.set(0f, 0f, 0f); 
 | 
  
 | 
                    Vector3f a = simplexVectorW[0]; 
 | 
                    Vector3f b = simplexVectorW[1]; 
 | 
                    Vector3f c = simplexVectorW[2]; 
 | 
                    Vector3f d = simplexVectorW[3]; 
 | 
  
 | 
                    boolean hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,cachedBC); 
 | 
  
 | 
                    if (hasSeperation) 
 | 
                    { 
 | 
                        tmp1.scale(cachedBC.barycentricCoords[0], simplexPointsP[0]); 
 | 
                        tmp2.scale(cachedBC.barycentricCoords[1], simplexPointsP[1]); 
 | 
                        tmp3.scale(cachedBC.barycentricCoords[2], simplexPointsP[2]); 
 | 
                        tmp4.scale(cachedBC.barycentricCoords[3], simplexPointsP[3]); 
 | 
                        VectorUtil.add(cachedP1, tmp1, tmp2, tmp3, tmp4); 
 | 
  
 | 
                        tmp1.scale(cachedBC.barycentricCoords[0], simplexPointsQ[0]); 
 | 
                        tmp2.scale(cachedBC.barycentricCoords[1], simplexPointsQ[1]); 
 | 
                        tmp3.scale(cachedBC.barycentricCoords[2], simplexPointsQ[2]); 
 | 
                        tmp4.scale(cachedBC.barycentricCoords[3], simplexPointsQ[3]); 
 | 
                        VectorUtil.add(cachedP2, tmp1, tmp2, tmp3, tmp4); 
 | 
  
 | 
                        cachedV.sub(cachedP1, cachedP2); 
 | 
                        reduceVertices (cachedBC.usedVertices); 
 | 
                    } else 
 | 
                    { 
 | 
    //                    printf("sub distance got penetration\n"); 
 | 
  
 | 
                        if (cachedBC.degenerate) 
 | 
                        { 
 | 
                            cachedValidClosest = false; 
 | 
                        } else 
 | 
                        { 
 | 
                            cachedValidClosest = true; 
 | 
                            //degenerate case == false, penetration = true + zero 
 | 
                            cachedV.set(0f, 0f, 0f); 
 | 
                        } 
 | 
                        break; 
 | 
                    } 
 | 
  
 | 
                    cachedValidClosest = cachedBC.isValid(); 
 | 
  
 | 
                    //closest point origin from tetrahedron 
 | 
                    break; 
 | 
                } 
 | 
            default: 
 | 
                { 
 | 
                    cachedValidClosest = false; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return cachedValidClosest; 
 | 
    } 
 | 
  
 | 
    @StaticAlloc 
 | 
    public boolean closestPtPointTriangle(Vector3f p, Vector3f a, Vector3f b, Vector3f c, SubSimplexClosestResult result) { 
 | 
        result.usedVertices.reset(); 
 | 
  
 | 
        // Check if P in vertex region outside A 
 | 
        Vector3f ab = Stack.alloc(Vector3f.class); 
 | 
        ab.sub(b, a); 
 | 
  
 | 
        Vector3f ac = Stack.alloc(Vector3f.class); 
 | 
        ac.sub(c, a); 
 | 
  
 | 
        Vector3f ap = Stack.alloc(Vector3f.class); 
 | 
        ap.sub(p, a); 
 | 
  
 | 
        float d1 = ab.dot(ap); 
 | 
        float d2 = ac.dot(ap); 
 | 
  
 | 
        if (d1 <= 0f && d2 <= 0f)  
 | 
        { 
 | 
            result.closestPointOnSimplex.set(a); 
 | 
            result.usedVertices.usedVertexA = true; 
 | 
            result.setBarycentricCoordinates(1f, 0f, 0f, 0f); 
 | 
            return true; // a; // barycentric coordinates (1,0,0) 
 | 
        } 
 | 
  
 | 
        // Check if P in vertex region outside B 
 | 
        Vector3f bp = Stack.alloc(Vector3f.class); 
 | 
        bp.sub(p, b); 
 | 
  
 | 
        float d3 = ab.dot(bp); 
 | 
        float d4 = ac.dot(bp); 
 | 
  
 | 
        if (d3 >= 0f && d4 <= d3)  
 | 
        { 
 | 
            result.closestPointOnSimplex.set(b); 
 | 
            result.usedVertices.usedVertexB = true; 
 | 
            result.setBarycentricCoordinates(0, 1f, 0f, 0f); 
 | 
  
 | 
            return true; // b; // barycentric coordinates (0,1,0) 
 | 
        } 
 | 
  
 | 
        // Check if P in edge region of AB, if so return projection of P onto AB 
 | 
        float vc = d1*d4 - d3*d2; 
 | 
        if (vc <= 0f && d1 >= 0f && d3 <= 0f) { 
 | 
            float v = d1 / (d1 - d3); 
 | 
            result.closestPointOnSimplex.scaleAdd(v, ab, a); 
 | 
            result.usedVertices.usedVertexA = true; 
 | 
            result.usedVertices.usedVertexB = true; 
 | 
            result.setBarycentricCoordinates(1f-v, v, 0f, 0f); 
 | 
            return true; 
 | 
            //return a + v * ab; // barycentric coordinates (1-v,v,0) 
 | 
        } 
 | 
  
 | 
        // Check if P in vertex region outside C 
 | 
        Vector3f cp = Stack.alloc(Vector3f.class); 
 | 
        cp.sub(p, c); 
 | 
  
 | 
        float d5 = ab.dot(cp); 
 | 
        float d6 = ac.dot(cp); 
 | 
  
 | 
        if (d6 >= 0f && d5 <= d6)  
 | 
        { 
 | 
            result.closestPointOnSimplex.set(c); 
 | 
            result.usedVertices.usedVertexC = true; 
 | 
            result.setBarycentricCoordinates(0f, 0f, 1f, 0f); 
 | 
            return true;//c; // barycentric coordinates (0,0,1) 
 | 
        } 
 | 
  
 | 
        // Check if P in edge region of AC, if so return projection of P onto AC 
 | 
        float vb = d5*d2 - d1*d6; 
 | 
        if (vb <= 0f && d2 >= 0f && d6 <= 0f) { 
 | 
            float w = d2 / (d2 - d6); 
 | 
            result.closestPointOnSimplex.scaleAdd(w, ac, a); 
 | 
            result.usedVertices.usedVertexA = true; 
 | 
            result.usedVertices.usedVertexC = true; 
 | 
            result.setBarycentricCoordinates(1f-w, 0f, w, 0f); 
 | 
            return true; 
 | 
            //return a + w * ac; // barycentric coordinates (1-w,0,w) 
 | 
        } 
 | 
  
 | 
        // Check if P in edge region of BC, if so return projection of P onto BC 
 | 
        float va = d3*d6 - d5*d4; 
 | 
        if (va <= 0f && (d4 - d3) >= 0f && (d5 - d6) >= 0f) { 
 | 
            float w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); 
 | 
  
 | 
            Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
            tmp.sub(c, b); 
 | 
            result.closestPointOnSimplex.scaleAdd(w, tmp, b); 
 | 
  
 | 
            result.usedVertices.usedVertexB = true; 
 | 
            result.usedVertices.usedVertexC = true; 
 | 
            result.setBarycentricCoordinates(0, 1f-w, w, 0f); 
 | 
            return true;         
 | 
           // return b + w * (c - b); // barycentric coordinates (0,1-w,w) 
 | 
        } 
 | 
  
 | 
        // P inside face region. Compute Q through its barycentric coordinates (u,v,w) 
 | 
        float denom = 1f / (va + vb + vc); 
 | 
        float v = vb * denom; 
 | 
        float w = vc * denom; 
 | 
  
 | 
        Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        tmp1.scale(v, ab); 
 | 
        tmp2.scale(w, ac); 
 | 
        VectorUtil.add(result.closestPointOnSimplex, a, tmp1, tmp2); 
 | 
        result.usedVertices.usedVertexA = true; 
 | 
        result.usedVertices.usedVertexB = true; 
 | 
        result.usedVertices.usedVertexC = true; 
 | 
        result.setBarycentricCoordinates(1f-v-w, v, w, 0f); 
 | 
  
 | 
        return true; 
 | 
        //    return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w 
 | 
    } 
 | 
     
 | 
    /// Test if point p and d lie on opposite sides of plane through abc 
 | 
    @StaticAlloc 
 | 
    public static int pointOutsideOfPlane(Vector3f p, Vector3f a, Vector3f b, Vector3f c, Vector3f d) 
 | 
    { 
 | 
        Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Vector3f normal = Stack.alloc(Vector3f.class); 
 | 
        normal.sub(b, a); 
 | 
        tmp.sub(c, a); 
 | 
        normal.cross(normal, tmp); 
 | 
  
 | 
        tmp.sub(p, a); 
 | 
        float signp = tmp.dot(normal); // [AP AB AC] 
 | 
  
 | 
        tmp.sub(d, a); 
 | 
        float signd = tmp.dot(normal); // [AD AB AC] 
 | 
  
 | 
    //#ifdef CATCH_DEGENERATE_TETRAHEDRON 
 | 
//    #ifdef BT_USE_DOUBLE_PRECISION 
 | 
//    if (signd * signd < (btScalar(1e-8) * btScalar(1e-8))) 
 | 
//        { 
 | 
//            return -1; 
 | 
//        } 
 | 
//    #else 
 | 
        if (signd * signd < ((1e-4f) * (1e-4f))) 
 | 
        { 
 | 
    //        printf("affine dependent/degenerate\n");// 
 | 
            return -1; 
 | 
        } 
 | 
    //#endif 
 | 
  
 | 
    //#endif 
 | 
        // Points on opposite sides if expression signs are opposite 
 | 
        return (signp * signd < 0f)? 1 : 0; 
 | 
    } 
 | 
     
 | 
    @StaticAlloc 
 | 
    public boolean closestPtPointTetrahedron(Vector3f p, Vector3f a, Vector3f b, Vector3f c, Vector3f d, SubSimplexClosestResult finalResult) { 
 | 
        SubSimplexClosestResult tempResult = subsimplexResultsPool.get(); 
 | 
        tempResult.reset(); 
 | 
        try { 
 | 
            Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
            Vector3f q = Stack.alloc(Vector3f.class); 
 | 
  
 | 
            // Start out assuming point inside all halfspaces, so closest to itself 
 | 
            finalResult.closestPointOnSimplex.set(p); 
 | 
            finalResult.usedVertices.reset(); 
 | 
            finalResult.usedVertices.usedVertexA = true; 
 | 
            finalResult.usedVertices.usedVertexB = true; 
 | 
            finalResult.usedVertices.usedVertexC = true; 
 | 
            finalResult.usedVertices.usedVertexD = true; 
 | 
  
 | 
            int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d); 
 | 
            int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b); 
 | 
            int    pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c); 
 | 
            int    pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a); 
 | 
  
 | 
           if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) 
 | 
           { 
 | 
               finalResult.degenerate = true; 
 | 
               return false; 
 | 
           } 
 | 
  
 | 
           if (pointOutsideABC == 0 && pointOutsideACD == 0 && pointOutsideADB == 0 && pointOutsideBDC == 0) 
 | 
             { 
 | 
                 return false; 
 | 
             } 
 | 
  
 | 
  
 | 
            float bestSqDist = Float.MAX_VALUE; 
 | 
            // If point outside face abc then compute closest point on abc 
 | 
            if (pointOutsideABC != 0)  
 | 
            { 
 | 
                closestPtPointTriangle(p, a, b, c,tempResult); 
 | 
                q.set(tempResult.closestPointOnSimplex); 
 | 
  
 | 
                tmp.sub(q, p); 
 | 
                float sqDist = tmp.dot(tmp); 
 | 
                // Update best closest point if (squared) distance is less than current best 
 | 
                if (sqDist < bestSqDist) { 
 | 
                    bestSqDist = sqDist; 
 | 
                    finalResult.closestPointOnSimplex.set(q); 
 | 
                    //convert result bitmask! 
 | 
                    finalResult.usedVertices.reset(); 
 | 
                    finalResult.usedVertices.usedVertexA = tempResult.usedVertices.usedVertexA; 
 | 
                    finalResult.usedVertices.usedVertexB = tempResult.usedVertices.usedVertexB; 
 | 
                    finalResult.usedVertices.usedVertexC = tempResult.usedVertices.usedVertexC; 
 | 
                    finalResult.setBarycentricCoordinates( 
 | 
                            tempResult.barycentricCoords[VERTA], 
 | 
                            tempResult.barycentricCoords[VERTB], 
 | 
                            tempResult.barycentricCoords[VERTC], 
 | 
                            0 
 | 
                    ); 
 | 
  
 | 
                } 
 | 
            } 
 | 
  
 | 
  
 | 
            // Repeat test for face acd 
 | 
            if (pointOutsideACD != 0)  
 | 
            { 
 | 
                closestPtPointTriangle(p, a, c, d,tempResult); 
 | 
                q.set(tempResult.closestPointOnSimplex); 
 | 
                //convert result bitmask! 
 | 
  
 | 
                tmp.sub(q, p); 
 | 
                float sqDist = tmp.dot(tmp); 
 | 
                if (sqDist < bestSqDist)  
 | 
                { 
 | 
                    bestSqDist = sqDist; 
 | 
                    finalResult.closestPointOnSimplex.set(q); 
 | 
                    finalResult.usedVertices.reset(); 
 | 
                    finalResult.usedVertices.usedVertexA = tempResult.usedVertices.usedVertexA; 
 | 
  
 | 
                    finalResult.usedVertices.usedVertexC = tempResult.usedVertices.usedVertexB; 
 | 
                    finalResult.usedVertices.usedVertexD = tempResult.usedVertices.usedVertexC; 
 | 
                    finalResult.setBarycentricCoordinates( 
 | 
                            tempResult.barycentricCoords[VERTA], 
 | 
                            0, 
 | 
                            tempResult.barycentricCoords[VERTB], 
 | 
                            tempResult.barycentricCoords[VERTC] 
 | 
                    ); 
 | 
  
 | 
                } 
 | 
            } 
 | 
            // Repeat test for face adb 
 | 
  
 | 
  
 | 
            if (pointOutsideADB != 0) 
 | 
            { 
 | 
                closestPtPointTriangle(p, a, d, b,tempResult); 
 | 
                q.set(tempResult.closestPointOnSimplex); 
 | 
                //convert result bitmask! 
 | 
  
 | 
                tmp.sub(q, p); 
 | 
                float sqDist = tmp.dot(tmp); 
 | 
                if (sqDist < bestSqDist)  
 | 
                { 
 | 
                    bestSqDist = sqDist; 
 | 
                    finalResult.closestPointOnSimplex.set(q); 
 | 
                    finalResult.usedVertices.reset(); 
 | 
                    finalResult.usedVertices.usedVertexA = tempResult.usedVertices.usedVertexA; 
 | 
                    finalResult.usedVertices.usedVertexB = tempResult.usedVertices.usedVertexC; 
 | 
  
 | 
                    finalResult.usedVertices.usedVertexD = tempResult.usedVertices.usedVertexB; 
 | 
                    finalResult.setBarycentricCoordinates( 
 | 
                            tempResult.barycentricCoords[VERTA], 
 | 
                            tempResult.barycentricCoords[VERTC], 
 | 
                            0, 
 | 
                            tempResult.barycentricCoords[VERTB] 
 | 
                    ); 
 | 
  
 | 
                } 
 | 
            } 
 | 
            // Repeat test for face bdc 
 | 
  
 | 
  
 | 
            if (pointOutsideBDC != 0) 
 | 
            { 
 | 
                closestPtPointTriangle(p, b, d, c,tempResult); 
 | 
                q.set(tempResult.closestPointOnSimplex); 
 | 
                //convert result bitmask! 
 | 
                tmp.sub(q, p); 
 | 
                float sqDist = tmp.dot(tmp); 
 | 
                if (sqDist < bestSqDist)  
 | 
                { 
 | 
                    bestSqDist = sqDist; 
 | 
                    finalResult.closestPointOnSimplex.set(q); 
 | 
                    finalResult.usedVertices.reset(); 
 | 
                    // 
 | 
                    finalResult.usedVertices.usedVertexB = tempResult.usedVertices.usedVertexA; 
 | 
                    finalResult.usedVertices.usedVertexC = tempResult.usedVertices.usedVertexC; 
 | 
                    finalResult.usedVertices.usedVertexD = tempResult.usedVertices.usedVertexB; 
 | 
  
 | 
                    finalResult.setBarycentricCoordinates( 
 | 
                            0, 
 | 
                            tempResult.barycentricCoords[VERTA], 
 | 
                            tempResult.barycentricCoords[VERTC], 
 | 
                            tempResult.barycentricCoords[VERTB] 
 | 
                    ); 
 | 
  
 | 
                } 
 | 
            } 
 | 
  
 | 
            //help! we ended up full ! 
 | 
  
 | 
            if (finalResult.usedVertices.usedVertexA && 
 | 
                finalResult.usedVertices.usedVertexB && 
 | 
                finalResult.usedVertices.usedVertexC && 
 | 
                finalResult.usedVertices.usedVertexD)  
 | 
            { 
 | 
                return true; 
 | 
            } 
 | 
  
 | 
            return true; 
 | 
        } 
 | 
        finally { 
 | 
            subsimplexResultsPool.release(tempResult); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Clear the simplex, remove all the vertices. 
 | 
     */ 
 | 
    public void reset() { 
 | 
        cachedValidClosest = false; 
 | 
        numVertices = 0; 
 | 
        needsUpdate = true; 
 | 
        lastW.set(1e30f, 1e30f, 1e30f); 
 | 
        cachedBC.reset(); 
 | 
    } 
 | 
  
 | 
    public void addVertex(Vector3f w, Vector3f p, Vector3f q) { 
 | 
        lastW.set(w); 
 | 
        needsUpdate = true; 
 | 
  
 | 
        simplexVectorW[numVertices].set(w); 
 | 
        simplexPointsP[numVertices].set(p); 
 | 
        simplexPointsQ[numVertices].set(q); 
 | 
  
 | 
        numVertices++; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Return/calculate the closest vertex. 
 | 
     */ 
 | 
    public boolean closest(Vector3f v) { 
 | 
        boolean succes = updateClosestVectorAndPoints(); 
 | 
        v.set(cachedV); 
 | 
        return succes; 
 | 
    } 
 | 
  
 | 
    public float maxVertex() { 
 | 
        int i, numverts = numVertices(); 
 | 
        float maxV = 0f; 
 | 
        for (i = 0; i < numverts; i++) { 
 | 
            float curLen2 = simplexVectorW[i].lengthSquared(); 
 | 
            if (maxV < curLen2) { 
 | 
                maxV = curLen2; 
 | 
            } 
 | 
        } 
 | 
        return maxV; 
 | 
    } 
 | 
  
 | 
    public boolean fullSimplex() { 
 | 
        return (numVertices == 4); 
 | 
    } 
 | 
  
 | 
    public int getSimplex(Vector3f[] pBuf, Vector3f[] qBuf, Vector3f[] yBuf) { 
 | 
        for (int i = 0; i < numVertices(); i++) { 
 | 
            yBuf[i].set(simplexVectorW[i]); 
 | 
            pBuf[i].set(simplexPointsP[i]); 
 | 
            qBuf[i].set(simplexPointsQ[i]); 
 | 
        } 
 | 
        return numVertices(); 
 | 
    } 
 | 
  
 | 
    public boolean inSimplex(Vector3f w) { 
 | 
        boolean found = false; 
 | 
        int i, numverts = numVertices(); 
 | 
        //btScalar maxV = btScalar(0.); 
 | 
  
 | 
        //w is in the current (reduced) simplex 
 | 
        for (i = 0; i < numverts; i++) { 
 | 
            if (simplexVectorW[i].equals(w)) { 
 | 
                found = true; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        //check in case lastW is already removed 
 | 
        if (w.equals(lastW)) { 
 | 
            return true; 
 | 
        } 
 | 
  
 | 
        return found; 
 | 
    } 
 | 
  
 | 
    public void backup_closest(Vector3f v) { 
 | 
        v.set(cachedV); 
 | 
    } 
 | 
  
 | 
    public boolean emptySimplex() { 
 | 
        return (numVertices() == 0); 
 | 
    } 
 | 
  
 | 
    public void compute_points(Vector3f p1, Vector3f p2) { 
 | 
        updateClosestVectorAndPoints(); 
 | 
        p1.set(cachedP1); 
 | 
        p2.set(cachedP2); 
 | 
    } 
 | 
  
 | 
    public int numVertices() { 
 | 
        return numVertices; 
 | 
    } 
 | 
     
 | 
    //////////////////////////////////////////////////////////////////////////// 
 | 
     
 | 
    public static class UsageBitfield  implements java.io.Serializable { 
 | 
        public boolean usedVertexA; 
 | 
        public boolean usedVertexB; 
 | 
        public boolean usedVertexC; 
 | 
        public boolean usedVertexD; 
 | 
         
 | 
        public void reset() { 
 | 
            usedVertexA = false; 
 | 
            usedVertexB = false; 
 | 
            usedVertexC = false; 
 | 
            usedVertexD = false; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    public static class SubSimplexClosestResult  implements java.io.Serializable { 
 | 
        public final Vector3f closestPointOnSimplex = new Vector3f(); 
 | 
        //MASK for m_usedVertices 
 | 
        //stores the simplex vertex-usage, using the MASK,  
 | 
        // if m_usedVertices & MASK then the related vertex is used 
 | 
        public final UsageBitfield usedVertices = new UsageBitfield(); 
 | 
        public final float[] barycentricCoords = new float[4]; 
 | 
        public boolean degenerate; 
 | 
         
 | 
        public void reset() { 
 | 
            degenerate = false; 
 | 
            setBarycentricCoordinates(0f, 0f, 0f, 0f); 
 | 
            usedVertices.reset(); 
 | 
        } 
 | 
  
 | 
        public boolean isValid() { 
 | 
            boolean valid = (barycentricCoords[0] >= 0f) && 
 | 
                    (barycentricCoords[1] >= 0f) && 
 | 
                    (barycentricCoords[2] >= 0f) && 
 | 
                    (barycentricCoords[3] >= 0f); 
 | 
            return valid; 
 | 
        } 
 | 
  
 | 
        public void setBarycentricCoordinates(float a, float b, float c, float d) { 
 | 
            barycentricCoords[0] = a; 
 | 
            barycentricCoords[1] = b; 
 | 
            barycentricCoords[2] = c; 
 | 
            barycentricCoords[3] = d; 
 | 
        } 
 | 
    } 
 | 
     
 | 
} 
 |