ellipticalArcToCubicBezier function

List<Vector3> ellipticalArcToCubicBezier(
  1. Vector3 v1,
  2. double rx,
  3. double ry,
  4. double phi,
  5. double fA,
  6. double fS,
  7. Vector3 v2,
)

Implementation

List<Vector3> ellipticalArcToCubicBezier(Vector3 v1, double rx, double ry,
    double phi, double fA, double fS, Vector3 v2) {
  var x1 = v1.x;
  var y1 = v1.y;
  var x2 = v2.x;
  var y2 = v2.y;

  if (rx == 0 || ry == 0) {
    return [v1, v2, v2];
  }

  phi *= DEGREES; // convert to radians

  fA = fA != 0 ? 1 : 0;
  fS = fS != 0 ? 1 : 0;

  var params =
      getEllipticalArcCenterParameters(x1, y1, rx, ry, phi, fA, fS, x2, y2);
  var cx = params[0];
  var cy = params[1];
  var theta1 = params[2];
  var dtheta = params[3];

  var sweepLimit = (dtheta / DEGREES) % 90 == 0 ? 90 : 36;

  var segments = ((dtheta / DEGREES) / sweepLimit).abs().ceil();
  var segment = dtheta / segments;
  var currentAngle = theta1;
  var startX = x1;
  var startY = y1;
  var cosPhi = cos(phi);
  var sinPhi = sin(phi);
  var alpha = sin(segment) * (sqrt(4 + 3 * pow(tan(segment / 2), 2)) - 1) / 3;
  var bezierPoints = <Vector3>[];

  for (var idx in range(end: segments)) {
    var nextAngle = currentAngle + segment;

    var cosStart = cos(currentAngle);
    var sinStart = sin(currentAngle);

    var e1x = -rx * cosPhi * sinStart - ry * sinPhi * cosStart;
    var e1y = -rx * sinPhi * sinStart + ry * cosPhi * cosStart;

    var q1x = startX + alpha * e1x;
    var q1y = startY + alpha * e1y;

    var cosEnd = cos(nextAngle);
    var sinEnd = sin(nextAngle);

    var p2x = cx + rx * cosPhi * cosEnd - ry * sinPhi * sinEnd;
    var p2y = cy + rx * sinPhi * cosEnd + ry * cosPhi * sinEnd;

    var endX = p2x;
    var endY = p2y;

    if (idx == segments - 1) {
      endX = x2;
      endY = y2;
    }
    var e2x = -rx * cosPhi * sinEnd - ry * sinPhi * cosEnd;
    var e2y = -rx * sinPhi * sinEnd + ry * cosPhi * cosEnd;
    var q2X = endX - alpha * e2x;
    var q2Y = endY - alpha * e2y;

    bezierPoints.addAll([
      Vector3(q1x, q1y, 0),
      Vector3(q2X, q2Y, 0),
      Vector3(endX, endY, 0),
    ]);
    startX = endX;
    startY = endY;
    currentAngle = nextAngle;
  }

  return bezierPoints;
}