buildPlan function

MorphPlan buildPlan(
  1. List<Sampled> srcSubs,
  2. List<Sampled> dstSubs
)

Builds the morph plan between two lists of sampled subpaths. The plan is cacheable; it accepts any list — including intermediate shapes (interruptions).

Implementation

MorphPlan buildPlan(List<Sampled> srcSubs, List<Sampled> dstSubs) {
  final p = srcSubs.length;
  final q = dstSubs.length;
  if (p == 0 || q == 0) morphFail('icon has no subpaths');
  final a = srcSubs.map((s) => s.pts).toList();
  final b = dstSubs.map((s) => s.pts).toList();
  // Undocumented precondition of the TypeScript, made explicit here: n comes
  // from the first source subpath and every subpath on both sides is assumed
  // to have been sampled at the same N.
  assert(
    a.every((x) => x.length == a[0].length) &&
        b.every((x) => x.length == a[0].length),
    'all subpaths must be sampled at the same N',
  );
  final pairs = <(int, int)>[];
  if (p == q) {
    final perm = _bestPermutation(_costMatrix(a, b));
    for (var i = 0; i < p; i++) {
      pairs.add((i, perm[i]));
    }
  } else if (p < q) {
    final f = _bestSurjection(_costMatrix(b, a));
    for (var j = 0; j < q; j++) {
      pairs.add((f[j], j));
    }
  } else {
    final f = _bestSurjection(_costMatrix(a, b));
    for (var i = 0; i < p; i++) {
      pairs.add((i, f[i]));
    }
  }
  final n = a[0].length ~/ 2;
  final items = pairs.map((pair) {
    final (si, di) = pair;
    final al = alignPair(a[si], b[di], srcSubs[si].closed, dstSubs[di].closed);
    final ap = al.a;
    final aC = Float64List(2 * n);
    final bT = Float64List(2 * n);
    final bO = Float64List(2 * n);
    final cos = math.cos(-al.theta);
    final sin = math.sin(-al.theta);
    for (var i = 0; i < n; i++) {
      aC[2 * i] = ap[2 * i] - al.ca.$1;
      aC[2 * i + 1] = ap[2 * i + 1] - al.ca.$2;
      final bx = al.b[2 * i] - al.cb.$1;
      final by = al.b[2 * i + 1] - al.cb.$2;
      bT[2 * i] = (bx * cos - by * sin) / al.sigma;
      bT[2 * i + 1] = (bx * sin + by * cos) / al.sigma;
      bO[2 * i] = al.b[2 * i];
      bO[2 * i + 1] = al.b[2 * i + 1];
    }
    return PlanItem(
      a: ap,
      aC: aC,
      bT: bT,
      bO: bO,
      ca: al.ca,
      cb: al.cb,
      theta: al.theta,
      lnSigma: math.log(al.sigma),
      res: al.res,
      closed: srcSubs[si].closed && dstSubs[di].closed,
      block: null,
    );
  }).toList();
  if (items.length > 1) _applyGlobal(items, n);
  return MorphPlan(items, n);
}