/*
* Flingbox - An OpenSource physics sandbox for Google's Android
* Copyright (C) 2009 Jon Ander Peñalba & Endika Gutiérrez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.eside.flingbox.physics.collisions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import android.util.Log;
import edu.eside.flingbox.physics.PhysicBody;
import edu.eside.flingbox.utils.PositionComparator;
/**
* Arbiter manages the collisions between bodies
*/
public class Arbiter {
/** List with all colliders on the scene */
private final ArrayList<Collider> mCollisionableBodies = new ArrayList<Collider>();
/** Adds new collider to the arbiter */
public void add(final Collider collider) {
mCollisionableBodies.add(collider);
}
/** Removes a collider from the arbiter */
public boolean remove(final Collider collider) {
return mCollisionableBodies.remove(collider);
}
/**
* Checks collision between bodies that are managed by the arbiter.
*
* @return number of collisions
*/
public void checkCollisions() {
final ArrayList<Collider> bodies = mCollisionableBodies;
final ArrayList<Contact> contactsToSolve = new ArrayList<Contact>();
final int bodiesCount = bodies.size();
/* Start checking movable objects */
for (int i = bodiesCount - 1; i >= 0; i--)
for (int j = i - 1; j >= 0; j--) {
Contact[] contacts = bodies.get(i).checkContacts(bodies.get(j));
for (Contact contact : contacts)
contactsToSolve.add(contact);
}
/* Sort contacts to solve those */
Collections.sort(contactsToSolve, PositionComparator.UPPER_COMPARATOR);
final ArrayList<Contact> isolatedContactTree = new ArrayList<Contact>();
while (!contactsToSolve.isEmpty()) {
isolatedContactTree.clear();
Contact treeRoot = contactsToSolve.get(0); // get top contact
contactsToSolve.remove(0);
isolatedContactTree.add(treeRoot);
getIsolatedContactsTree(treeRoot.collidedBody, contactsToSolve,
isolatedContactTree);
getIsolatedContactsTree(treeRoot.collidingBody, contactsToSolve,
isolatedContactTree);
solveIsolatedContactTree(isolatedContactTree);
}
}
private void solveIsolatedContactTree(
final ArrayList<Contact> isolatedContacts) {
// Vector2D totalImpulse = new Vector2D();
for (Contact contact : isolatedContacts) {
ContactSolver.solveCollision(contact);
ContactSolver.solvePenetration(contact);
}
for (int i = isolatedContacts.size() - 2; i >= 0; i--) {
ContactSolver.solveCollision(isolatedContacts.get(i));
ContactSolver.solvePenetration(isolatedContacts.get(i));
}
}
private void getIsolatedContactsTree(final PhysicBody rootBody,
final ArrayList<Contact> contacts,
ArrayList<Contact> isolatedContacts) {
try {
for (int i = 0; i < contacts.size(); i++) {
Contact contact = contacts.get(i);
if (contact.concerns(rootBody)) {
contacts.remove(contact);
i--;
isolatedContacts.add(contact);
getIsolatedContactsTree(contact.otherBody(rootBody),
contacts, isolatedContacts);
}
}
} catch (ConcurrentModificationException ex) {
Log
.e(
"flingbox",
"ConcurrentModificationException getting isolated contacts tree",
ex);
}
}
}