solve method

  1. @override
int solve(
  1. double dt,
  2. World world
)
override

Solve @return number of iterations performed

Implementation

@override
int solve(double dt, World world) {
  int iter = 0;
  final int maxIter = iterations;
  final double tolSquared = tolerance * tolerance;
  final equations = this.equations;
  final int nEq = equations.length;
  final bodies = world.bodies;
  final int nBodies = bodies.length;
  final double h = dt;

  double? B;
  double? invC;
  double deltalambda;
  double deltalambdaTot;
  double gwlambda;
  double? lambdaj;

  // Update solve mass
  if (nEq != 0) {
    for (int i = 0; i != nBodies; i++) {
      bodies[i].updateSolveMassProperties();
    }
  }

  // Things that do not change during iteration can be computed once
  List<double?> invCs = gsSolverSolveInvCs;
  List<double?> bs = gsSolverSolveBs;
  List<double?> lambda = gsSolverSolveLambda;
  invCs.length = nEq;
  bs.length = nEq;
  lambda.length = nEq;
  for (int i = 0; i != nEq; i++) {
    final c = equations[i];
    lambda[i] = 0.0;
    bs[i] = c.computeB(h);
    invCs[i] = 1.0 / c.computeC();
  }

  if (nEq != 0) {
    // Reset vlambda
    for (int i = 0; i != nBodies; i++) {
      final b = bodies[i];
      final vlambda = b.vlambda;
      final wlambda = b.wlambda;
      vlambda.set(0, 0, 0);
      wlambda.set(0, 0, 0);
    }

    // Iterate over equations
    for (iter = 0; iter != maxIter; iter++) {
      // Accumulate the total error for each iteration.
      deltalambdaTot = 0.0;

      for (int j = 0; j != nEq; j++) {
        final c = equations[j];

        // Compute iteration
        B = bs[j];
        invC = invCs[j];
        lambdaj = lambda[j];
        if(B == null || invC == null || lambdaj == null || lambda[j] == null) break;
        gwlambda = c.computeGWlambda();
        deltalambda = invC * (B - gwlambda - c.eps * lambdaj);

        // Clamp if we are not within the min/max interval
        if (lambdaj + deltalambda < c.minForce) {
          deltalambda = c.minForce - lambdaj;
        } else if (lambdaj + deltalambda > c.maxForce) {
          deltalambda = c.maxForce - lambdaj;
        }
        lambda[j] = lambda[j]!+deltalambda;

        deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)

        c.addToWlambda(deltalambda);
      }

      // If the total error is small enough - stop iterate
      if (deltalambdaTot * deltalambdaTot < tolSquared) {
        break;
      }
    }

    // Add result to velocity
    for (int i = 0; i != nBodies; i++) {
      final b = bodies[i];
      final v = b.velocity;
      final w = b.angularVelocity;

      b.vlambda.vmul(b.linearFactor, b.vlambda);
      v.vadd(b.vlambda, v);

      b.wlambda.vmul(b.angularFactor, b.wlambda);
      w.vadd(b.wlambda, w);
    }

    // Set the `.multiplier` property of each equation
    int l = equations.length-1;
    double invDt = 1 / h;
    while(l > -1) {
      equations[l].multiplier = lambda[l]! * invDt;
      l--;
    }
  }

  return iter;
}