org.jbox2d.dynamics.Fixture Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2013, Daniel Murphy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package org.jbox2d.dynamics;
import org.jbox2d.collision.AABB;
import org.jbox2d.collision.RayCastInput;
import org.jbox2d.collision.RayCastOutput;
import org.jbox2d.collision.broadphase.BroadPhase;
import org.jbox2d.collision.shapes.MassData;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.collision.shapes.ShapeType;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Transform;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.contacts.Contact;
import org.jbox2d.dynamics.contacts.ContactEdge;
/**
* A fixture is used to attach a shape to a body for collision detection. A fixture inherits its
* transform from its parent. Fixtures hold additional non-geometric data such as friction,
* collision filters, etc. Fixtures are created via Body::CreateFixture.
*
* @warning you cannot reuse fixtures.
*
* @author daniel
*/
public class Fixture {
public float m_density;
public Fixture m_next;
public Body m_body;
public Shape m_shape;
public float m_friction;
public float m_restitution;
public FixtureProxy[] m_proxies;
public int m_proxyCount;
public final Filter m_filter;
public boolean m_isSensor;
public Object m_userData;
public Fixture() {
m_userData = null;
m_body = null;
m_next = null;
m_proxies = null;
m_proxyCount = 0;
m_shape = null;
m_filter = new Filter();
}
/**
* Get the type of the child shape. You can use this to down cast to the concrete shape.
*
* @return the shape type.
*/
public ShapeType getType() {
return m_shape.getType();
}
/**
* Get the child shape. You can modify the child shape, however you should not change the number
* of vertices because this will crash some collision caching mechanisms.
*
* @return
*/
public Shape getShape() {
return m_shape;
}
/**
* Is this fixture a sensor (non-solid)?
*
* @return the true if the shape is a sensor.
* @return
*/
public boolean isSensor() {
return m_isSensor;
}
/**
* Set if this fixture is a sensor.
*
* @param sensor
*/
public void setSensor(boolean sensor) {
if (sensor != m_isSensor) {
m_body.setAwake(true);
m_isSensor = sensor;
}
}
/**
* Set the contact filtering data. This is an expensive operation and should not be called
* frequently. This will not update contacts until the next time step when either parent body is
* awake. This automatically calls refilter.
*
* @param filter
*/
public void setFilterData(final Filter filter) {
m_filter.set(filter);
refilter();
}
/**
* Get the contact filtering data.
*
* @return
*/
public Filter getFilterData() {
return m_filter;
}
/**
* Call this if you want to establish collision that was previously disabled by
* ContactFilter::ShouldCollide.
*/
public void refilter() {
if (m_body == null) {
return;
}
// Flag associated contacts for filtering.
ContactEdge edge = m_body.getContactList();
while (edge != null) {
Contact contact = edge.contact;
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
if (fixtureA == this || fixtureB == this) {
contact.flagForFiltering();
}
edge = edge.next;
}
World world = m_body.getWorld();
if (world == null) {
return;
}
// Touch each proxy so that new pairs may be created
BroadPhase broadPhase = world.m_contactManager.m_broadPhase;
for (int i = 0; i < m_proxyCount; ++i) {
broadPhase.touchProxy(m_proxies[i].proxyId);
}
}
/**
* Get the parent body of this fixture. This is NULL if the fixture is not attached.
*
* @return the parent body.
* @return
*/
public Body getBody() {
return m_body;
}
/**
* Get the next fixture in the parent body's fixture list.
*
* @return the next shape.
* @return
*/
public Fixture getNext() {
return m_next;
}
public void setDensity(float density) {
assert (density >= 0f);
m_density = density;
}
public float getDensity() {
return m_density;
}
/**
* Get the user data that was assigned in the fixture definition. Use this to store your
* application specific data.
*
* @return
*/
public Object getUserData() {
return m_userData;
}
/**
* Set the user data. Use this to store your application specific data.
*
* @param data
*/
public void setUserData(Object data) {
m_userData = data;
}
/**
* Test a point for containment in this fixture. This only works for convex shapes.
*
* @param p a point in world coordinates.
* @return
*/
public boolean testPoint(final Vec2 p) {
return m_shape.testPoint(m_body.m_xf, p);
}
/**
* Cast a ray against this shape.
*
* @param output the ray-cast results.
* @param input the ray-cast input parameters.
* @param output
* @param input
*/
public boolean raycast(RayCastOutput output, RayCastInput input, int childIndex) {
return m_shape.raycast(output, input, m_body.m_xf, childIndex);
}
/**
* Get the mass data for this fixture. The mass data is based on the density and the shape. The
* rotational inertia is about the shape's origin.
*
* @return
*/
public void getMassData(MassData massData) {
m_shape.computeMass(massData, m_density);
}
/**
* Get the coefficient of friction.
*
* @return
*/
public float getFriction() {
return m_friction;
}
/**
* Set the coefficient of friction. This will _not_ change the friction of existing contacts.
*
* @param friction
*/
public void setFriction(float friction) {
m_friction = friction;
}
/**
* Get the coefficient of restitution.
*
* @return
*/
public float getRestitution() {
return m_restitution;
}
/**
* Set the coefficient of restitution. This will _not_ change the restitution of existing
* contacts.
*
* @param restitution
*/
public void setRestitution(float restitution) {
m_restitution = restitution;
}
/**
* Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a more accurate
* AABB, compute it using the shape and the body transform.
*
* @return
*/
public AABB getAABB(int childIndex) {
assert (childIndex >= 0 && childIndex < m_proxyCount);
return m_proxies[childIndex].aabb;
}
/**
* Compute the distance from this fixture.
*
* @param p a point in world coordinates.
* @return distance
*/
public float computeDistance(Vec2 p, int childIndex, Vec2 normalOut) {
return m_shape.computeDistanceToOut(m_body.getTransform(), p, childIndex, normalOut);
}
// We need separation create/destroy functions from the constructor/destructor because
// the destructor cannot access the allocator (no destructor arguments allowed by C++).
public void create(Body body, FixtureDef def) {
m_userData = def.userData;
m_friction = def.friction;
m_restitution = def.restitution;
m_body = body;
m_next = null;
m_filter.set(def.filter);
m_isSensor = def.isSensor;
m_shape = def.shape.clone();
// Reserve proxy space
int childCount = m_shape.getChildCount();
if (m_proxies == null) {
m_proxies = new FixtureProxy[childCount];
for (int i = 0; i < childCount; i++) {
m_proxies[i] = new FixtureProxy();
m_proxies[i].fixture = null;
m_proxies[i].proxyId = BroadPhase.NULL_PROXY;
}
}
if (m_proxies.length < childCount) {
FixtureProxy[] old = m_proxies;
int newLen = MathUtils.max(old.length * 2, childCount);
m_proxies = new FixtureProxy[newLen];
System.arraycopy(old, 0, m_proxies, 0, old.length);
for (int i = 0; i < newLen; i++) {
if (i >= old.length) {
m_proxies[i] = new FixtureProxy();
}
m_proxies[i].fixture = null;
m_proxies[i].proxyId = BroadPhase.NULL_PROXY;
}
}
m_proxyCount = 0;
m_density = def.density;
}
public void destroy() {
// The proxies must be destroyed before calling this.
assert (m_proxyCount == 0);
// Free the child shape.
m_shape = null;
m_proxies = null;
m_next = null;
// TODO pool shapes
// TODO pool fixtures
}
// These support body activation/deactivation.
public void createProxies(BroadPhase broadPhase, final Transform xf) {
assert (m_proxyCount == 0);
// Create proxies in the broad-phase.
m_proxyCount = m_shape.getChildCount();
for (int i = 0; i < m_proxyCount; ++i) {
FixtureProxy proxy = m_proxies[i];
m_shape.computeAABB(proxy.aabb, xf, i);
proxy.proxyId = broadPhase.createProxy(proxy.aabb, proxy);
proxy.fixture = this;
proxy.childIndex = i;
}
}
/**
* Internal method
*
* @param broadPhase
*/
public void destroyProxies(BroadPhase broadPhase) {
// Destroy proxies in the broad-phase.
for (int i = 0; i < m_proxyCount; ++i) {
FixtureProxy proxy = m_proxies[i];
broadPhase.destroyProxy(proxy.proxyId);
proxy.proxyId = BroadPhase.NULL_PROXY;
}
m_proxyCount = 0;
}
private final AABB pool1 = new AABB();
private final AABB pool2 = new AABB();
private final Vec2 displacement = new Vec2();
/**
* Internal method
*
* @param broadPhase
* @param xf1
* @param xf2
*/
protected void synchronize(BroadPhase broadPhase, final Transform transform1,
final Transform transform2) {
if (m_proxyCount == 0) {
return;
}
for (int i = 0; i < m_proxyCount; ++i) {
FixtureProxy proxy = m_proxies[i];
// Compute an AABB that covers the swept shape (may miss some rotation effect).
final AABB aabb1 = pool1;
final AABB aab = pool2;
m_shape.computeAABB(aabb1, transform1, proxy.childIndex);
m_shape.computeAABB(aab, transform2, proxy.childIndex);
proxy.aabb.lowerBound.x =
aabb1.lowerBound.x < aab.lowerBound.x ? aabb1.lowerBound.x : aab.lowerBound.x;
proxy.aabb.lowerBound.y =
aabb1.lowerBound.y < aab.lowerBound.y ? aabb1.lowerBound.y : aab.lowerBound.y;
proxy.aabb.upperBound.x =
aabb1.upperBound.x > aab.upperBound.x ? aabb1.upperBound.x : aab.upperBound.x;
proxy.aabb.upperBound.y =
aabb1.upperBound.y > aab.upperBound.y ? aabb1.upperBound.y : aab.upperBound.y;
displacement.x = transform2.p.x - transform1.p.x;
displacement.y = transform2.p.y - transform1.p.y;
broadPhase.moveProxy(proxy.proxyId, proxy.aabb, displacement);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy