Dart Documentationbox2d_consoleDistanceJoint

DistanceJoint class

A distance joint constrains two points on two bodies to remain at a fixed distance from each other. You can view this as a massless, rigid rod.

class DistanceJoint extends Joint {
  final Vector localAnchor1;
  final Vector localAnchor2;
  final Vector 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 Vector.copy(def.localAnchorA),
    localAnchor2 = new Vector.copy(def.localAnchorB),
    length = def.length,
    impulse = 0.0,
    u = new Vector(),
    frequencyHz = def.frequencyHz,
    dampingRatio = def.dampingRatio,
    gamma = 0.0,
    bias = 0.0 { }

  void getAnchorA(Vector argOut) {
    bodyA.getWorldPointToOut(localAnchor1, argOut);
  }

  void getAnchorB(Vector argOut) {
    bodyB.getWorldPointToOut(localAnchor2, argOut);
  }

  void getReactionForce(num inv_dt, Vector 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 step) {
    final Body b1 = bodyA;
    final Body b2 = bodyB;

    Vector r1 = new Vector();
    Vector r2 = new Vector();

    // Compute the effective mass matrix.
    r1.setFrom(localAnchor1).subLocal(b1.localCenter);
    r2.setFrom(localAnchor2).subLocal(b2.localCenter);
    Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
    Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

    u.x = b2.sweep.center.x + r2.x - b1.sweep.center.x - r1.x;
    u.y = b2.sweep.center.y + r2.y - b1.sweep.center.y - r1.y;

    // Handle singularity.
    num len = u.length;
    if (len > Settings.LINEAR_SLOP) {
      u.x *= 1.0 / len;
      u.y *= 1.0 / len;
    } else {
      u.setCoords(0.0, 0.0);
    }

    num cr1u = Vector.crossVectors(r1, u);
    num cr2u = Vector.crossVectors(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 = step.dt * (d + step.dt * k);
      gamma = gamma != 0.0 ? 1.0 / gamma : 0.0;
      bias = C * step.dt * k * gamma;

      mass = invMass + gamma;
      mass = mass != 0.0 ? 1.0 / mass : 0.0;
    }

    if (step.warmStarting) {
      // Scale the impulse to support a variable time step.
      impulse *= step.dtRatio;

      Vector P = new Vector();
      P.setFrom(u).mulLocal(impulse);

      b1.linearVelocity.x -= b1.invMass * P.x;
      b1.linearVelocity.y -= b1.invMass * P.y;
      b1.angularVelocity -= b1.invInertia * Vector.crossVectors(r1, P);

      b2.linearVelocity.x += b2.invMass * P.x;
      b2.linearVelocity.y += b2.invMass * P.y;
      b2.angularVelocity += b2.invInertia * Vector.crossVectors(r2, P);
    } else {
      impulse = 0.0;
    }
  }

  void solveVelocityConstraints(TimeStep step) {
    final Body b1 = bodyA;
    final Body b2 = bodyB;

    final r1 = new Vector();
    final r2 = new Vector();

    r1.setFrom(localAnchor1).subLocal(b1.localCenter);
    r2.setFrom(localAnchor2).subLocal(b2.localCenter);
    Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
    Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

    final v1 = new Vector();
    final v2 = new Vector();

    Vector.crossNumAndVectorToOut(b1.angularVelocity, r1, v1);
    Vector.crossNumAndVectorToOut(b2.angularVelocity, r2, v2);
    v1.addLocal(b1.linearVelocity);
    v2.addLocal(b2.linearVelocity);

    num Cdot = Vector.dot(u, v2.subLocal(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 r1 = new Vector();
    final r2 = new Vector();
    final d = new Vector();

    r1.setFrom(localAnchor1).subLocal(b1.localCenter);
    r2.setFrom(localAnchor2).subLocal(b2.localCenter);
    Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
    Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

    d.x = b2.sweep.center.x + r2.x - b1.sweep.center.x - r1.x;
    d.y = b2.sweep.center.y + r2.y - b1.sweep.center.y - r1.y;

    num len = d.normalize();
    num C = len - length;
    C = MathBox.clamp(C, -Settings.MAX_LINEAR_CORRECTION,
        Settings.MAX_LINEAR_CORRECTION);

    num imp = -mass * C;
    u.setFrom(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 Vector.copy(def.localAnchorA),
  localAnchor2 = new Vector.copy(def.localAnchorB),
  length = def.length,
  impulse = 0.0,
  u = new Vector(),
  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() {
  return bodyA.active && bodyB.active;
}

num bias #

num bias;

Body bodyA #

inherited from Joint
Body bodyA;

Body bodyB #

inherited from Joint
Body bodyB;

bool collideConnected #

inherited from Joint
bool collideConnected;

num dampingRatio #

num dampingRatio;

JointEdge edgeA #

inherited from Joint
JointEdge edgeA;

JointEdge edgeB #

inherited from Joint
JointEdge edgeB;

num frequencyHz #

num frequencyHz;

num gamma #

num gamma;

num impulse #

num impulse;

num invIA #

inherited from Joint
num invIA;

num invIB #

inherited from Joint
num invIB;

num invMassA #

inherited from Joint
num invMassA;

num invMassB #

inherited from Joint
num invMassB;

bool islandFlag #

inherited from Joint
bool islandFlag;

num length #

num length;

final Vector localAnchor1 #

final Vector localAnchor1;

final Vector localAnchor2 #

final Vector localAnchor2;

final Vector localCenterA #

inherited from Joint
final Vector localCenterA;

final Vector localCenterB #

inherited from Joint
final Vector localCenterB;

num mass #

Effective mass for the constraint.

num mass;

final Type runtimeType #

inherited from Object

A representation of the runtime type of the object.

external Type get runtimeType;

int type #

inherited from Joint
int type;

final Vector u #

final Vector u;

Object userData #

inherited from Joint
Object userData;

Operators

bool operator ==(other) #

inherited from Object

The equality operator.

The default behavior for all Objects is to return true if and only if this and other are the same object.

If a subclass overrides the equality operator it should override the hashCode method as well to maintain consistency.

bool operator ==(other) => identical(this, other);

Methods

void destructor() #

inherited from Joint

Override to handle destruction of joint

void destructor() { }

new DistanceJoint(DistanceJointDef def) #

DistanceJoint(DistanceJointDef def) :
  super(def),
  localAnchor1 = new Vector.copy(def.localAnchorA),
  localAnchor2 = new Vector.copy(def.localAnchorB),
  length = def.length,
  impulse = 0.0,
  u = new Vector(),
  frequencyHz = def.frequencyHz,
  dampingRatio = def.dampingRatio,
  gamma = 0.0,
  bias = 0.0 { }

void getAnchorA(Vector argOut) #

Get the anchor point on bodyA in world coordinates.

docs inherited from Joint
void getAnchorA(Vector argOut) {
  bodyA.getWorldPointToOut(localAnchor1, argOut);
}

void getAnchorB(Vector argOut) #

Get the anchor point on bodyB in world coordinates.

docs inherited from Joint
void getAnchorB(Vector argOut) {
  bodyB.getWorldPointToOut(localAnchor2, argOut);
}

void getReactionForce(num inv_dt, Vector argOut) #

Get the reaction force on body2 at the joint anchor in Newtons.

docs inherited from Joint
void getReactionForce(num inv_dt, Vector 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;
}

int hashCode() #

inherited from Object

Get a hash code for this object.

All objects have hash codes. Hash codes are guaranteed to be the same for objects that are equal when compared using the equality operator ==. Other than that there are no guarantees about the hash codes. They will not be consistent between runs and there are no distribution guarantees.

If a subclass overrides hashCode it should override the equality operator as well to maintain consistency.

external int hashCode();

void initVelocityConstraints(TimeStep step) #

void initVelocityConstraints(TimeStep step) {
  final Body b1 = bodyA;
  final Body b2 = bodyB;

  Vector r1 = new Vector();
  Vector r2 = new Vector();

  // Compute the effective mass matrix.
  r1.setFrom(localAnchor1).subLocal(b1.localCenter);
  r2.setFrom(localAnchor2).subLocal(b2.localCenter);
  Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
  Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

  u.x = b2.sweep.center.x + r2.x - b1.sweep.center.x - r1.x;
  u.y = b2.sweep.center.y + r2.y - b1.sweep.center.y - r1.y;

  // Handle singularity.
  num len = u.length;
  if (len > Settings.LINEAR_SLOP) {
    u.x *= 1.0 / len;
    u.y *= 1.0 / len;
  } else {
    u.setCoords(0.0, 0.0);
  }

  num cr1u = Vector.crossVectors(r1, u);
  num cr2u = Vector.crossVectors(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 = step.dt * (d + step.dt * k);
    gamma = gamma != 0.0 ? 1.0 / gamma : 0.0;
    bias = C * step.dt * k * gamma;

    mass = invMass + gamma;
    mass = mass != 0.0 ? 1.0 / mass : 0.0;
  }

  if (step.warmStarting) {
    // Scale the impulse to support a variable time step.
    impulse *= step.dtRatio;

    Vector P = new Vector();
    P.setFrom(u).mulLocal(impulse);

    b1.linearVelocity.x -= b1.invMass * P.x;
    b1.linearVelocity.y -= b1.invMass * P.y;
    b1.angularVelocity -= b1.invInertia * Vector.crossVectors(r1, P);

    b2.linearVelocity.x += b2.invMass * P.x;
    b2.linearVelocity.y += b2.invMass * P.y;
    b2.angularVelocity += b2.invInertia * Vector.crossVectors(r2, P);
  } else {
    impulse = 0.0;
  }
}

new Joint(JointDef def) #

inherited from Joint
Joint(JointDef def) :
  type = def.type,
  _prev = null,
  _next = null,
  bodyA = def.bodyA,
  bodyB = def.bodyB,
  collideConnected = def.collideConnected,
  islandFlag = false,
  userData = def.userData,

  localCenterA = new Vector(),
  localCenterB = new Vector(),
  edgeA = new JointEdge(),
  edgeB = new JointEdge() { }

factory Joint.create(World argWorld, JointDef def) #

inherited from Joint
factory Joint.create(World argWorld, JointDef def) {
  switch(def.type){
    case JointType.MOUSE:
      throw new NotImplementedException();
      //  return new MouseJoint(def);
    case JointType.DISTANCE:
      return new DistanceJoint(def);
    case JointType.PRISMATIC:
      throw new NotImplementedException();
      //  return new PrismaticJoint(def);
    case JointType.REVOLUTE:
      return new RevoluteJoint(def);
    case JointType.WELD:
      throw new NotImplementedException();
      //return new WeldJoint(def);
    case JointType.FRICTION:
      return new FrictionJoint(def);
    case JointType.LINE:
      throw new NotImplementedException();
      //return new LineJoint(def);
    case JointType.GEAR:
      throw new NotImplementedException();
      //return new GearJoint(def);
    case JointType.PULLEY:
      throw new NotImplementedException();
      //return new PulleyJoint(def);
    case JointType.CONSTANT_VOLUME:
      return new ConstantVolumeJoint(argWorld, def);
  }
  return null;
}

noSuchMethod(String name, List args) #

inherited from Object

noSuchMethod is invoked when users invoke a non-existant method on an object. The name of the method and the arguments of the invocation are passed to noSuchMethod. If noSuchMethod returns a value, that value becomes the result of the original invocation.

The default behavior of noSuchMethod is to throw a noSuchMethodError.

external Dynamic noSuchMethod(String name, List args);

const Object() #

inherited from Object

Creates a new Object instance.

Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.

const Object();

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 r1 = new Vector();
  final r2 = new Vector();
  final d = new Vector();

  r1.setFrom(localAnchor1).subLocal(b1.localCenter);
  r2.setFrom(localAnchor2).subLocal(b2.localCenter);
  Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
  Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

  d.x = b2.sweep.center.x + r2.x - b1.sweep.center.x - r1.x;
  d.y = b2.sweep.center.y + r2.y - b1.sweep.center.y - r1.y;

  num len = d.normalize();
  num C = len - length;
  C = MathBox.clamp(C, -Settings.MAX_LINEAR_CORRECTION,
      Settings.MAX_LINEAR_CORRECTION);

  num imp = -mass * C;
  u.setFrom(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 step) #

void solveVelocityConstraints(TimeStep step) {
  final Body b1 = bodyA;
  final Body b2 = bodyB;

  final r1 = new Vector();
  final r2 = new Vector();

  r1.setFrom(localAnchor1).subLocal(b1.localCenter);
  r2.setFrom(localAnchor2).subLocal(b2.localCenter);
  Matrix22.mulMatrixAndVectorToOut(b1.originTransform.rotation, r1, r1);
  Matrix22.mulMatrixAndVectorToOut(b2.originTransform.rotation, r2, r2);

  final v1 = new Vector();
  final v2 = new Vector();

  Vector.crossNumAndVectorToOut(b1.angularVelocity, r1, v1);
  Vector.crossNumAndVectorToOut(b2.angularVelocity, r2, v2);
  v1.addLocal(b1.linearVelocity);
  v2.addLocal(b2.linearVelocity);

  num Cdot = Vector.dot(u, v2.subLocal(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);
}

String toString() #

inherited from Object

Returns a string representation of this object.

external String toString();