buildPlan function

MeldPlan buildPlan(
  1. List<SampledPath> source,
  2. List<SampledPath> target, {
  3. bool cacheHit = false,
})

Implementation

MeldPlan buildPlan(List<SampledPath> source, List<SampledPath> target,
    {bool cacheHit = false}) {
  final stopwatch = Stopwatch()..start();
  if (source.isEmpty || target.isEmpty)
    throw MeldException(
        'empty-icon', 'Both icons must contain at least one subpath.');
  final sampleCount = source.first.pointCount;
  if (source.any((path) => path.pointCount != sampleCount) ||
      target.any((path) => path.pointCount != sampleCount)) {
    throw MeldException('sample-count-mismatch',
        'All source and target subpaths must use the same sample count.');
  }
  final a = source.map((path) => path.points).toList(growable: false);
  final b = target.map((path) => path.points).toList(growable: false);
  final pairs = <(int, int)>[];
  if (a.length == b.length) {
    final permutation = _bestPermutation(_costMatrix(a, b));
    for (var i = 0; i < a.length; i++) {
      pairs.add((i, permutation[i]));
    }
  } else if (a.length < b.length) {
    final assignment = _bestSurjection(_costMatrix(b, a));
    for (var j = 0; j < b.length; j++) {
      pairs.add((assignment[j], j));
    }
  } else {
    final assignment = _bestSurjection(_costMatrix(a, b));
    for (var i = 0; i < a.length; i++) {
      pairs.add((i, assignment[i]));
    }
  }
  final items = <MeldPlanItem>[];
  for (final pair in pairs) {
    final alignment = alignPair(
      a[pair.$1],
      b[pair.$2],
      closedA: source[pair.$1].closed,
      closedB: target[pair.$2].closed,
    );
    final centeredA = Float64List(sampleCount * 2);
    final transformedB = Float64List(sampleCount * 2);
    final orientedB = Float64List(sampleCount * 2);
    final cos = math.cos(-alignment.theta);
    final sin = math.sin(-alignment.theta);
    for (var i = 0; i < sampleCount; i++) {
      centeredA[i * 2] = alignment.a[i * 2] - alignment.centerA.$1;
      centeredA[i * 2 + 1] = alignment.a[i * 2 + 1] - alignment.centerA.$2;
      final bx = alignment.b[i * 2] - alignment.centerB.$1;
      final by = alignment.b[i * 2 + 1] - alignment.centerB.$2;
      transformedB[i * 2] = (bx * cos - by * sin) / alignment.scale;
      transformedB[i * 2 + 1] = (bx * sin + by * cos) / alignment.scale;
      orientedB[i * 2] = alignment.b[i * 2];
      orientedB[i * 2 + 1] = alignment.b[i * 2 + 1];
    }
    items.add(
      MeldPlanItem(
        a: alignment.a,
        centeredA: centeredA,
        transformedB: transformedB,
        orientedB: orientedB,
        centerA: alignment.centerA,
        centerB: alignment.centerB,
        theta: alignment.theta,
        logScale: math.log(alignment.scale),
        residual: alignment.residual,
        closed: source[pair.$1].closed && target[pair.$2].closed,
        sourceIndex: pair.$1,
        targetIndex: pair.$2,
      ),
    );
  }
  final plannedItems = items.length > 1
      ? _applyGlobal(items, sampleCount)
      : List<MeldPlanItem>.unmodifiable(items);
  stopwatch.stop();
  final residuals = plannedItems.map((item) => item.residual);
  final diagnostics = PlanDiagnostics(
    sourceSubpaths: source.length,
    targetSubpaths: target.length,
    sampleCount: sampleCount,
    meanResidual:
        residuals.fold<double>(0, (sum, value) => sum + value) / items.length,
    maxResidual: residuals.fold<double>(0, math.max),
    usedGlobalBlock: plannedItems.any((item) => item.block != null),
    elapsedMicros: stopwatch.elapsedMicroseconds,
    cacheHit: cacheHit,
  );
  return MeldPlan(
      items: plannedItems, sampleCount: sampleCount, diagnostics: diagnostics);
}