pathFromCubics function

Path pathFromCubics(
  1. List<CubicBezier> cubics, {
  2. double startAngle = 0.0,
  3. bool repeatPath = false,
  4. bool closePath = true,
  5. Offset rotationPivot = .zero,
  6. Path? path,
})

Returns a Path built from the given cubics.

This is the building block behind RoundedPolygon.toPath and Morph.toPath, and is useful when working with a list of curves obtained from Morph.toCubics directly.

startAngle places the start point of the first curve at that angle, in radians, around rotationPivot, rotating the whole path to get it there. Zero is to the right of the pivot and pi / 2 below it, since y grows downwards. The default of zero is special: it skips the rotation entirely and leaves the curves as given.

If repeatPath is true, the curves are added twice before the Path is closed. This is useful when the caller would like to draw parts of the path while offsetting the start and stop positions, for example when phasing and rotating a path to simulate motion as a star-shaped circular progress indicator advances.

If closePath is false, the returned Path is left open.

rotationPivot is the point startAngle rotates the path around, and the point its angle is measured from. It defaults to the origin, which suits curves laid out around Offset.zero.

Implementation

Path pathFromCubics(
  List<CubicBezier> cubics, {
  double startAngle = 0.0,
  bool repeatPath = false,
  bool closePath = true,
  Offset rotationPivot = .zero,
  Path? path,
}) {
  if (path != null) {
    path.reset();
  } else {
    path = Path();
  }

  if (cubics.isEmpty) return path;

  final firstCubic = cubics.first;
  path.moveTo(firstCubic.anchor0X, firstCubic.anchor0Y);

  for (final cubic in cubics) {
    path.cubicTo(
      cubic.control0X,
      cubic.control0Y,
      cubic.control1X,
      cubic.control1Y,
      cubic.anchor1X,
      cubic.anchor1Y,
    );
  }

  if (repeatPath) {
    path.lineTo(firstCubic.anchor0X, firstCubic.anchor0Y);
    for (final cubic in cubics) {
      path.cubicTo(
        cubic.control0X,
        cubic.control0Y,
        cubic.control1X,
        cubic.control1Y,
        cubic.anchor1X,
        cubic.anchor1Y,
      );
    }
  }

  if (closePath) path.close();

  if (startAngle != 0.0) {
    final angleToFirstCubic = math.atan2(
      firstCubic.anchor0Y - rotationPivot.dy,
      firstCubic.anchor0X - rotationPivot.dx,
    );
    // Rotate the path around the pivot so that it starts from the given angle.
    final transform = Matrix4.identity()
      ..translateByDouble(rotationPivot.dx, rotationPivot.dy, 0.0, 1.0)
      ..rotateZ(-angleToFirstCubic + startAngle)
      ..translateByDouble(-rotationPivot.dx, -rotationPivot.dy, 0.0, 1.0);
    path = path.transform(transform.storage);
  }

  return path;
}