solve2 method

void solve2(
  1. BoneChain fk1,
  2. BoneChain fk2,
  3. Vec2D worldTargetTranslation
)

Implementation

void solve2(BoneChain fk1, BoneChain fk2, Vec2D worldTargetTranslation) {
  ActorBone b1 = fk1.bone;
  ActorBone b2 = fk2.bone;
  BoneChain firstChild = _fkChain[fk1.index + 1];

  Mat2D iworld = fk1.parentWorldInverse;

  Vec2D pA = b1.getWorldTranslation(Vec2D());
  Vec2D pC = firstChild.bone.getWorldTranslation(Vec2D());
  Vec2D pB = b2.getTipWorldTranslation(Vec2D());

  Vec2D pBT = Vec2D.clone(worldTargetTranslation);

  pA = Vec2D.transformMat2D(pA, pA, iworld);
  pC = Vec2D.transformMat2D(pC, pC, iworld);
  pB = Vec2D.transformMat2D(pB, pB, iworld);
  pBT = Vec2D.transformMat2D(pBT, pBT, iworld);

  // http://mathworld.wolfram.com/LawofCosines.html
  Vec2D av = Vec2D.subtract(Vec2D(), pB, pC);
  double a = Vec2D.length(av);

  Vec2D bv = Vec2D.subtract(Vec2D(), pC, pA);
  double b = Vec2D.length(bv);

  Vec2D cv = Vec2D.subtract(Vec2D(), pBT, pA);
  double c = Vec2D.length(cv);

  double A = acos(max(-1, min(1, (-a * a + b * b + c * c) / (2 * b * c))));
  double C = acos(max(-1, min(1, (a * a + b * b - c * c) / (2 * a * b))));

  double r1, r2;
  if (b2.parent != b1) {
    BoneChain secondChild = _fkChain[fk1.index + 2];

    Mat2D secondChildWorldInverse = secondChild.parentWorldInverse;

    pC = firstChild.bone.getWorldTranslation(Vec2D());
    pB = b2.getTipWorldTranslation(Vec2D());

    Vec2D avec = Vec2D.subtract(Vec2D(), pB, pC);
    Vec2D avLocal =
        Vec2D.transformMat2(Vec2D(), avec, secondChildWorldInverse);
    double angleCorrection = -atan2(avLocal[1], avLocal[0]);

    if (_invertDirection) {
      r1 = atan2(cv[1], cv[0]) - A;
      r2 = -C + pi + angleCorrection;
    } else {
      r1 = A + atan2(cv[1], cv[0]);
      r2 = C - pi + angleCorrection;
    }
  } else if (_invertDirection) {
    r1 = atan2(cv[1], cv[0]) - A;
    r2 = -C + pi;
  } else {
    r1 = A + atan2(cv[1], cv[0]);
    r2 = C - pi;
  }

  constrainRotation(fk1, r1);
  constrainRotation(firstChild, r2);
  if (firstChild != fk2) {
    ActorBone bone = fk2.bone;
    Mat2D.multiply(
        bone.worldTransform, bone.parent!.worldTransform, bone.transform);
  }

  // Simple storage, need this for interpolation.
  fk1.angle = r1;
  firstChild.angle = r2;
}