package org.codecranachan.asteroidpush.base.simulation.jbox2d;
import java.util.HashMap;
import java.util.Map;
import org.codecranachan.asteroidpush.base.simulation.DynamicJointFactory;
import org.codecranachan.asteroidpush.base.simulation.Hull;
import org.codecranachan.asteroidpush.base.simulation.InteractionHandler;
import org.codecranachan.asteroidpush.base.simulation.Material;
import org.codecranachan.asteroidpush.base.simulation.RigidBody;
import org.codecranachan.asteroidpush.utils.Angle;
import org.codecranachan.asteroidpush.utils.Circle;
import org.codecranachan.asteroidpush.utils.Force;
import org.codecranachan.asteroidpush.utils.GeometryConverter;
import org.codecranachan.asteroidpush.utils.NewtonianState;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.Fixture;
public class Box2dBody implements RigidBody {
private World world;
private Body body;
private Map<Hull, Fixture> fixtureMap;
public Box2dBody(World world, BodyDef bodyDefinition) {
assert world != null;
assert bodyDefinition != null;
this.world = world;
this.fixtureMap = new HashMap<Hull, Fixture>();
body = this.world.createBody(bodyDefinition);
}
public void destroy() {
assert body != null;
fixtureMap.clear();
world.destroyBody(body);
body = null;
}
public Body getBox2dBody() {
return body;
}
public RigidBody shallowClone() {
BodyDef def = new BodyDef();
def.type = body.getType();
def.active = body.isActive();
def.angularDamping = body.getAngularDamping();
def.linearDamping = body.getLinearDamping();
def.fixedRotation = body.isFixedRotation();
def.position.set(body.getPosition());
def.angle = body.getAngle();
def.angularVelocity = body.getAngularVelocity();
def.linearVelocity = body.getLinearVelocity();
return new Box2dBody(world, def);
}
public NewtonianState getState() {
assert body != null;
NewtonianState state = new NewtonianState();
state.setState(body.getPosition(), Angle.fromRad(body.getAngle()));
state.setVelocity(body.getLinearVelocity(),
Angle.fromRad(body.getAngularVelocity()));
return state;
}
public void addHull(Hull hull, InteractionHandler handler) {
FixtureDef def = new FixtureDef();
def.shape = ConvertToShape(hull);
def.userData = handler;
setMaterial(def, hull.getMaterial());
Fixture fix = body.createFixture(def);
fixtureMap.put(hull, fix);
// TODO attach interaction handler somewhere
}
public void removeHull(Hull primitive) {
assert (fixtureMap.containsKey(primitive));
body.destroyFixture(fixtureMap.get(primitive));
fixtureMap.remove(primitive);
}
public void applyTorque(float torque) {
body.applyTorque(torque);
}
private Shape ConvertToShape(Hull hull) {
Shape shape = GeometryConverter.convertToBox2dShape(hull.getShape(),
hull.getOffset());
return shape;
}
private void setMaterial(FixtureDef def, Material material) {
def.density = material.density;
def.friction = material.friction;
def.restitution = material.restitution;
}
public void applyForce(Force force) {
Force transformed = transformToWorld(force);
body.applyForce(transformed.getForce(), transformed.getOffset());
}
public Force transformToWorld(Force force) {
Vec2 point = body.getWorldPoint(force.getOffset());
Vec2 vector = body.getWorldVector(force.getForce());
return new Force(point, vector);
}
public Circle getEnclosingCircle() {
// TODO: calculate correct radius of circle
return new Circle(body.getWorldCenter(), 10f);
}
public NewtonianState transformToWorld(NewtonianState state) {
NewtonianState transformed = new NewtonianState();
transformed.setState(body.getWorldPoint(state.getPosition()), Angle
.fromRad(body.getAngle()).add(state.getRotation()));
Vec2 linVel = body.getWorldVector(state.getLinearVelocity())
.add(body.getLinearVelocity());
Angle angVel = Angle.fromRad(body.getAngularVelocity())
.add(state.getAngularVelocity());
transformed.setVelocity(linVel, angVel);
return transformed;
}
public DynamicJointFactory getJointFactory() {
return new Box2dJointFactory(world);
}
}