ellipticalArcToCubicBezier function
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;
}