Package com.bulletphysics.collision.narrowphase

Source Code of com.bulletphysics.collision.narrowphase.GjkEpaSolver$EPA

/*
* 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 java.util.Arrays;
import com.bulletphysics.BulletGlobals;
import com.bulletphysics.util.ObjectStackList;
import com.bulletphysics.collision.shapes.ConvexShape;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.QuaternionUtil;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.VectorUtil;
import com.bulletphysics.util.ArrayPool;
import cz.advel.stack.Stack;
import javax.vecmath.Matrix3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;

/*
GJK-EPA collision solver by Nathanael Presson
Nov.2006
*/

/**
* GjkEpaSolver contributed under zlib by Nathanael Presson.
*
* @author jezek2
*/
public class GjkEpaSolver {

  protected final ArrayPool<float[]> floatArrays = ArrayPool.get(float.class);

  protected final ObjectStackList<Mkv> stackMkv = new ObjectStackList<Mkv>(Mkv.class);
  protected final ObjectStackList<He> stackHe = new ObjectStackList<He>(He.class);
  protected final ObjectStackList<Face> stackFace = new ObjectStackList<Face>(Face.class);

  protected void pushStack() {
    stackMkv.push();
    stackHe.push();
    stackFace.push();
  }

  protected void popStack() {
    stackMkv.pop();
    stackHe.pop();
    stackFace.pop();
  }

  public enum ResultsStatus {
    Separated,    /* Shapes doesnt penetrate                        */
    Penetrating,  /* Shapes are penetrating                        */
    GJK_Failed,    /* GJK phase fail, no big issue, shapes are probably just 'touching'  */
    EPA_Failed,    /* EPA phase fail, bigger problem, need to save parameters, and debug  */
  }
 
  public static class Results {
    public ResultsStatus status;
    public final Vector3f[] witnesses/*[2]*/ = new Vector3f[] { new Vector3f(), new Vector3f() };
    public final Vector3f normal = new Vector3f();
    public float depth;
    public int epa_iterations;
    public int gjk_iterations;
  }
 
  ////////////////////////////////////////////////////////////////////////////
 
  private static final float cstInf = BulletGlobals.SIMD_INFINITY;
  private static final float cstPi = BulletGlobals.SIMD_PI;
  private static final float cst2Pi = BulletGlobals.SIMD_2_PI;
  private static final int GJK_maxiterations = 128;
  private static final int GJK_hashsize = 1 << 6;
  private static final int GJK_hashmask = GJK_hashsize - 1;
  private static final float GJK_insimplex_eps = 0.0001f;
  private static final float GJK_sqinsimplex_eps = GJK_insimplex_eps * GJK_insimplex_eps;
  private static final int EPA_maxiterations = 256;
  private static final float EPA_inface_eps = 0.01f;
  private static final float EPA_accuracy = 0.001f;
 
  ////////////////////////////////////////////////////////////////////////////

  public static class Mkv {
    public final Vector3f w = new Vector3f(); // Minkowski vertice
    public final Vector3f r = new Vector3f(); // Ray

    public void set(Mkv m) {
      w.set(m.w);
      r.set(m.r);
    }
  }

  public static class He {
    public final Vector3f v = new Vector3f();
    public He n;
  }
 
  protected class GJK {
    //protected final BulletStack stack = BulletStack.get();
   
    //public btStackAlloc sa;
    //public Block sablock;
    public final He[] table = new He[GJK_hashsize];
    public final Matrix3f[] wrotations/*[2]*/ = new Matrix3f[] { new Matrix3f(), new Matrix3f() };
    public final Vector3f[] positions/*[2]*/ = new Vector3f[] { new Vector3f(), new Vector3f() };
    public final ConvexShape[] shapes = new ConvexShape[2];
    public final Mkv[] simplex = new Mkv[5];
    public final Vector3f ray = new Vector3f();
    public /*unsigned*/ int order;
    public /*unsigned*/ int iterations;
    public float margin;
    public boolean failed;
   
    {
      for (int i=0; i<simplex.length; i++) simplex[i] = new Mkv();
    }

    public GJK() {
    }

    public GJK(/*StackAlloc psa,*/
        Matrix3f wrot0, Vector3f pos0, ConvexShape shape0,
        Matrix3f wrot1, Vector3f pos1, ConvexShape shape1) {
      this(wrot0, pos0, shape0, wrot1, pos1, shape1, 0f);
    }

    public GJK(/*StackAlloc psa,*/
        Matrix3f wrot0, Vector3f pos0, ConvexShape shape0,
        Matrix3f wrot1, Vector3f pos1, ConvexShape shape1,
        float pmargin) {
      init(wrot0, pos0, shape0, wrot1, pos1, shape1, pmargin);
    }
   
    public void init(/*StackAlloc psa,*/
        Matrix3f wrot0, Vector3f pos0, ConvexShape shape0,
        Matrix3f wrot1, Vector3f pos1, ConvexShape shape1,
        float pmargin) {
      pushStack();
      wrotations[0].set(wrot0);
      positions[0].set(pos0);
      shapes[0] = shape0;
      wrotations[1].set(wrot1);
      positions[1].set(pos1);
      shapes[1] = shape1;
      //sa    =psa;
      //sablock  =sa->beginBlock();
      margin = pmargin;
      failed = false;
    }
   
    public void destroy() {
      popStack();
    }
   
    // vdh: very dummy hash
    public /*unsigned*/ int Hash(Vector3f v) {
      int h = (int)(v.x * 15461) ^ (int)(v.y * 83003) ^ (int)(v.z * 15473);
      return (h * 169639) & GJK_hashmask;
    }

    public Vector3f LocalSupport(Vector3f d, /*unsigned*/ int i, Vector3f out) {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      MatrixUtil.transposeTransform(tmp, d, wrotations[i]);

      shapes[i].localGetSupportingVertex(tmp, out);
      wrotations[i].transform(out);
      out.add(positions[i]);

      return out;
    }
   
    public void Support(Vector3f d, Mkv v) {
      v.r.set(d);

      Vector3f tmp1 = LocalSupport(d, 0, Stack.alloc(Vector3f.class));

      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.set(d);
      tmp.negate();
      Vector3f tmp2 = LocalSupport(tmp, 1, Stack.alloc(Vector3f.class));

      v.w.sub(tmp1, tmp2);
      v.w.scaleAdd(margin, d, v.w);
    }

    public boolean FetchSupport() {
      int h = Hash(ray);
      He e = table[h];
      while (e != null) {
        if (e.v.equals(ray)) {
          --order;
          return false;
        }
        else {
          e = e.n;
        }
      }
      //e = (He*)sa->allocate(sizeof(He));
      //e = new He();
      e = stackHe.get();
      e.v.set(ray);
      e.n = table[h];
      table[h] = e;
      Support(ray, simplex[++order]);
      return (ray.dot(simplex[order].w) > 0);
    }

    public boolean SolveSimplex2(Vector3f ao, Vector3f ab) {
      if (ab.dot(ao) >= 0) {
        Vector3f cabo = Stack.alloc(Vector3f.class);
        cabo.cross(ab, ao);
        if (cabo.lengthSquared() > GJK_sqinsimplex_eps) {
          ray.cross(cabo, ab);
        }
        else {
          return true;
        }
      }
      else {
        order = 0;
        simplex[0].set(simplex[1]);
        ray.set(ao);
      }
      return (false);
    }

    public boolean SolveSimplex3(Vector3f ao, Vector3f ab, Vector3f ac)
    {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.cross(ab, ac);
      return (SolveSimplex3a(ao,ab,ac,tmp));
    }
   
    public boolean SolveSimplex3a(Vector3f ao, Vector3f ab, Vector3f ac, Vector3f cabc) {
      // TODO: optimize

      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.cross(cabc, ab);

      Vector3f tmp2 = Stack.alloc(Vector3f.class);
      tmp2.cross(cabc, ac);

      if (tmp.dot(ao) < -GJK_insimplex_eps) {
        order = 1;
        simplex[0].set(simplex[1]);
        simplex[1].set(simplex[2]);
        return SolveSimplex2(ao, ab);
      }
      else if (tmp2.dot(ao) > +GJK_insimplex_eps) {
        order = 1;
        simplex[1].set(simplex[2]);
        return SolveSimplex2(ao, ac);
      }
      else {
        float d = cabc.dot(ao);
        if (Math.abs(d) > GJK_insimplex_eps) {
          if (d > 0) {
            ray.set(cabc);
          }
          else {
            ray.negate(cabc);

            Mkv swapTmp = new Mkv();
            swapTmp.set(simplex[0]);
            simplex[0].set(simplex[1]);
            simplex[1].set(swapTmp);
          }
          return false;
        }
        else {
          return true;
        }
      }
    }
   
    public boolean SolveSimplex4(Vector3f ao, Vector3f ab, Vector3f ac, Vector3f ad) {
      // TODO: optimize

      Vector3f crs = Stack.alloc(Vector3f.class);

      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.cross(ab, ac);

      Vector3f tmp2 = Stack.alloc(Vector3f.class);
      tmp2.cross(ac, ad);

      Vector3f tmp3 = Stack.alloc(Vector3f.class);
      tmp3.cross(ad, ab);

      if (tmp.dot(ao) > GJK_insimplex_eps) {
        crs.set(tmp);
        order = 2;
        simplex[0].set(simplex[1]);
        simplex[1].set(simplex[2]);
        simplex[2].set(simplex[3]);
        return SolveSimplex3a(ao, ab, ac, crs);
      }
      else if (tmp2.dot(ao) > GJK_insimplex_eps) {
        crs.set(tmp2);
        order = 2;
        simplex[2].set(simplex[3]);
        return SolveSimplex3a(ao, ac, ad, crs);
      }
      else if (tmp3.dot(ao) > GJK_insimplex_eps) {
        crs.set(tmp3);
        order = 2;
        simplex[1].set(simplex[0]);
        simplex[0].set(simplex[2]);
        simplex[2].set(simplex[3]);
        return SolveSimplex3a(ao, ad, ab, crs);
      }
      else {
        return (true);
      }
    }
   
    public boolean SearchOrigin() {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.set(1f, 0f, 0f);
      return SearchOrigin(tmp);
    }
   
    public boolean SearchOrigin(Vector3f initray) {
      Vector3f tmp1 = Stack.alloc(Vector3f.class);
      Vector3f tmp2 = Stack.alloc(Vector3f.class);
      Vector3f tmp3 = Stack.alloc(Vector3f.class);
      Vector3f tmp4 = Stack.alloc(Vector3f.class);

      iterations = 0;
      order = -1;
      failed = false;
      ray.set(initray);
      ray.normalize();

      Arrays.fill(table, null);

      FetchSupport();
      ray.negate(simplex[0].w);
      for (; iterations < GJK_maxiterations; ++iterations) {
        float rl = ray.length();
        ray.scale(1f / (rl > 0f ? rl : 1f));
        if (FetchSupport()) {
          boolean found = false;
          switch (order) {
            case 1: {
              tmp1.negate(simplex[1].w);
              tmp2.sub(simplex[0].w, simplex[1].w);
              found = SolveSimplex2(tmp1, tmp2);
              break;
            }
            case 2: {
              tmp1.negate(simplex[2].w);
              tmp2.sub(simplex[1].w, simplex[2].w);
              tmp3.sub(simplex[0].w, simplex[2].w);
              found = SolveSimplex3(tmp1, tmp2, tmp3);
              break;
            }
            case 3: {
              tmp1.negate(simplex[3].w);
              tmp2.sub(simplex[2].w, simplex[3].w);
              tmp3.sub(simplex[1].w, simplex[3].w);
              tmp4.sub(simplex[0].w, simplex[3].w);
              found = SolveSimplex4(tmp1, tmp2, tmp3, tmp4);
              break;
            }
          }
          if (found) {
            return true;
          }
        }
        else {
          return false;
        }
      }
      failed = true;
      return false;
    }
   
    public boolean EncloseOrigin() {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      Vector3f tmp1 = Stack.alloc(Vector3f.class);
      Vector3f tmp2 = Stack.alloc(Vector3f.class);

      switch (order) {
        // Point
        case 0:
          break;
        // Line
        case 1: {
          Vector3f ab = Stack.alloc(Vector3f.class);
          ab.sub(simplex[1].w, simplex[0].w);

          Vector3f[] b = new Vector3f[] { Stack.alloc(Vector3f.class), Stack.alloc(Vector3f.class), Stack.alloc(Vector3f.class) };
          b[0].set(1f, 0f, 0f);
          b[1].set(0f, 1f, 0f);
          b[2].set(0f, 0f, 1f);
         
          b[0].cross(ab, b[0]);
          b[1].cross(ab, b[1]);
          b[2].cross(ab, b[2]);

          float m[] = new float[] { b[0].lengthSquared(), b[1].lengthSquared(), b[2].lengthSquared() };

          Quat4f tmpQuat = Stack.alloc(Quat4f.class);
          tmp.normalize(ab);
          QuaternionUtil.setRotation(tmpQuat, tmp, cst2Pi / 3f);

          Matrix3f r = Stack.alloc(Matrix3f.class);
          MatrixUtil.setRotation(r, tmpQuat);

          Vector3f w = Stack.alloc(Vector3f.class);
          w.set(b[m[0] > m[1] ? m[0] > m[2] ? 0 : 2 : m[1] > m[2] ? 1 : 2]);

          tmp.normalize(w);
          Support(tmp, simplex[4]); r.transform(w);
          tmp.normalize(w);
          Support(tmp, simplex[2]); r.transform(w);
          tmp.normalize(w);
          Support(tmp, simplex[3]); r.transform(w);
          order = 4;
          return (true);
        }
        // Triangle
        case 2: {
          tmp1.sub(simplex[1].w, simplex[0].w);
          tmp2.sub(simplex[2].w, simplex[0].w);
          Vector3f n = Stack.alloc(Vector3f.class);
          n.cross(tmp1, tmp2);
          n.normalize();

          Support(n, simplex[3]);

          tmp.negate(n);
          Support(tmp, simplex[4]);
          order = 4;
          return (true);
        }
        // Tetrahedron
        case 3:
          return (true);
        // Hexahedron
        case 4:
          return (true);
      }
      return (false);
    }
   
  }

  ////////////////////////////////////////////////////////////////////////////

  private static int[] mod3 = new int[] { 0, 1, 2, 0, 1 };

  private static final int[][] tetrahedron_fidx/*[4][3]*/ = new int[][] {{2,1,0},{3,0,1},{3,1,2},{3,2,0}};
  private static final int[][] tetrahedron_eidx/*[6][4]*/ = new int[][] {{0,0,2,1},{0,1,1,1},{0,2,3,1},{1,0,3,2},{2,0,1,2},{3,0,2,2}};

  private static final int[][] hexahedron_fidx/*[6][3]*/ = new int[][] {{2,0,4},{4,1,2},{1,4,0},{0,3,1},{0,2,3},{1,3,2}};
  private static final int[][] hexahedron_eidx/*[9][4]*/ = new int[][] {{0,0,4,0},{0,1,2,1},{0,2,1,2},{1,1,5,2},{1,0,2,0},{2,2,3,2},{3,1,5,0},{3,0,4,2},{5,1,4,1}};

  public static class Face {
    public final Mkv[] v = new Mkv[3];
    public final Face[] f = new Face[3];
    public final int[] e = new int[3];
    public final Vector3f n = new Vector3f();
    public float d;
    public int mark;
    public Face prev;
    public Face next;
  }
 
  protected class EPA {
    //protected final BulletStack stack = BulletStack.get();
   
    public GJK gjk;
    //public btStackAlloc* sa;
    public Face root;
    public int nfaces;
    public int iterations;
    public final Vector3f[][] features = new Vector3f[2][3];
    public final Vector3f[] nearest/*[2]*/ = new Vector3f[] { new Vector3f(), new Vector3f() };
    public final Vector3f normal = new Vector3f();
    public float depth;
    public boolean failed;
   
    {
      for (int i=0; i<features.length; i++) {
        for (int j=0; j<features[i].length; j++) {
          features[i][j] = new Vector3f();
        }
      }
    }

    public EPA(GJK pgjk) {
      gjk = pgjk;
      //sa = pgjk->sa;
    }
   
    public Vector3f GetCoordinates(Face face, Vector3f out) {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      Vector3f tmp1 = Stack.alloc(Vector3f.class);
      Vector3f tmp2 = Stack.alloc(Vector3f.class);

      Vector3f o = Stack.alloc(Vector3f.class);
      o.scale(-face.d, face.n);

      float[] a = floatArrays.getFixed(3);

      tmp1.sub(face.v[0].w, o);
      tmp2.sub(face.v[1].w, o);
      tmp.cross(tmp1, tmp2);
      a[0] = tmp.length();

      tmp1.sub(face.v[1].w, o);
      tmp2.sub(face.v[2].w, o);
      tmp.cross(tmp1, tmp2);
      a[1] = tmp.length();

      tmp1.sub(face.v[2].w, o);
      tmp2.sub(face.v[0].w, o);
      tmp.cross(tmp1, tmp2);
      a[2] = tmp.length();

      float sm = a[0] + a[1] + a[2];

      out.set(a[1], a[2], a[0]);
      out.scale(1f / (sm > 0f ? sm : 1f));

      floatArrays.release(a);

      return out;
    }
   
    public Face FindBest() {
      Face bf = null;
      if (root != null) {
        Face cf = root;
        float bd = cstInf;
        do {
          if (cf.d < bd) {
            bd = cf.d;
            bf = cf;
          }
        }
        while (null != (cf = cf.next));
      }
      return bf;
    }

    public boolean Set(Face f, Mkv a, Mkv b, Mkv c) {
      Vector3f tmp1 = Stack.alloc(Vector3f.class);
      Vector3f tmp2 = Stack.alloc(Vector3f.class);
      Vector3f tmp3 = Stack.alloc(Vector3f.class);

      Vector3f nrm = Stack.alloc(Vector3f.class);
      tmp1.sub(b.w, a.w);
      tmp2.sub(c.w, a.w);
      nrm.cross(tmp1, tmp2);

      float len = nrm.length();

      tmp1.cross(a.w, b.w);
      tmp2.cross(b.w, c.w);
      tmp3.cross(c.w, a.w);

      boolean valid = (tmp1.dot(nrm) >= -EPA_inface_eps) &&
          (tmp2.dot(nrm) >= -EPA_inface_eps) &&
          (tmp3.dot(nrm) >= -EPA_inface_eps);

      f.v[0] = a;
      f.v[1] = b;
      f.v[2] = c;
      f.mark = 0;
      f.n.scale(1f / (len > 0f ? len : cstInf), nrm);
      f.d = Math.max(0, -f.n.dot(a.w));
      return valid;
    }
   
    public Face NewFace(Mkv a, Mkv b, Mkv c) {
      //Face pf = new Face();
      Face pf = stackFace.get();
      if (Set(pf, a, b, c)) {
        if (root != null) {
          root.prev = pf;
        }
        pf.prev = null;
        pf.next = root;
        root = pf;
        ++nfaces;
      }
      else {
        pf.prev = pf.next = null;
      }
      return (pf);
    }
 
    public void Detach(Face face) {
      if (face.prev != null || face.next != null) {
        --nfaces;
        if (face == root) {
          root = face.next;
          root.prev = null;
        }
        else {
          if (face.next == null) {
            face.prev.next = null;
          }
          else {
            face.prev.next = face.next;
            face.next.prev = face.prev;
          }
        }
        face.prev = face.next = null;
      }
    }

    public void Link(Face f0, int e0, Face f1, int e1) {
      f0.f[e0] = f1; f1.e[e1] = e0;
      f1.f[e1] = f0; f0.e[e0] = e1;
    }

    public Mkv Support(Vector3f w) {
      //Mkv v = new Mkv();
      Mkv v = stackMkv.get();
      gjk.Support(w, v);
      return v;
    }
   
    public int BuildHorizon(int markid, Mkv w, Face f, int e, Face[] cf, Face[] ff) {
      int ne = 0;
      if (f.mark != markid) {
        int e1 = mod3[e + 1];
        if ((f.n.dot(w.w) + f.d) > 0) {
          Face nf = NewFace(f.v[e1], f.v[e], w);
          Link(nf, 0, f, e);
          if (cf[0] != null) {
            Link(cf[0], 1, nf, 2);
          }
          else {
            ff[0] = nf;
          }
          cf[0] = nf;
          ne = 1;
        }
        else {
          int e2 = mod3[e + 2];
          Detach(f);
          f.mark = markid;
          ne += BuildHorizon(markid, w, f.f[e1], f.e[e1], cf, ff);
          ne += BuildHorizon(markid, w, f.f[e2], f.e[e2], cf, ff);
        }
      }
      return (ne);
    }

    public float EvaluatePD() {
      return EvaluatePD(EPA_accuracy);
    }
   
    public float EvaluatePD(float accuracy) {
      pushStack();
      try {
        Vector3f tmp = Stack.alloc(Vector3f.class);

        //btBlock* sablock = sa->beginBlock();
        Face bestface = null;
        int markid = 1;
        depth = -cstInf;
        normal.set(0f, 0f, 0f);
        root = null;
        nfaces = 0;
        iterations = 0;
        failed = false;
        /* Prepare hull    */
        if (gjk.EncloseOrigin()) {
          //const U* pfidx = 0;
          int[][] pfidx_ptr = null;
          int pfidx_index = 0;

          int nfidx = 0;
          //const U* peidx = 0;
          int[][] peidx_ptr = null;
          int peidx_index = 0;

          int neidx = 0;
          Mkv[] basemkv = new Mkv[5];
          Face[] basefaces = new Face[6];
          switch (gjk.order) {
            // Tetrahedron
            case 3:
               {
                //pfidx=(const U*)fidx;
                pfidx_ptr = tetrahedron_fidx;
                pfidx_index = 0;

                nfidx = 4;

                //peidx=(const U*)eidx;
                peidx_ptr = tetrahedron_eidx;
                peidx_index = 0;

                neidx = 6;
              }
              break;
            // Hexahedron
            case 4:
               {
                //pfidx=(const U*)fidx;
                pfidx_ptr = hexahedron_fidx;
                pfidx_index = 0;

                nfidx = 6;

                //peidx=(const U*)eidx;
                peidx_ptr = hexahedron_eidx;
                peidx_index = 0;

                neidx = 9;
              }
              break;
          }
          int i;

          for (i = 0; i <= gjk.order; ++i) {
            basemkv[i] = new Mkv();
            basemkv[i].set(gjk.simplex[i]);
          }
          for (i = 0; i < nfidx; ++i, pfidx_index++) {
            basefaces[i] = NewFace(basemkv[pfidx_ptr[pfidx_index][0]], basemkv[pfidx_ptr[pfidx_index][1]], basemkv[pfidx_ptr[pfidx_index][2]]);
          }
          for (i = 0; i < neidx; ++i, peidx_index++) {
            Link(basefaces[peidx_ptr[peidx_index][0]], peidx_ptr[peidx_index][1], basefaces[peidx_ptr[peidx_index][2]], peidx_ptr[peidx_index][3]);
          }
        }
        if (0 == nfaces) {
          //sa->endBlock(sablock);
          return (depth);
        }
        /* Expand hull    */
        for (; iterations < EPA_maxiterations; ++iterations) {
          Face bf = FindBest();
          if (bf != null) {
            tmp.negate(bf.n);
            Mkv w = Support(tmp);
            float d = bf.n.dot(w.w) + bf.d;
            bestface = bf;
            if (d < -accuracy) {
              Face[] cf = new Face[]{null};
              Face[] ff = new Face[]{null};
              int nf = 0;
              Detach(bf);
              bf.mark = ++markid;
              for (int i = 0; i < 3; ++i) {
                nf += BuildHorizon(markid, w, bf.f[i], bf.e[i], cf, ff);
              }
              if (nf <= 2) {
                break;
              }
              Link(cf[0], 1, ff[0], 2);
            }
            else {
              break;
            }
          }
          else {
            break;
          }
        }
        /* Extract contact  */
        if (bestface != null) {
          Vector3f b = GetCoordinates(bestface, Stack.alloc(Vector3f.class));
          normal.set(bestface.n);
          depth = Math.max(0, bestface.d);
          for (int i = 0; i < 2; ++i) {
            float s = i != 0 ? -1f : 1f;
            for (int j = 0; j < 3; ++j) {
              tmp.scale(s, bestface.v[j].r);
              gjk.LocalSupport(tmp, i, features[i][j]);
            }
          }

          Vector3f tmp1 = Stack.alloc(Vector3f.class);
          Vector3f tmp2 = Stack.alloc(Vector3f.class);
          Vector3f tmp3 = Stack.alloc(Vector3f.class);

          tmp1.scale(b.x, features[0][0]);
          tmp2.scale(b.y, features[0][1]);
          tmp3.scale(b.z, features[0][2]);
          VectorUtil.add(nearest[0], tmp1, tmp2, tmp3);

          tmp1.scale(b.x, features[1][0]);
          tmp2.scale(b.y, features[1][1]);
          tmp3.scale(b.z, features[1][2]);
          VectorUtil.add(nearest[1], tmp1, tmp2, tmp3);
        }
        else {
          failed = true;
        }
        //sa->endBlock(sablock);
        return (depth);
      }
      finally {
        popStack();
      }
    }
   
  }
 
  ////////////////////////////////////////////////////////////////////////////
 
  private GJK gjk = new GJK();
 
  public boolean collide(ConvexShape shape0, Transform wtrs0,
      ConvexShape shape1, Transform wtrs1,
      float radialmargin/*,
      btStackAlloc* stackAlloc*/,
      Results results) {
   
    // Initialize
    results.witnesses[0].set(0f, 0f, 0f);
    results.witnesses[1].set(0f, 0f, 0f);
    results.normal.set(0f, 0f, 0f);
    results.depth = 0;
    results.status = ResultsStatus.Separated;
    results.epa_iterations = 0;
    results.gjk_iterations = 0;
    /* Use GJK to locate origin    */
    gjk.init(/*stackAlloc,*/
        wtrs0.basis, wtrs0.origin, shape0,
        wtrs1.basis, wtrs1.origin, shape1,
        radialmargin + EPA_accuracy);
    try {
      boolean collide = gjk.SearchOrigin();
      results.gjk_iterations = gjk.iterations + 1;
      if (collide) {
        /* Then EPA for penetration depth  */
        EPA epa = new EPA(gjk);
        float pd = epa.EvaluatePD();
        results.epa_iterations = epa.iterations + 1;
        if (pd > 0) {
          results.status = ResultsStatus.Penetrating;
          results.normal.set(epa.normal);
          results.depth = pd;
          results.witnesses[0].set(epa.nearest[0]);
          results.witnesses[1].set(epa.nearest[1]);
          return (true);
        }
        else {
          if (epa.failed) {
            results.status = ResultsStatus.EPA_Failed;
          }
        }
      }
      else {
        if (gjk.failed) {
          results.status = ResultsStatus.GJK_Failed;
        }
      }
      return (false);
    }
    finally {
      gjk.destroy();
    }
  }
 
}
TOP

Related Classes of com.bulletphysics.collision.narrowphase.GjkEpaSolver$EPA

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.