Package com.bulletphysics.collision.narrowphase

Source Code of com.bulletphysics.collision.narrowphase.GjkPairDetector

/*
* 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.BulletGlobals;
import com.bulletphysics.BulletStats;
import com.bulletphysics.collision.shapes.ConvexShape;
import com.bulletphysics.linearmath.IDebugDraw;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.Transform;
import cz.advel.stack.Stack;
import cz.advel.stack.StaticAlloc;
import javax.vecmath.Vector3f;

/**
* GjkPairDetector uses GJK to implement the {@link DiscreteCollisionDetectorInterface}.
*
* @author jezek2
*/
public class GjkPairDetector extends DiscreteCollisionDetectorInterface {

  //protected final BulletStack stack = BulletStack.get();
 
  // must be above the machine epsilon
  private static final float REL_ERROR2 = 1.0e-6f;
 
  private final Vector3f cachedSeparatingAxis = new Vector3f();
  private ConvexPenetrationDepthSolver penetrationDepthSolver;
  private SimplexSolverInterface simplexSolver;
  private ConvexShape minkowskiA;
  private ConvexShape minkowskiB;
  private boolean ignoreMargin;
 
  // some debugging to fix degeneracy problems
  public int lastUsedMethod;
  public int curIter;
  public int degenerateSimplex;
  public int catchDegeneracies;
 
  public void init(ConvexShape objectA, ConvexShape objectB, SimplexSolverInterface simplexSolver, ConvexPenetrationDepthSolver penetrationDepthSolver) {
    this.cachedSeparatingAxis.set(0f, 0f, 1f);
    this.ignoreMargin = false;
    this.lastUsedMethod = -1;
    this.catchDegeneracies = 1;
   
    this.penetrationDepthSolver = penetrationDepthSolver;
    this.simplexSolver = simplexSolver;
    this.minkowskiA = objectA;
    this.minkowskiB = objectB;
  }
 
  @StaticAlloc
  public void getClosestPoints(ClosestPointInput input, Result output, IDebugDraw debugDraw, boolean swapResults) {
    Vector3f tmp = Stack.alloc(Vector3f.class);

    float distance = 0f;
    Vector3f normalInB = Stack.alloc(Vector3f.class);
    normalInB.set(0f, 0f, 0f);
    Vector3f pointOnA = Stack.alloc(Vector3f.class), pointOnB = Stack.alloc(Vector3f.class);
    Transform localTransA = Stack.alloc(input.transformA);
    Transform localTransB = Stack.alloc(input.transformB);
    Vector3f positionOffset = Stack.alloc(Vector3f.class);
    positionOffset.add(localTransA.origin, localTransB.origin);
    positionOffset.scale(0.5f);
    localTransA.origin.sub(positionOffset);
    localTransB.origin.sub(positionOffset);

    float marginA = minkowskiA.getMargin();
    float marginB = minkowskiB.getMargin();

    BulletStats.gNumGjkChecks++;

    // for CCD we don't use margins
    if (ignoreMargin) {
      marginA = 0f;
      marginB = 0f;
    }

    curIter = 0;
    int gGjkMaxIter = 1000; // this is to catch invalid input, perhaps check for #NaN?
    cachedSeparatingAxis.set(0f, 1f, 0f);

    boolean isValid = false;
    boolean checkSimplex = false;
    boolean checkPenetration = true;
    degenerateSimplex = 0;

    lastUsedMethod = -1;

    {
      float squaredDistance = BulletGlobals.SIMD_INFINITY;
      float delta = 0f;

      float margin = marginA + marginB;

      simplexSolver.reset();

      Vector3f seperatingAxisInA = Stack.alloc(Vector3f.class);
      Vector3f seperatingAxisInB = Stack.alloc(Vector3f.class);
     
      Vector3f pInA = Stack.alloc(Vector3f.class);
      Vector3f qInB = Stack.alloc(Vector3f.class);
     
      Vector3f pWorld = Stack.alloc(Vector3f.class);
      Vector3f qWorld = Stack.alloc(Vector3f.class);
      Vector3f w = Stack.alloc(Vector3f.class);
     
      Vector3f tmpPointOnA = Stack.alloc(Vector3f.class), tmpPointOnB = Stack.alloc(Vector3f.class);
      Vector3f tmpNormalInB = Stack.alloc(Vector3f.class);
     
      for (;;) //while (true)
      {
        seperatingAxisInA.negate(cachedSeparatingAxis);
        MatrixUtil.transposeTransform(seperatingAxisInA, seperatingAxisInA, input.transformA.basis);

        seperatingAxisInB.set(cachedSeparatingAxis);
        MatrixUtil.transposeTransform(seperatingAxisInB, seperatingAxisInB, input.transformB.basis);

        minkowskiA.localGetSupportingVertexWithoutMargin(seperatingAxisInA, pInA);
        minkowskiB.localGetSupportingVertexWithoutMargin(seperatingAxisInB, qInB);

        pWorld.set(pInA);
        localTransA.transform(pWorld);
       
        qWorld.set(qInB);
        localTransB.transform(qWorld);

        w.sub(pWorld, qWorld);

        delta = cachedSeparatingAxis.dot(w);

        // potential exit, they don't overlap
        if ((delta > 0f) && (delta * delta > squaredDistance * input.maximumDistanceSquared)) {
          checkPenetration = false;
          break;
        }

        // exit 0: the new point is already in the simplex, or we didn't come any closer
        if (simplexSolver.inSimplex(w)) {
          degenerateSimplex = 1;
          checkSimplex = true;
          break;
        }
        // are we getting any closer ?
        float f0 = squaredDistance - delta;
        float f1 = squaredDistance * REL_ERROR2;

        if (f0 <= f1) {
          if (f0 <= 0f) {
            degenerateSimplex = 2;
          }
          checkSimplex = true;
          break;
        }
        // add current vertex to simplex
        simplexSolver.addVertex(w, pWorld, qWorld);

        // calculate the closest point to the origin (update vector v)
        if (!simplexSolver.closest(cachedSeparatingAxis)) {
          degenerateSimplex = 3;
          checkSimplex = true;
          break;
        }

        if (cachedSeparatingAxis.lengthSquared() < REL_ERROR2) {
          degenerateSimplex = 6;
          checkSimplex = true;
          break;
        }
       
        float previousSquaredDistance = squaredDistance;
        squaredDistance = cachedSeparatingAxis.lengthSquared();

        // redundant m_simplexSolver->compute_points(pointOnA, pointOnB);

        // are we getting any closer ?
        if (previousSquaredDistance - squaredDistance <= BulletGlobals.FLT_EPSILON * previousSquaredDistance) {
          simplexSolver.backup_closest(cachedSeparatingAxis);
          checkSimplex = true;
          break;
        }

        // degeneracy, this is typically due to invalid/uninitialized worldtransforms for a CollisionObject  
        if (curIter++ > gGjkMaxIter) {
          //#if defined(DEBUG) || defined (_DEBUG)  
          if (BulletGlobals.DEBUG) {
            System.err.printf("btGjkPairDetector maxIter exceeded:%i\n", curIter);
            System.err.printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
                cachedSeparatingAxis.x,
                cachedSeparatingAxis.y,
                cachedSeparatingAxis.z,
                squaredDistance,
                minkowskiA.getShapeType(),
                minkowskiB.getShapeType());
          }
          //#endif  
          break;

        }

        boolean check = (!simplexSolver.fullSimplex());
        //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());

        if (!check) {
          // do we need this backup_closest here ?
          simplexSolver.backup_closest(cachedSeparatingAxis);
          break;
        }
      }

      if (checkSimplex) {
        simplexSolver.compute_points(pointOnA, pointOnB);
        normalInB.sub(pointOnA, pointOnB);
        float lenSqr = cachedSeparatingAxis.lengthSquared();
        // valid normal
        if (lenSqr < 0.0001f) {
          degenerateSimplex = 5;
        }
        if (lenSqr > BulletGlobals.FLT_EPSILON * BulletGlobals.FLT_EPSILON) {
          float rlen = 1f / (float) Math.sqrt(lenSqr);
          normalInB.scale(rlen); // normalize
          float s = (float) Math.sqrt(squaredDistance);

          assert (s > 0f);

          tmp.scale((marginA / s), cachedSeparatingAxis);
          pointOnA.sub(tmp);

          tmp.scale((marginB / s), cachedSeparatingAxis);
          pointOnB.add(tmp);

          distance = ((1f / rlen) - margin);
          isValid = true;

          lastUsedMethod = 1;
        }
        else {
          lastUsedMethod = 2;
        }
      }

      boolean catchDegeneratePenetrationCase =
          (catchDegeneracies != 0 && penetrationDepthSolver != null && degenerateSimplex != 0 && ((distance + margin) < 0.01f));

      //if (checkPenetration && !isValid)
      if (checkPenetration && (!isValid || catchDegeneratePenetrationCase)) {
        // penetration case

        // if there is no way to handle penetrations, bail out
        if (penetrationDepthSolver != null) {
          // Penetration depth case.
          BulletStats.gNumDeepPenetrationChecks++;

          boolean isValid2 = penetrationDepthSolver.calcPenDepth(
              simplexSolver,
              minkowskiA, minkowskiB,
              localTransA, localTransB,
              cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
              debugDraw/*,input.stackAlloc*/);

          if (isValid2) {
            tmpNormalInB.sub(tmpPointOnB, tmpPointOnA);

            float lenSqr = tmpNormalInB.lengthSquared();
            if (lenSqr > (BulletGlobals.FLT_EPSILON * BulletGlobals.FLT_EPSILON)) {
              tmpNormalInB.scale(1f / (float) Math.sqrt(lenSqr));
              tmp.sub(tmpPointOnA, tmpPointOnB);
              float distance2 = -tmp.length();
              // only replace valid penetrations when the result is deeper (check)
              if (!isValid || (distance2 < distance)) {
                distance = distance2;
                pointOnA.set(tmpPointOnA);
                pointOnB.set(tmpPointOnB);
                normalInB.set(tmpNormalInB);
                isValid = true;
                lastUsedMethod = 3;
              }
              else {

              }
            }
            else {
              //isValid = false;
              lastUsedMethod = 4;
            }
          }
          else {
            lastUsedMethod = 5;
          }

        }
      }
    }

    if (isValid) {
      //#ifdef __SPU__
      //    //spu_printf("distance\n");
      //#endif //__CELLOS_LV2__

      tmp.add(pointOnB, positionOffset);
      output.addContactPoint(
          normalInB,
          tmp,
          distance);
    //printf("gjk add:%f",distance);
    }
  }

  public void setMinkowskiA(ConvexShape minkA) {
    minkowskiA = minkA;
  }

  public void setMinkowskiB(ConvexShape minkB) {
    minkowskiB = minkB;
  }

  public void setCachedSeperatingAxis(Vector3f seperatingAxis) {
    cachedSeparatingAxis.set(seperatingAxis);
  }

  public void setPenetrationDepthSolver(ConvexPenetrationDepthSolver penetrationDepthSolver) {
    this.penetrationDepthSolver = penetrationDepthSolver;
  }

  /**
   * Don't use setIgnoreMargin, it's for Bullet's internal use.
   */
  public void setIgnoreMargin(boolean ignoreMargin) {
    this.ignoreMargin = ignoreMargin;
  }
 
}
TOP

Related Classes of com.bulletphysics.collision.narrowphase.GjkPairDetector

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.