@thi.ng/geom-arc
Version:
2D circular / elliptic arc operations
61 lines (60 loc) • 1.83 kB
JavaScript
import { EPS, TAU } from "@thi.ng/math/api";
import { abs2 } from "@thi.ng/vectors/abs";
import { angleBetween2 } from "@thi.ng/vectors/angle-between";
import { X2 } from "@thi.ng/vectors/api";
import { div2 } from "@thi.ng/vectors/div";
import { eqDelta2 } from "@thi.ng/vectors/eqdelta";
import { mulN2 } from "@thi.ng/vectors/muln";
import { neg } from "@thi.ng/vectors/neg";
import { powN2 } from "@thi.ng/vectors/pown";
import { sub2 } from "@thi.ng/vectors/sub";
import { submN2 } from "@thi.ng/vectors/submn";
const fromEndPoints = (a, b, radii, axis = 0, xl = false, cw = false) => {
const r = abs2([], radii);
if (eqDelta2(a, b) || r[0] < EPS || r[1] < EPS) {
return;
}
axis %= TAU;
const d = submN2([], a, b, 0.5);
const c = Math.cos(axis);
const s = Math.sin(axis);
const tp = [c * d[0] + s * d[1], -s * d[0] + c * d[1]];
const [tx2, ty2] = powN2([], tp, 2);
const rc = tx2 / (r[0] * r[0]) + ty2 / (r[1] * r[1]);
rc > 1 && mulN2(r, r, Math.sqrt(rc));
const [rx, ry] = r;
const rx2 = rx * rx;
const ry2 = ry * ry;
const radicant = Math.max(
0,
(rx2 * ry2 - rx2 * ty2 - ry2 * tx2) / (rx2 * ty2 + ry2 * tx2)
);
const coeff = (xl !== cw ? 1 : -1) * Math.sqrt(radicant);
const tc = [coeff * (rx * tp[1] / ry), coeff * (-(ry * tp[0]) / rx)];
const center = [
c * tc[0] - s * tc[1] + (a[0] + b[0]) / 2,
s * tc[0] + c * tc[1] + (a[1] + b[1]) / 2
];
const ta = div2(null, sub2([], tp, tc), r);
const tb = div2(null, sub2(null, neg([], tp), tc), r);
const start = angleBetween2(X2, ta);
let sweep = angleBetween2(ta, tb);
if (!cw && sweep > 0) {
sweep -= TAU;
} else if (cw && sweep < 0) {
sweep += TAU;
}
sweep %= TAU;
return {
center,
r,
axis,
start,
end: start + sweep,
xl,
cw
};
};
export {
fromEndPoints
};