parseArcCommand method

dynamic parseArcCommand(
  1. dynamic path,
  2. dynamic rx,
  3. dynamic ry,
  4. dynamic xAxisRotation,
  5. dynamic largeArcFlag,
  6. dynamic sweepFlag,
  7. dynamic start,
  8. dynamic end,
)

Implementation

parseArcCommand(
    path, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, start, end) {
  if (rx == 0 || ry == 0) {
    // draw a line if either of the radii == 0
    path.lineTo(end.x, end.y);
    return;
  }

  xAxisRotation = xAxisRotation * Math.PI / 180;

  // Ensure radii are positive
  rx = Math.abs(rx);
  ry = Math.abs(ry);

  // Compute (x1', y1')
  var dx2 = (start.x - end.x) / 2.0;
  var dy2 = (start.y - end.y) / 2.0;
  var x1p = Math.cos(xAxisRotation) * dx2 + Math.sin(xAxisRotation) * dy2;
  var y1p = -Math.sin(xAxisRotation) * dx2 + Math.cos(xAxisRotation) * dy2;

  // Compute (cx', cy')
  var rxs = rx * rx;
  var rys = ry * ry;
  var x1ps = x1p * x1p;
  var y1ps = y1p * y1p;

  // Ensure radii are large enough
  var cr = x1ps / rxs + y1ps / rys;

  if (cr > 1) {
    // scale up rx,ry equally so cr == 1
    var s = Math.sqrt(cr);
    rx = s * rx;
    ry = s * ry;
    rxs = rx * rx;
    rys = ry * ry;
  }

  var dq = (rxs * y1ps + rys * x1ps);
  var pq = (rxs * rys - dq) / dq;
  var q = Math.sqrt(Math.max(0, pq));
  if (largeArcFlag == sweepFlag) q = -q;
  var cxp = q * rx * y1p / ry;
  var cyp = -q * ry * x1p / rx;

  // Step 3: Compute (cx, cy) from (cx', cy')
  var cx = Math.cos(xAxisRotation) * cxp -
      Math.sin(xAxisRotation) * cyp +
      (start.x + end.x) / 2;
  var cy = Math.sin(xAxisRotation) * cxp +
      Math.cos(xAxisRotation) * cyp +
      (start.y + end.y) / 2;

  // Step 4: Compute θ1 and Δθ
  var theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
  var delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx,
          (-y1p - cyp) / ry) %
      (Math.PI * 2);

  path.currentPath.absellipse(
      cx, cy, rx, ry, theta, theta + delta, sweepFlag == 0, xAxisRotation);
}