DistanceJoint class
class DistanceJoint extends Joint { final vec2 localAnchor1; final vec2 localAnchor2; final vec2 u; num impulse; /** Effective mass for the constraint. */ num mass; num length; num frequencyHz; num dampingRatio; num gamma; num bias; DistanceJoint(DistanceJointDef def) : super(def), localAnchor1 = new vec2.copy(def.localAnchorA), localAnchor2 = new vec2.copy(def.localAnchorB), length = def.length, impulse = 0.0, u = new vec2.zero(), frequencyHz = def.frequencyHz, dampingRatio = def.dampingRatio, gamma = 0.0, bias = 0.0 { } void getAnchorA(vec2 argOut) { bodyA.getWorldPointToOut(localAnchor1, argOut); } void getAnchorB(vec2 argOut) { bodyB.getWorldPointToOut(localAnchor2, argOut); } void getReactionForce(num inv_dt, vec2 argOut) { argOut.x = impulse * u.x * inv_dt; argOut.y = impulse * u.y * inv_dt; } num getReactionTorque(num inv_dt) { return 0.0; } void initVelocityConstraints(TimeStep time_step) { final Body b1 = bodyA; final Body b2 = bodyB; vec2 r1 = new vec2.zero(); vec2 r2 = new vec2.zero(); // Compute the effective mass matrix. r1.copyFrom(localAnchor1).sub(b1.localCenter); r2.copyFrom(localAnchor2).sub(b2.localCenter); b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); u.copyFrom(b2.sweep.center).add(r2).sub(b1.sweep.center).sub(r1); // Handle singularity. num len = u.length; if (len > Settings.LINEAR_SLOP) { u.scale(1.0 / len); } else { u.splat(0.0); } num cr1u = cross(r1, u); num cr2u = cross(r2, u); num invMass = b1.invMass + b1.invInertia * cr1u * cr1u + b2.invMass + b2.invInertia * cr2u * cr2u; assert (invMass > Settings.EPSILON); mass = 1.0 / invMass; if (frequencyHz > 0.0) { num C = len - length; // Frequency num omega = MathBox.TWO_PI * frequencyHz; // Damping coefficient num d = 2.0 * mass * dampingRatio * omega; // Spring stiffness num k = mass * omega * omega; // magic formulas gamma = time_step.dt * (d + time_step.dt * k); gamma = gamma != 0.0 ? 1.0 / gamma : 0.0; bias = C * time_step.dt * k * gamma; mass = invMass + gamma; mass = mass != 0.0 ? 1.0 / mass : 0.0; } if (time_step.warmStarting) { // Scale the impulse to support a variable time time_step. impulse *= time_step.dtRatio; vec2 P = new vec2.zero(); P.copyFrom(u).scale(impulse); b1.linearVelocity.x -= b1.invMass * P.x; b1.linearVelocity.y -= b1.invMass * P.y; b1.angularVelocity -= b1.invInertia * cross(r1, P); b2.linearVelocity.x += b2.invMass * P.x; b2.linearVelocity.y += b2.invMass * P.y; b2.angularVelocity += b2.invInertia * cross(r2, P); } else { impulse = 0.0; } } void solveVelocityConstraints(TimeStep time_step) { final Body b1 = bodyA; final Body b2 = bodyB; final vec2 r1 = localAnchor1 - b1.localCenter; final vec2 r2 = localAnchor2 - b2.localCenter; b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); final v1 = cross(b1.angularVelocity, r1); final v2 = cross(b2.angularVelocity, r2); v1.add(b1.linearVelocity); v2.add(b2.linearVelocity); num Cdot = dot(u, v2.sub(v1)); num imp = -mass * (Cdot + bias + gamma * impulse); impulse += imp; num Px = imp * u.x; num Py = imp * u.y; b1.linearVelocity.x -= b1.invMass * Px; b1.linearVelocity.y -= b1.invMass * Py; b1.angularVelocity -= b1.invInertia * (r1.x * Py - r1.y * Px); b2.linearVelocity.x += b2.invMass * Px; b2.linearVelocity.y += b2.invMass * Py; b2.angularVelocity += b2.invInertia * (r2.x * Py - r2.y * Px); } bool solvePositionConstraints(num baumgarte) { if (frequencyHz > 0.0) { return true; } final b1 = bodyA; final b2 = bodyB; final vec2 r1 = localAnchor1 - b1.localCenter; final vec2 r2 = localAnchor2 - b2.localCenter; b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); final vec2 d = b2.sweep.center + r2 - (b1.sweep.center + r1); num len = d.length; d.normalize(); num C = len - length; C = clamp(C, -Settings.MAX_LINEAR_CORRECTION, Settings.MAX_LINEAR_CORRECTION); num imp = -mass * C; u.copyFrom(d); num Px = imp * u.x; num Py = imp * u.y; b1.sweep.center.x -= b1.invMass * Px; b1.sweep.center.y -= b1.invMass * Py; b1.sweep.angle -= b1.invInertia * (r1.x * Py - r1.y * Px); b2.sweep.center.x += b2.invMass * Px; b2.sweep.center.y += b2.invMass * Py; b2.sweep.angle += b2.invInertia * (r2.x * Py - r2.y * Px); b1.synchronizeTransform(); b2.synchronizeTransform(); return C.abs() < Settings.LINEAR_SLOP; } }
Extends
Joint > DistanceJoint
Constructors
new DistanceJoint(DistanceJointDef def) #
DistanceJoint(DistanceJointDef def) : super(def), localAnchor1 = new vec2.copy(def.localAnchorA), localAnchor2 = new vec2.copy(def.localAnchorB), length = def.length, impulse = 0.0, u = new vec2.zero(), frequencyHz = def.frequencyHz, dampingRatio = def.dampingRatio, gamma = 0.0, bias = 0.0 { }
Properties
final bool active #
inherited from Joint
Short-cut function to determine if either body is inactive.
bool get active => bodyA.active && bodyB.active;
num bias #
num bias
num dampingRatio #
num dampingRatio
num frequencyHz #
num frequencyHz
num gamma #
num gamma
num impulse #
num impulse
num length #
num length
num mass #
Effective mass for the constraint.
num mass
Methods
void destructor() #
inherited from Joint
Override to handle destruction of joint.
void destructor() { }
void getAnchorA(vec2 argOut) #
Get the anchor point on bodyA in world coordinates.
docs inherited from Joint
void getAnchorA(vec2 argOut) { bodyA.getWorldPointToOut(localAnchor1, argOut); }
void getAnchorB(vec2 argOut) #
Get the anchor point on bodyB in world coordinates.
docs inherited from Joint
void getAnchorB(vec2 argOut) { bodyB.getWorldPointToOut(localAnchor2, argOut); }
void getReactionForce(num inv_dt, vec2 argOut) #
Get the reaction force on body2 at the joint anchor in Newtons.
docs inherited from Joint
void getReactionForce(num inv_dt, vec2 argOut) { argOut.x = impulse * u.x * inv_dt; argOut.y = impulse * u.y * inv_dt; }
num getReactionTorque(num inv_dt) #
Get the reaction torque on body2 in N*m.
docs inherited from Joint
num getReactionTorque(num inv_dt) { return 0.0; }
void initVelocityConstraints(TimeStep time_step) #
void initVelocityConstraints(TimeStep time_step) { final Body b1 = bodyA; final Body b2 = bodyB; vec2 r1 = new vec2.zero(); vec2 r2 = new vec2.zero(); // Compute the effective mass matrix. r1.copyFrom(localAnchor1).sub(b1.localCenter); r2.copyFrom(localAnchor2).sub(b2.localCenter); b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); u.copyFrom(b2.sweep.center).add(r2).sub(b1.sweep.center).sub(r1); // Handle singularity. num len = u.length; if (len > Settings.LINEAR_SLOP) { u.scale(1.0 / len); } else { u.splat(0.0); } num cr1u = cross(r1, u); num cr2u = cross(r2, u); num invMass = b1.invMass + b1.invInertia * cr1u * cr1u + b2.invMass + b2.invInertia * cr2u * cr2u; assert (invMass > Settings.EPSILON); mass = 1.0 / invMass; if (frequencyHz > 0.0) { num C = len - length; // Frequency num omega = MathBox.TWO_PI * frequencyHz; // Damping coefficient num d = 2.0 * mass * dampingRatio * omega; // Spring stiffness num k = mass * omega * omega; // magic formulas gamma = time_step.dt * (d + time_step.dt * k); gamma = gamma != 0.0 ? 1.0 / gamma : 0.0; bias = C * time_step.dt * k * gamma; mass = invMass + gamma; mass = mass != 0.0 ? 1.0 / mass : 0.0; } if (time_step.warmStarting) { // Scale the impulse to support a variable time time_step. impulse *= time_step.dtRatio; vec2 P = new vec2.zero(); P.copyFrom(u).scale(impulse); b1.linearVelocity.x -= b1.invMass * P.x; b1.linearVelocity.y -= b1.invMass * P.y; b1.angularVelocity -= b1.invInertia * cross(r1, P); b2.linearVelocity.x += b2.invMass * P.x; b2.linearVelocity.y += b2.invMass * P.y; b2.angularVelocity += b2.invInertia * cross(r2, P); } else { impulse = 0.0; } }
bool solvePositionConstraints(num baumgarte) #
This returns true if the position errors are within tolerance.
docs inherited from Joint
bool solvePositionConstraints(num baumgarte) { if (frequencyHz > 0.0) { return true; } final b1 = bodyA; final b2 = bodyB; final vec2 r1 = localAnchor1 - b1.localCenter; final vec2 r2 = localAnchor2 - b2.localCenter; b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); final vec2 d = b2.sweep.center + r2 - (b1.sweep.center + r1); num len = d.length; d.normalize(); num C = len - length; C = clamp(C, -Settings.MAX_LINEAR_CORRECTION, Settings.MAX_LINEAR_CORRECTION); num imp = -mass * C; u.copyFrom(d); num Px = imp * u.x; num Py = imp * u.y; b1.sweep.center.x -= b1.invMass * Px; b1.sweep.center.y -= b1.invMass * Py; b1.sweep.angle -= b1.invInertia * (r1.x * Py - r1.y * Px); b2.sweep.center.x += b2.invMass * Px; b2.sweep.center.y += b2.invMass * Py; b2.sweep.angle += b2.invInertia * (r2.x * Py - r2.y * Px); b1.synchronizeTransform(); b2.synchronizeTransform(); return C.abs() < Settings.LINEAR_SLOP; }
void solveVelocityConstraints(TimeStep time_step) #
void solveVelocityConstraints(TimeStep time_step) { final Body b1 = bodyA; final Body b2 = bodyB; final vec2 r1 = localAnchor1 - b1.localCenter; final vec2 r2 = localAnchor2 - b2.localCenter; b1.originTransform.rotation.transform(r1); b2.originTransform.rotation.transform(r2); final v1 = cross(b1.angularVelocity, r1); final v2 = cross(b2.angularVelocity, r2); v1.add(b1.linearVelocity); v2.add(b2.linearVelocity); num Cdot = dot(u, v2.sub(v1)); num imp = -mass * (Cdot + bias + gamma * impulse); impulse += imp; num Px = imp * u.x; num Py = imp * u.y; b1.linearVelocity.x -= b1.invMass * Px; b1.linearVelocity.y -= b1.invMass * Py; b1.angularVelocity -= b1.invInertia * (r1.x * Py - r1.y * Px); b2.linearVelocity.x += b2.invMass * Px; b2.linearVelocity.y += b2.invMass * Py; b2.angularVelocity += b2.invInertia * (r2.x * Py - r2.y * Px); }