Published
Edited
Mar 23, 2019
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function getEndpointParameters(cx, cy, rx, ry, phi, theta, dTheta) {
const [x1, y1] = getEllipsePointForAngle(cx, cy, rx, ry, phi, theta);
const [x2, y2] = getEllipsePointForAngle(cx, cy, rx, ry, phi, theta + dTheta);
const fa = Math.abs(dTheta) > Math.PI ? 1 : 0;
const fs = dTheta > 0 ? 1 : 0;
return { x1, y1, x2, y2, fa, fs }
}
Insert cell
function getEllipsePointForAngle(cx, cy, rx, ry, phi, theta) {
const { abs, sin, cos } = Math;
const M = abs(rx) * cos(theta),
N = abs(ry) * sin(theta);
return [
cx + cos(phi) * M - sin(phi) * N,
cy + sin(phi) * M + cos(phi) * N
];
}
Insert cell
function getCenterParameters(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
const { abs, sin, cos, sqrt } = Math;
const pow = n => Math.pow(n, 2);
const sinphi = sin(phi), cosphi = cos(phi);
// Step 1: simplify through translation/rotation
const x = cosphi * (x1 - x2) / 2 + sinphi * (y1 - y2) / 2,
y = -sinphi * (x1 - x2) / 2 + cosphi * (y1 - y2) / 2;
const px = pow(x), py = pow(y), prx = pow(rx), pry = pow(ry);
// correct of out-of-range radii
const L = px / prx + py / pry;
if (L > 1) {
rx = sqrt(L) * abs(rx);
ry = sqrt(L) * abs(ry);
} else {
rx = abs(rx);
ry = abs(ry);
}

// Step 2 + 3: compute center
const sign = fa === fs ? -1 : 1;
const M = sqrt((prx * pry - prx * py - pry * px) / (prx * py + pry * px)) * sign;

const _cx = M * (rx * y) / ry,
_cy = M * (-ry * x) / rx;

const cx = cosphi * _cx - sinphi * _cy + (x1 + x2) / 2,
cy = sinphi * _cx + cosphi * _cy + (y1 + y2) / 2;

// Step 4: compute θ and dθ
const theta = vectorAngle(
[1, 0],
[(x - _cx) / rx, (y - _cy) / ry]
);

let _dTheta = deg(vectorAngle(
[(x - _cx) / rx, (y - _cy) / ry],
[(-x - _cx) / rx, (-y - _cy) / ry]
)) % 360;

if (fs === 0 && _dTheta > 0) _dTheta -= 360;
if (fs === 1 && _dTheta < 0) _dTheta += 360;
return { cx, cy, theta, dTheta: rad(_dTheta) };
}
Insert cell
function vectorAngle ([ux, uy], [vx, vy]) {
const { acos, sqrt } = Math;
const sign = ux * vy - uy * vx < 0 ? -1 : 1,
ua = sqrt(ux * ux + uy * uy),
va = sqrt(vx * vx + vy * vy),
dot = ux * vx + uy * vy;

return sign * acos(dot / (ua * va));
};
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more