/*
* 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.dynamics.contacts;
import java.util.ArrayList;
import java.util.List;
import org.jbox2d.collision.Manifold;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.collision.shapes.ShapeType;
import org.jbox2d.common.MathUtils;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.ContactListener;
import org.jbox2d.dynamics.World;
// Updated to rev 142 of b2Contact.h/cpp
/**
* Base class for contacts between shapes.
* @author ewjordan
*
*/
public abstract class Contact {
public static final int e_nonSolidFlag = 0x0001;
public static final int e_slowFlag = 0x0002;
public static final int e_islandFlag = 0x0004;
public static final int e_toiFlag = 0x0008;
static ArrayList<ContactRegister> s_registers;
static boolean s_initialized;
/** The parent world. */
public World m_world;
/* World pool and list pointers. */
public Contact m_prev;
public Contact m_next;
/** Node for connecting bodies. */
public final ContactEdge m_node1;
/** Node for connecting bodies. */
public final ContactEdge m_node2;
public Shape m_shape1;
public Shape m_shape2;
/** Combined friction */
public float m_friction;
/** Combined restitution */
public float m_restitution;
// public boolean m_islandFlag;
public int m_flags;
public int m_manifoldCount;
public float m_toi;
public abstract void evaluate(ContactListener listener);
/** Get the manifold array. */
public abstract List<Manifold> getManifolds();
/**
* Get the number of manifolds. This is 0 or 1 between convex shapes.
* This may be greater than 1 for convex-vs-concave shapes. Each
* manifold holds up to two contact points with a shared contact normal.
*/
public int getManifoldCount() {
/*
* List<Manifold> m = GetManifolds(); if (m == null) return 0; else
* return GetManifolds().size();
*/
return m_manifoldCount;
}
public boolean isSolid() {
return (m_flags & e_nonSolidFlag) == 0;
}
public Contact() {
m_node1 = new ContactEdge();
m_node2 = new ContactEdge();
}
public Contact(final Shape s1, final Shape s2) {
this();
m_flags = 0;
if (s1.isSensor() || s2.isSensor()) {
m_flags |= e_nonSolidFlag;
}
m_shape1 = s1;
m_shape2 = s2;
m_manifoldCount = 0;
//getManifolds().clear(); //unnecessary, I think// djm now causes error
m_friction = MathUtils.sqrt(m_shape1.m_friction * m_shape2.m_friction);
m_restitution = MathUtils.max(m_shape1.m_restitution, m_shape2.m_restitution);
//m_world = s1.m_body.m_world;
m_prev = null;
m_next = null;
m_node1.contact = null;
m_node1.prev = null;
m_node1.next = null;
m_node1.other = null;
m_node2.contact = null;
m_node2.prev = null;
m_node2.next = null;
m_node2.other = null;
}
public Contact getNext() {
return m_next;
}
public Shape getShape1() {
return m_shape1;
}
public Shape getShape2() {
return m_shape2;
}
public void update(final ContactListener listener) {
final int oldCount = getManifoldCount();
evaluate(listener);
final int newCount = getManifoldCount();
final Body body1 = m_shape1.getBody();
final Body body2 = m_shape2.getBody();
if (newCount == 0 && oldCount > 0) {
body1.wakeUp();
body2.wakeUp();
}
// Slow contacts don't generate TOI events.
if (body1.isStatic() || body1.isBullet() || body2.isStatic() || body2.isBullet()) {
m_flags &= ~e_slowFlag;
} else {
m_flags |= e_slowFlag;
}
}
/**
* returns a clone of this contact. rev 166: not used in the engine
*/
@Override
public abstract Contact clone();
public static final void initializeRegisters() {
s_registers = new ArrayList<ContactRegister>();
Contact.addType(new CircleContact(), ShapeType.CIRCLE_SHAPE,
ShapeType.CIRCLE_SHAPE);
Contact.addType(new PolyAndCircleContact(), ShapeType.POLYGON_SHAPE,
ShapeType.CIRCLE_SHAPE);
Contact.addType(new PolyContact(), ShapeType.POLYGON_SHAPE,
ShapeType.POLYGON_SHAPE);
Contact.addType(new PolyAndEdgeContact(), ShapeType.POLYGON_SHAPE,
ShapeType.EDGE_SHAPE);
Contact.addType(new EdgeAndCircleContact(), ShapeType.EDGE_SHAPE,
ShapeType.CIRCLE_SHAPE);
Contact.addType(new PointAndCircleContact(), ShapeType.POINT_SHAPE,
ShapeType.CIRCLE_SHAPE);
Contact.addType(new PointAndPolyContact(), ShapeType.POLYGON_SHAPE,
ShapeType.POINT_SHAPE);
}
public static final void addType(final ContactCreateFcn createFcn, final ShapeType type1,
final ShapeType type2) {
final ContactRegister cr = new ContactRegister();
cr.s1 = type1;
cr.s2 = type2;
cr.createFcn = createFcn;
cr.primary = true;
s_registers.add(cr);
if (type1 != type2) {
final ContactRegister cr2 = new ContactRegister();
cr2.s2 = type1;
cr2.s1 = type2;
cr2.createFcn = createFcn;
cr2.primary = false;
s_registers.add(cr2);
}
}
/* Java note:
* This function is called "create" in C++ version.
* Doing this in Java causes problems, so leave it as is.
*/
public static final Contact createContact(final Shape shape1, final Shape shape2) {
if (s_initialized == false) {
Contact.initializeRegisters();
s_initialized = true;
}
final ShapeType type1 = shape1.m_type;
final ShapeType type2 = shape2.m_type;
// assert ShapeType.UNKNOWN_SHAPE< type1 && type1 <
// ShapeType.SHAPE_TYPE_COUNT;
// assert ShapeType.UNKNOWN_SHAPE < type2 && type2 <
// ShapeType.SHAPE_TYPE_COUNT;
final ContactRegister register = Contact.getContactRegister(type1, type2);
if (register != null) {
if (register.primary) {
return register.createFcn.create(shape1, shape2);
} else {
final Contact c = register.createFcn.create(shape2, shape1);
for (int i = 0; i < c.getManifoldCount(); ++i) {
final Manifold m = c.getManifolds().get(i);
m.normal.negateLocal();
}
return c;
}
} else {
return null;
}
}
private static final ContactRegister getContactRegister(final ShapeType type1,
final ShapeType type2) {
for (int i=0; i<s_registers.size(); ++i) {//ContactRegister cr : s_registers) {
final ContactRegister cr = s_registers.get(i);
if (cr.s1 == type1 && cr.s2 == type2) {
return cr;
}
}
return null;
}
public static final void destroy(final Contact contact) {
assert (s_initialized == true);
if (contact.getManifoldCount() > 0) {
contact.getShape1().getBody().wakeUp();
contact.getShape2().getBody().wakeUp();
}
}
}