/*
* JBox2D - A Java Port of Erin Catto's Box2D
*
* JBox2D homepage: http://jbox2d.sourceforge.net/
* Box2D homepage: http://www.box2d.org
*
* 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 org.jbox2d.collision;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.Body;
//Updated through rev. 56->139 of b2Shape.cpp/.h
/**
* A shape is used for collision detection. Shapes are created in World.
* You can use shape for collision detection before they are attached to the world.
*
Warning: you cannot reuse shapes on different bodies, they must
* be re-created or copied.
*/
public abstract class Shape {
/** Unique id for shape for sorting (C++ version uses memory address) */
public int uid;
/**
* Used to generate uids - not initialized on applet reload,
* but that's okay since these just have to be unique.
*/
static private int uidcount = 0;
public int m_type;
public Shape m_next;
public Body m_body;
/** Sweep radius relative to the parent body's center of mass. */
public float m_sweepRadius;
public float m_density;
public float m_friction;
public float m_restitution;
public int m_proxyId;
public FilterData m_filter;
public boolean m_isSensor;
public Object m_userData;
public Shape(ShapeDef def) {
uid = uidcount++; //Java version only (C++ version sorts by memory location)
m_userData = def.userData;
m_friction = def.friction;
m_restitution = def.restitution;
m_density = def.density;
m_body = null;
m_sweepRadius = 0.0f;
m_next = null;
m_proxyId = PairManager.NULL_PROXY;
m_filter = new FilterData();
m_filter.categoryBits = def.filter.categoryBits;
m_filter.maskBits = def.filter.maskBits;
m_filter.groupIndex = def.filter.groupIndex;
m_isSensor = def.isSensor;
}
/** Get the coefficient of friction. */
public float getFriction() {
return m_friction;
}
/** Set the coefficient of friction. */
public void setFriction(float friction) {
m_friction = friction;
}
/** Get the coefficient of restitution. */
public float getRestitution() {
return m_restitution;
}
/** Set the coefficient of restitution. */
public void setRestitution(float restitution) {
m_restitution = restitution;
}
/** Set the collision filtering data. */
public void setFilterData(FilterData filter){
m_filter.set(filter);
}
/** Get the collision filtering data. */
public FilterData getFilterData() {
return m_filter;
}
/**
* Get the type of this shape. You can use this to down cast to the concrete shape.
* @return the shape type.
*/
public int getType() {
return m_type;
}
/**
* Is this shape a sensor (non-solid)?
* @return the true if the shape is a sensor.
*/
public boolean isSensor() {
return m_isSensor;
}
/**
* Get the user data that was assigned in the shape definition. Use this to
* store your application specific data.
*/
public Object getUserData() {
return m_userData;
}
/**
* Set the user data associated with the object.
* @param o User data to set
*/
public void setUserData(Object o) {
m_userData = o;
}
/**
* Get the parent body of this shape. This is NULL if the shape is not attached.
* @return the parent body.
*/
public Body getBody() {
return m_body;
}
/**
* Get the next shape in the parent body's shape list.
* @return the next shape.
*/
public Shape getNext() {
return m_next;
}
/**
* Get the sweep radius of the shape.
* @return the sweep radius
*/
public float getSweepRadius() {
return m_sweepRadius;
}
/**
* Test a point for containment in this shape. This only works for convex shapes.
* @param xf the shape world transform.
* @param p a point in world coordinates.
* @return true if the point is within the shape
*/
public abstract boolean testPoint(XForm xf, Vec2 p);
/*
/// Perform a ray cast against this shape.
/// @param xf the shape world transform.
/// @param lambda returns the hit fraction. You can use this to compute the contact point
/// p = (1 - lambda) * segment.p1 + lambda * segment.p2.
/// @param normal returns the normal at the contact point. If there is no intersection, the normal
/// is not set.
/// @param segment defines the begin and end point of the ray cast.
/// @param maxLambda a number typically in the range [0,1].
/// @return true if there was an intersection.
public boolean TestSegment( const b2XForm& xf,
float32* lambda,
b2Vec2* normal,
const b2Segment& segment,
float32 maxLambda) const = 0;*/
/**
* Given a transform, compute the associated axis aligned bounding box for this shape.
* @param aabb returns the axis aligned box.
* @param xf the world transform of the shape.
*/
public abstract void computeAABB(AABB aabb, XForm xf);
/**
* Given two transforms, compute the associated swept axis aligned bounding box for this shape.
* @param aabb returns the axis aligned box. (return parameter)
* @param xf1 the starting shape world transform.
* @param xf2 the ending shape world transform.
*/
public abstract void computeSweptAABB(AABB aabb,
XForm xf1,
XForm xf2);
/**
* Compute the mass properties of this shape using its dimensions and density.
* The inertia tensor is computed about the local origin, not the centroid.
* @param massData returns the mass data for this shape. (return parameter)
*/
public abstract void computeMass(MassData massData);
/* INTERNALS BELOW */
/** Internal */
public abstract void updateSweepRadius(Vec2 center);
/** Internal */
public boolean synchronize(BroadPhase broadPhase, XForm transform1, XForm transform2) {
if (m_proxyId == PairManager.NULL_PROXY) {
return false;
}
// Compute an AABB that covers the swept shape (may miss some rotation effect).
AABB aabb = new AABB();
computeSweptAABB(aabb, transform1, transform2);
//if (this.getType() == ShapeType.CIRCLE_SHAPE){
// System.out.println("Sweeping: "+transform1+" " +transform2);
// System.out.println("Resulting AABB: "+aabb);
//}
if (broadPhase.inRange(aabb)) {
broadPhase.moveProxy(m_proxyId, aabb);
return true;
} else {
return false;
}
}
/** Internal */
public void refilterProxy(BroadPhase broadPhase, XForm transform){
if (m_proxyId == PairManager.NULL_PROXY){
return;
}
broadPhase.destroyProxy(m_proxyId);
AABB aabb = new AABB();
computeAABB(aabb, transform);
boolean inRange = broadPhase.inRange(aabb);
if (inRange) {
m_proxyId = broadPhase.createProxy(aabb, this);
} else {
m_proxyId = PairManager.NULL_PROXY;
}
}
/** Internal */
public static Shape create(ShapeDef def) {
if (def.type == ShapeType.CIRCLE_SHAPE) {
return new CircleShape(def);
}
else if (def.type == ShapeType.POLYGON_SHAPE) {
return new PolygonShape(def);
}
//assert false;
return null;
}
/** Internal */
public static void destroy(Shape s) {
s.destructor();
}
/** Internal */
public void destructor() {
//assert(m_proxyId == PairManager.NULL_PROXY);
}
/** Internal */
public void createProxy(BroadPhase broadPhase, XForm transform) {
//assert(m_proxyId == PairManager.NULL_PROXY);
AABB aabb = new AABB();
computeAABB(aabb, transform);
boolean inRange = broadPhase.inRange(aabb);
// You are creating a shape outside the world box.
//assert(inRange);
if (inRange){
m_proxyId = broadPhase.createProxy(aabb, this);
} else {
m_proxyId = PairManager.NULL_PROXY;
}
}
/** Internal */
public void destroyProxy(BroadPhase broadPhase) {
if (m_proxyId != PairManager.NULL_PROXY) {
broadPhase.destroyProxy(m_proxyId);
m_proxyId = PairManager.NULL_PROXY;
}
}
}