retarget method

ExpressiveShapeGeometry retarget(
  1. MaterialExpressiveShape target, {
  2. required double progress,
})

Redirect from the current outline, not the previous target. Settled endpoints keep their original polygon features. An interrupted frame has no catalog corner metadata: preserve its exact cubics as ignorable edge features and let Morph use its perimeter-based fallback correspondence. This preserves position, not animation velocity. It neither samples nor normalizes the outline and retains no chain of previous animations.

For interrupted transitions only the new destination's interior is used: the snapshot is a transient frame and is NOT certified content-safe.

Implementation

ExpressiveShapeGeometry retarget(
  MaterialExpressiveShape target, {
  required double progress,
}) {
  _validateProgress(progress);
  if (progress == 1 || _morph == null) {
    return ExpressiveShapeGeometry(from: to, to: target);
  }
  if (progress == 0 && _snapshot == null) {
    return ExpressiveShapeGeometry(from: from, to: target);
  }
  final cubics = _morph.toCubics(progress);
  // Morph's matching tolerances can leave tiny gaps after repeated cuts.
  // Match Path.cubicTo's behavior: each segment starts at the previous end,
  // not its independently stored anchor0. This keeps the captured path closed.
  final connected = [
    for (var i = 0; i < cubics.length; i++)
      CubicBezier(
        cubics[(i + cubics.length - 1) % cubics.length].anchor1,
        cubics[i].control0,
        cubics[i].control1,
        cubics[i].anchor1,
      ),
  ];
  return ExpressiveShapeGeometry._retarget(
    to: target,
    snapshot: RoundedPolygon.fromFeatures(
      connected.map(PolygonFeature.edge).toList(),
    ),
    snapshotCenter:
        _morph.toPath(progress).getBounds().center -
        _startCorrection * (1 - progress),
  );
}