49 lines
1.3 KiB
TypeScript
49 lines
1.3 KiB
TypeScript
export type Pt = [number, number];
|
|
|
|
export function cubicBezierCommand(pts: Pt[], p1: Pt, p2: Pt, p3: Pt){
|
|
const p0 = pts[pts.length - 1];
|
|
if (!p0) return pts;
|
|
|
|
const [b1p0, b1p1, b1p2] = getMidPoints(p0, p1, p2, p3);
|
|
const [b2p0, b2p1] = getMidPoints(b1p0, b1p1, b1p2);
|
|
const [b3p0] = getMidPoints(b2p0, b2p1);
|
|
|
|
const a1 = Math.atan2(b3p0[1] - p0[1], b3p0[0] - p0[0]);
|
|
const a2 = Math.atan2(p3[1] - b3p0[1], p3[0] - b3p0[0]);
|
|
const d = a2 - a1 - Math.round((a2 - a1) / Math.PI / 2) * Math.PI * 2;
|
|
if (isNaN(d)) {
|
|
console.error('NaN found', { d, a2, a1, p0, p1, p2, p3 });
|
|
return pts;
|
|
}
|
|
|
|
const d03 = sqdist(p0, p3);
|
|
if (d * d * d03 < Math.PI * Math.PI / 18 / 18) {
|
|
pts.push(p3);
|
|
return pts;
|
|
}
|
|
|
|
cubicBezierCommand(pts, b1p0, b2p0, b3p0);
|
|
pts.push(b3p0);
|
|
cubicBezierCommand(pts, b2p1, b1p2, p3);
|
|
|
|
return pts;
|
|
}
|
|
|
|
function sqdist(pt: Pt, to: Pt) {
|
|
const x = pt[0] - to[0];
|
|
const y = pt[1] - to[1];
|
|
return x * x + y * y;
|
|
}
|
|
|
|
function getMidPoints(...pts: Pt[]){
|
|
const mps = [] as typeof pts;
|
|
|
|
for(let i = 1; i < pts.length; i ++){
|
|
mps[i-1] = [
|
|
(pts[i][0] + pts[i-1][0])/2,
|
|
(pts[i][1] + pts[i-1][1])/2,
|
|
];
|
|
}
|
|
|
|
return mps;
|
|
} |