Cubic.circularArc constructor

Cubic.circularArc(
  1. double centerX,
  2. double centerY,
  3. double x0,
  4. double y0,
  5. double x1,
  6. double y1,
)

Generates a bezier curve that approximates a circular arc, with p0 and p1 as the starting and ending anchor points. The curve generated is the smallest of the two possible arcs around the entire 360-degree circle. Arcs of greater than 180 degrees should use more than one arc together. Note that p0 and p1 should be equidistant from the center.

Implementation

// TODO: consider a more general function (maybe in addition to this) that
// allows caller to get a list of curves surpassing 180 degrees.
factory Cubic.circularArc(
  double centerX,
  double centerY,
  double x0,
  double y0,
  double x1,
  double y1,
) {
  final p0d = directionVector(x0 - centerX, y0 - centerY);
  final p1d = directionVector(x1 - centerX, y1 - centerY);
  final rotatedP0 = p0d.rotate90();
  final rotatedP1 = p1d.rotate90();
  final clockwise = rotatedP0.dotProductXY(x1 - centerX, y1 - centerY) >= 0;
  final cosa = p0d.dotProduct(p1d);

  // p0 ~= p1
  if (cosa > 0.999) {
    return Cubic.straightLine(x0, y0, x1, y1);
  }

  final k = distance(x0 - centerX, y0 - centerY) *
      4 /
      3 *
      (math.sqrt(2 * (1 - cosa)) - math.sqrt(1 - cosa * cosa)) /
      (1 - cosa) *
      (clockwise ? 1 : -1);

  return Cubic(
    x0,
    y0,
    x0 + rotatedP0.x * k,
    y0 + rotatedP0.y * k,
    x1 - rotatedP1.x * k,
    y1 - rotatedP1.y * k,
    x1,
    y1,
  );
}