/*
* 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 edu.eside.flingbox.math.Intersect;
import edu.eside.flingbox.math.Matrix22;
import edu.eside.flingbox.math.Vector2D;
import edu.eside.flingbox.physics.PhysicBody;
import edu.eside.flingbox.physics.PhysicBody.OnMovementListener;
/**
* Collider for a polygon. it handles all functions needed by Collision system
* NOTE This class should only be created by {@link PhisicPolygon}.
*
* How collision detector optimizer works: - When created collider check each
* polygon's vertex angle and stores them. - When bounding circle collides
* Collider checks only segments in other circle region.
*
*/
public class ColliderPolygon extends Collider implements OnMovementListener {
/** Handled in Physics, only pointer */
private final Vector2D[] mPolygonContour;
/** Located and rotated contour */
private final Vector2D[] mLocatedContour;
/**
* Default constructor for a polygon collider.
*
* @param contour
* Polygon's points. It handles pointer in order to preserve
* recurses, so mPolygonContour should be automatically rotated.
* NOTE It has to be in counterclockwise ordering!!!
*
* @return
*/
public ColliderPolygon(final Vector2D[] contour, PhysicBody thisPhysic) {
super(thisPhysic);
final int pointsCount = contour.length;
mPolygonContour = contour;
mRadius = computeBoundingCircleRadius(contour);
mLocatedContour = new Vector2D[pointsCount];
for (int i = 0; i < pointsCount; i++)
mLocatedContour[i] = new Vector2D();
}
/**
*
*/
public Contact[] checkContacts(final Collider collider) {
if (!super.canContact(collider))
return new Contact[0];
final Vector2D[] polygon = updateLocatedPolygon();
final Vector2D[] otherPolygon = ((ColliderPolygon) collider)
.updateLocatedPolygon();
/* Find intersections */
// Intersect[] intersections = Intersect.intersectPolygons(polygon,
// otherPolygon);
Intersect[] intersections = Intersect.intersectPolygons(polygon,
otherPolygon);
/* Compute detected intersections */
Contact[] contacts = new Contact[intersections.length];
for (int i = intersections.length - 1; i >= 0; i--) {
Intersect intersect = intersections[i];
Vector2D position = new Vector2D(intersect.outgoingPoint).add(
intersect.ingoingPoint).mul(0.5f);
Vector2D sense = new Vector2D(intersect.outgoingPoint)
.sub(intersect.ingoingPoint);
contacts[i] = new Contact(this.mPhysicBody, collider.mPhysicBody,
position, sense, intersect);
}
return contacts;
}
/**
* Computes bounding circle with center in point (0, 0)
*
* @param contour
* Polygon's contour
* @return Circles radius
*/
private static float computeBoundingCircleRadius(final Vector2D[] contour) {
float radiusSquare = 0.0f;
for (int i = contour.length - 1; i >= 0; i--) { // Do not use fast
// enumeration since
// performance issues
final Vector2D v = contour[i];
float vRadSquare = (v.i * v.i) + (v.j * v.j);
if (vRadSquare > radiusSquare)
radiusSquare = vRadSquare;
}
return (float) Math.sqrt(radiusSquare);
}
/**
* Moves polygon to determinate point and rotates it
*
* @return New translated polygon
*/
private Vector2D[] updateLocatedPolygon() {
final Vector2D[] polygon = mPolygonContour;
final Vector2D[] locatedPolygon = mLocatedContour;
final Vector2D position = mPosition;
final float angle = mAngle;
final int pointsCount = polygon.length;
final Matrix22 rotationMatrix = new Matrix22(angle);
for (int i = 0; i < pointsCount; i++)
locatedPolygon[i].set(polygon[i]).mul(rotationMatrix).add(position);
return locatedPolygon;
}
}