/**
* Copyright 2013 The Loon Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package loon.physics;
import loon.geom.Vector2f;
public class PRodJoint extends PJoint {
private Vector2f anchor1;
private Vector2f anchor2;
private PBody b1;
private PBody b2;
private float dist;
private float length;
private Vector2f localAnchor1;
private Vector2f localAnchor2;
private float mass;
private float norI;
private Vector2f normal;
private Vector2f relAnchor1;
private Vector2f relAnchor2;
public PRodJoint(PBody b1, PBody b2, float rel1x, float rel1y, float rel2x,
float rel2y, float distance) {
this.b1 = b1;
this.b2 = b2;
localAnchor1 = new Vector2f(rel1x, rel1y);
localAnchor2 = new Vector2f(rel2x, rel2y);
b1.mAng.transpose().mulEqual(localAnchor1);
b2.mAng.transpose().mulEqual(localAnchor2);
dist = distance;
anchor1 = b1.mAng.mul(localAnchor1).add(b1.pos);
anchor2 = b2.mAng.mul(localAnchor2).add(b2.pos);
normal = anchor1.sub(anchor2);
normal.normalize();
type = PJointType.ROD_JOINT;
}
public Vector2f getAnchorPoint1() {
return anchor1.cpy();
}
public Vector2f getAnchorPoint2() {
return anchor2.cpy();
}
public PBody getBody1() {
return b1;
}
public PBody getBody2() {
return b2;
}
public float getDistance() {
return dist;
}
public Vector2f getRelativeAnchorPoint1() {
return relAnchor1.cpy();
}
public Vector2f getRelativeAnchorPoint2() {
return relAnchor2.cpy();
}
private float max(float v, float max) {
return v <= max ? max : v;
}
private float min(float v, float min) {
return v >= min ? min : v;
}
void preSolve(float dt) {
relAnchor1 = b1.mAng.mul(localAnchor1);
relAnchor2 = b2.mAng.mul(localAnchor2);
anchor1.set(relAnchor1.x + b1.pos.x, relAnchor1.y + b1.pos.y);
anchor2.set(relAnchor2.x + b2.pos.x, relAnchor2.y + b2.pos.y);
normal = anchor2.sub(anchor1);
length = normal.length();
normal.normalize();
mass = PTransformer.calcEffectiveMass(b1, b2, relAnchor1, relAnchor2,
normal);
b1.applyImpulse(normal.x * norI, normal.y * norI, anchor1.x, anchor1.y);
b2.applyImpulse(normal.x * -norI, normal.y * -norI, anchor2.x,
anchor2.y);
}
public void setDistance(float distance) {
dist = distance;
}
public void setRelativeAnchorPoint1(float relx, float rely) {
localAnchor1.set(relx, rely);
b1.mAng.transpose().mulEqual(localAnchor1);
}
public void setRelativeAnchorPoint2(float relx, float rely) {
localAnchor2.set(relx, rely);
b2.mAng.transpose().mulEqual(localAnchor2);
}
void solvePosition() {
float rvn = normal.dot(PTransformer.calcRelativeCorrectVelocity(b1, b2,
relAnchor1, relAnchor2));
float impulse = -mass * ((dist - length) + rvn) * 0.2F;
if (impulse > 0.0F)
impulse = max(impulse - 0.002F, 0.0F);
else if (impulse < 0.0F)
impulse = min(impulse + 0.002F, 0.0F);
float forceX = normal.x * impulse;
float forceY = normal.y * impulse;
b1.positionCorrection(forceX, forceY, anchor1.x, anchor1.y);
b2.positionCorrection(-forceX, -forceY, anchor2.x, anchor2.y);
}
void solveVelocity(float dt) {
float rn = normal.dot(PTransformer.calcRelativeVelocity(b1, b2,
relAnchor1, relAnchor2));
float impulse = -mass * rn;
norI += impulse;
float forceX = normal.x * impulse;
float forceY = normal.y * impulse;
b1.applyImpulse(forceX, forceY, anchor1.x, anchor1.y);
b2.applyImpulse(-forceX, -forceY, anchor2.x, anchor2.y);
}
void update() {
relAnchor1 = b1.mAng.mul(localAnchor1);
relAnchor2 = b2.mAng.mul(localAnchor2);
anchor1.set(relAnchor1.x + b1.pos.x, relAnchor1.y + b1.pos.y);
anchor2.set(relAnchor2.x + b2.pos.x, relAnchor2.y + b2.pos.y);
if (b1.rem || b2.rem || b1.fix && b2.fix) {
rem = true;
}
}
}