Package com.bulletphysics.collision.dispatch

Source Code of com.bulletphysics.collision.dispatch.SimulationIslandManager

/*
* 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.dispatch;

import com.bulletphysics.BulletStats;
import java.util.Comparator;
import com.bulletphysics.collision.broadphase.BroadphasePair;
import com.bulletphysics.collision.broadphase.Dispatcher;
import com.bulletphysics.collision.narrowphase.PersistentManifold;
import com.bulletphysics.linearmath.MiscUtil;
import com.bulletphysics.util.ObjectArrayList;

/**
* SimulationIslandManager creates and handles simulation islands, using {@link UnionFind}.
*
* @author jezek2
*/
public class SimulationIslandManager {

  private final UnionFind unionFind = new UnionFind();

  private final ObjectArrayList<PersistentManifold> islandmanifold = new ObjectArrayList<PersistentManifold>();
  private final ObjectArrayList<CollisionObject> islandBodies = new ObjectArrayList<CollisionObject>();
 
  public void initUnionFind(int n) {
    unionFind.reset(n);
  }
 
  public UnionFind getUnionFind() {
    return unionFind;
  }
 
  public void findUnions(Dispatcher dispatcher, CollisionWorld colWorld) {
    ObjectArrayList<BroadphasePair> pairPtr = colWorld.getPairCache().getOverlappingPairArray();
    for (int i=0; i<pairPtr.size(); i++) {
      BroadphasePair collisionPair = pairPtr.getQuick(i);
     
      CollisionObject colObj0 = (CollisionObject) collisionPair.pProxy0.clientObject;
      CollisionObject colObj1 = (CollisionObject) collisionPair.pProxy1.clientObject;

      if (((colObj0 != null) && ((colObj0).mergesSimulationIslands())) &&
          ((colObj1 != null) && ((colObj1).mergesSimulationIslands()))) {
        unionFind.unite((colObj0).getIslandTag(), (colObj1).getIslandTag());
      }
    }
  }

  public void updateActivationState(CollisionWorld colWorld, Dispatcher dispatcher) {
    initUnionFind(colWorld.getCollisionObjectArray().size());

    // put the index into m_controllers into m_tag 
    {
      int index = 0;
      int i;
      for (i = 0; i < colWorld.getCollisionObjectArray().size(); i++) {
        CollisionObject collisionObject = colWorld.getCollisionObjectArray().getQuick(i);
        collisionObject.setIslandTag(index);
        collisionObject.setCompanionId(-1);
        collisionObject.setHitFraction(1f);
        index++;
      }
    }
    // do the union find

    findUnions(dispatcher, colWorld);
  }
 
  public void storeIslandActivationState(CollisionWorld colWorld) {
    // put the islandId ('find' value) into m_tag 
    {
      int index = 0;
      int i;
      for (i = 0; i < colWorld.getCollisionObjectArray().size(); i++) {
        CollisionObject collisionObject = colWorld.getCollisionObjectArray().getQuick(i);
        if (!collisionObject.isStaticOrKinematicObject()) {
          collisionObject.setIslandTag(unionFind.find(index));
          collisionObject.setCompanionId(-1);
        }
        else {
          collisionObject.setIslandTag(-1);
          collisionObject.setCompanionId(-2);
        }
        index++;
      }
    }
  }
 
  private static int getIslandId(PersistentManifold lhs) {
    int islandId;
    CollisionObject rcolObj0 = (CollisionObject) lhs.getBody0();
    CollisionObject rcolObj1 = (CollisionObject) lhs.getBody1();
    islandId = rcolObj0.getIslandTag() >= 0? rcolObj0.getIslandTag() : rcolObj1.getIslandTag();
    return islandId;
  }

  public void buildIslands(Dispatcher dispatcher, ObjectArrayList<CollisionObject> collisionObjects) {
    BulletStats.pushProfile("islandUnionFindAndQuickSort");
    try {
      islandmanifold.clear();

      // we are going to sort the unionfind array, and store the element id in the size
      // afterwards, we clean unionfind, to make sure no-one uses it anymore

      getUnionFind().sortIslands();
      int numElem = getUnionFind().getNumElements();

      int endIslandIndex = 1;
      int startIslandIndex;

      // update the sleeping state for bodies, if all are sleeping
      for (startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex) {
        int islandId = getUnionFind().getElement(startIslandIndex).id;
        for (endIslandIndex = startIslandIndex + 1; (endIslandIndex < numElem) && (getUnionFind().getElement(endIslandIndex).id == islandId); endIslandIndex++) {
        }

        //int numSleeping = 0;

        boolean allSleeping = true;

        int idx;
        for (idx = startIslandIndex; idx < endIslandIndex; idx++) {
          int i = getUnionFind().getElement(idx).sz;

          CollisionObject colObj0 = collisionObjects.getQuick(i);
          if ((colObj0.getIslandTag() != islandId) && (colObj0.getIslandTag() != -1)) {
            //System.err.println("error in island management\n");
          }

          assert ((colObj0.getIslandTag() == islandId) || (colObj0.getIslandTag() == -1));
          if (colObj0.getIslandTag() == islandId) {
            if (colObj0.getActivationState() == CollisionObject.ACTIVE_TAG) {
              allSleeping = false;
            }
            if (colObj0.getActivationState() == CollisionObject.DISABLE_DEACTIVATION) {
              allSleeping = false;
            }
          }
        }


        if (allSleeping) {
          //int idx;
          for (idx = startIslandIndex; idx < endIslandIndex; idx++) {
            int i = getUnionFind().getElement(idx).sz;
            CollisionObject colObj0 = collisionObjects.getQuick(i);
            if ((colObj0.getIslandTag() != islandId) && (colObj0.getIslandTag() != -1)) {
              //System.err.println("error in island management\n");
            }

            assert ((colObj0.getIslandTag() == islandId) || (colObj0.getIslandTag() == -1));

            if (colObj0.getIslandTag() == islandId) {
              colObj0.setActivationState(CollisionObject.ISLAND_SLEEPING);
            }
          }
        }
        else {

          //int idx;
          for (idx = startIslandIndex; idx < endIslandIndex; idx++) {
            int i = getUnionFind().getElement(idx).sz;

            CollisionObject colObj0 = collisionObjects.getQuick(i);
            if ((colObj0.getIslandTag() != islandId) && (colObj0.getIslandTag() != -1)) {
              //System.err.println("error in island management\n");
            }

            assert ((colObj0.getIslandTag() == islandId) || (colObj0.getIslandTag() == -1));

            if (colObj0.getIslandTag() == islandId) {
              if (colObj0.getActivationState() == CollisionObject.ISLAND_SLEEPING) {
                colObj0.setActivationState(CollisionObject.WANTS_DEACTIVATION);
              }
            }
          }
        }
      }


      int i;
      int maxNumManifolds = dispatcher.getNumManifolds();

      //#define SPLIT_ISLANDS 1
      //#ifdef SPLIT_ISLANDS
      //#endif //SPLIT_ISLANDS

      for (i = 0; i < maxNumManifolds; i++) {
        PersistentManifold manifold = dispatcher.getManifoldByIndexInternal(i);

        CollisionObject colObj0 = (CollisionObject) manifold.getBody0();
        CollisionObject colObj1 = (CollisionObject) manifold.getBody1();

        // todo: check sleeping conditions!
        if (((colObj0 != null) && colObj0.getActivationState() != CollisionObject.ISLAND_SLEEPING) ||
            ((colObj1 != null) && colObj1.getActivationState() != CollisionObject.ISLAND_SLEEPING)) {

          // kinematic objects don't merge islands, but wake up all connected objects
          if (colObj0.isKinematicObject() && colObj0.getActivationState() != CollisionObject.ISLAND_SLEEPING) {
            colObj1.activate();
          }
          if (colObj1.isKinematicObject() && colObj1.getActivationState() != CollisionObject.ISLAND_SLEEPING) {
            colObj0.activate();
          }
          //#ifdef SPLIT_ISLANDS
          //filtering for response
          if (dispatcher.needsResponse(colObj0, colObj1)) {
            islandmanifold.add(manifold);
          }
          //#endif //SPLIT_ISLANDS
        }
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }

  public void buildAndProcessIslands(Dispatcher dispatcher, ObjectArrayList<CollisionObject> collisionObjects, IslandCallback callback) {
    buildIslands(dispatcher, collisionObjects);

    int endIslandIndex = 1;
    int startIslandIndex;
    int numElem = getUnionFind().getNumElements();

    BulletStats.pushProfile("processIslands");
    try {
      //#ifndef SPLIT_ISLANDS
      //btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
      //
      //callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
      //#else
      // Sort manifolds, based on islands
      // Sort the vector using predicate and std::sort
      //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);

      int numManifolds = islandmanifold.size();

      // we should do radix sort, it it much faster (O(n) instead of O (n log2(n))
      //islandmanifold.heapSort(btPersistentManifoldSortPredicate());
     
      // JAVA NOTE: memory optimized sorting with caching of temporary array
      //Collections.sort(islandmanifold, persistentManifoldComparator);
      MiscUtil.quickSort(islandmanifold, persistentManifoldComparator);

      // now process all active islands (sets of manifolds for now)

      int startManifoldIndex = 0;
      int endManifoldIndex = 1;

      //int islandId;

      //printf("Start Islands\n");

      // traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
      for (startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex) {
        int islandId = getUnionFind().getElement(startIslandIndex).id;
        boolean islandSleeping = false;

        for (endIslandIndex = startIslandIndex; (endIslandIndex < numElem) && (getUnionFind().getElement(endIslandIndex).id == islandId); endIslandIndex++) {
          int i = getUnionFind().getElement(endIslandIndex).sz;
          CollisionObject colObj0 = collisionObjects.getQuick(i);
          islandBodies.add(colObj0);
          if (!colObj0.isActive()) {
            islandSleeping = true;
          }
        }


        // find the accompanying contact manifold for this islandId
        int numIslandManifolds = 0;
        //ObjectArrayList<PersistentManifold> startManifold = null;
        int startManifold_idx = -1;

        if (startManifoldIndex < numManifolds) {
          int curIslandId = getIslandId(islandmanifold.getQuick(startManifoldIndex));
          if (curIslandId == islandId) {
            //startManifold = &m_islandmanifold[startManifoldIndex];
            //startManifold = islandmanifold.subList(startManifoldIndex, islandmanifold.size());
            startManifold_idx = startManifoldIndex;

            for (endManifoldIndex = startManifoldIndex + 1; (endManifoldIndex < numManifolds) && (islandId == getIslandId(islandmanifold.getQuick(endManifoldIndex))); endManifoldIndex++) {

            }
            // Process the actual simulation, only if not sleeping/deactivated
            numIslandManifolds = endManifoldIndex - startManifoldIndex;
          }

        }

        if (!islandSleeping) {
          callback.processIsland(islandBodies, islandBodies.size(), islandmanifold, startManifold_idx, numIslandManifolds, islandId);
          //printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
        }

        if (numIslandManifolds != 0) {
          startManifoldIndex = endManifoldIndex;
        }

        islandBodies.clear();
      }
      //#endif //SPLIT_ISLANDS
    }
    finally {
      BulletStats.popProfile();
    }
  }

  ////////////////////////////////////////////////////////////////////////////
 
  public static abstract class IslandCallback {
    public abstract void processIsland(ObjectArrayList<CollisionObject> bodies, int numBodies, ObjectArrayList<PersistentManifold> manifolds, int manifolds_offset, int numManifolds, int islandId);
  }
 
  private static final Comparator<PersistentManifold> persistentManifoldComparator = new Comparator<PersistentManifold>() {
    public int compare(PersistentManifold lhs, PersistentManifold rhs) {
      return getIslandId(lhs) < getIslandId(rhs)? -1 : +1;
    }
  };
 
}
TOP

Related Classes of com.bulletphysics.collision.dispatch.SimulationIslandManager

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.