@remotion/paths
Version:
Utilities for working with SVG paths
2,012 lines (1,997 loc) • 99.9 kB
JavaScript
// src/cut-instruction.ts
var cutLInstruction = ({
instruction,
lastPoint,
progress
}) => {
const x = lastPoint.x + (instruction.x - lastPoint.x) * progress;
const y = lastPoint.y + (instruction.y - lastPoint.y) * progress;
return {
type: "L",
x,
y
};
};
function interpolatePoint(pA, pB, factor) {
return {
x: pA.x + (pB.x - pA.x) * factor,
y: pA.y + (pB.y - pA.y) * factor
};
}
function cutCInstruction({
progress,
lastPoint,
instruction
}) {
const u = progress;
const p0 = { x: lastPoint.x, y: lastPoint.y };
const p1 = { x: instruction.cp1x, y: instruction.cp1y };
const p2 = { x: instruction.cp2x, y: instruction.cp2y };
const p3 = { x: instruction.x, y: instruction.y };
const p01 = interpolatePoint(p0, p1, u);
const p12 = interpolatePoint(p1, p2, u);
const p23 = interpolatePoint(p2, p3, u);
const p012 = interpolatePoint(p01, p12, u);
const p123 = interpolatePoint(p12, p23, u);
const p0123 = interpolatePoint(p012, p123, u);
return {
type: "C",
cp1x: p01.x,
cp1y: p01.y,
cp2x: p012.x,
cp2y: p012.y,
x: p0123.x,
y: p0123.y
};
}
var cutInstruction = ({
instruction,
lastPoint,
progress
}) => {
if (instruction.type === "M") {
return instruction;
}
if (instruction.type === "L") {
return cutLInstruction({ instruction, lastPoint, progress });
}
if (instruction.type === "C") {
return cutCInstruction({ instruction, lastPoint, progress });
}
if (instruction.type === "Z") {
return instruction;
}
throw new TypeError(`${instruction.type} is not supported.`);
};
// src/helpers/bezier-values.ts
var tValues = [
[],
[],
[
-0.5773502691896257,
0.5773502691896257
],
[
0,
-0.7745966692414834,
0.7745966692414834
],
[
-0.33998104358485626,
0.33998104358485626,
-0.8611363115940526,
0.8611363115940526
],
[
0,
-0.5384693101056831,
0.5384693101056831,
-0.906179845938664,
0.906179845938664
],
[
0.6612093864662645,
-0.6612093864662645,
-0.2386191860831969,
0.2386191860831969,
-0.932469514203152,
0.932469514203152
],
[
0,
0.4058451513773972,
-0.4058451513773972,
-0.7415311855993945,
0.7415311855993945,
-0.9491079123427585,
0.9491079123427585
],
[
-0.1834346424956498,
0.1834346424956498,
-0.525532409916329,
0.525532409916329,
-0.7966664774136267,
0.7966664774136267,
-0.9602898564975363,
0.9602898564975363
],
[
0,
-0.8360311073266358,
0.8360311073266358,
-0.9681602395076261,
0.9681602395076261,
-0.3242534234038089,
0.3242534234038089,
-0.6133714327005904,
0.6133714327005904
],
[
-0.14887433898163122,
0.14887433898163122,
-0.4333953941292472,
0.4333953941292472,
-0.6794095682990244,
0.6794095682990244,
-0.8650633666889845,
0.8650633666889845,
-0.9739065285171717,
0.9739065285171717
],
[
0,
-0.26954315595234496,
0.26954315595234496,
-0.5190961292068118,
0.5190961292068118,
-0.7301520055740494,
0.7301520055740494,
-0.8870625997680953,
0.8870625997680953,
-0.978228658146057,
0.978228658146057
],
[
-0.1252334085114689,
0.1252334085114689,
-0.3678314989981802,
0.3678314989981802,
-0.5873179542866175,
0.5873179542866175,
-0.7699026741943047,
0.7699026741943047,
-0.9041172563704749,
0.9041172563704749,
-0.9815606342467192,
0.9815606342467192
],
[
0,
-0.2304583159551348,
0.2304583159551348,
-0.44849275103644687,
0.44849275103644687,
-0.6423493394403402,
0.6423493394403402,
-0.8015780907333099,
0.8015780907333099,
-0.9175983992229779,
0.9175983992229779,
-0.9841830547185881,
0.9841830547185881
],
[
-0.10805494870734367,
0.10805494870734367,
-0.31911236892788974,
0.31911236892788974,
-0.5152486363581541,
0.5152486363581541,
-0.6872929048116855,
0.6872929048116855,
-0.827201315069765,
0.827201315069765,
-0.9284348836635735,
0.9284348836635735,
-0.9862838086968123,
0.9862838086968123
],
[
0,
-0.20119409399743451,
0.20119409399743451,
-0.3941513470775634,
0.3941513470775634,
-0.5709721726085388,
0.5709721726085388,
-0.7244177313601701,
0.7244177313601701,
-0.8482065834104272,
0.8482065834104272,
-0.937273392400706,
0.937273392400706,
-0.9879925180204854,
0.9879925180204854
],
[
-0.09501250983763744,
0.09501250983763744,
-0.2816035507792589,
0.2816035507792589,
-0.45801677765722737,
0.45801677765722737,
-0.6178762444026438,
0.6178762444026438,
-0.755404408355003,
0.755404408355003,
-0.8656312023878318,
0.8656312023878318,
-0.9445750230732326,
0.9445750230732326,
-0.9894009349916499,
0.9894009349916499
],
[
0,
-0.17848418149584785,
0.17848418149584785,
-0.3512317634538763,
0.3512317634538763,
-0.5126905370864769,
0.5126905370864769,
-0.6576711592166907,
0.6576711592166907,
-0.7815140038968014,
0.7815140038968014,
-0.8802391537269859,
0.8802391537269859,
-0.9506755217687678,
0.9506755217687678,
-0.9905754753144174,
0.9905754753144174
],
[
-0.0847750130417353,
0.0847750130417353,
-0.2518862256915055,
0.2518862256915055,
-0.41175116146284263,
0.41175116146284263,
-0.5597708310739475,
0.5597708310739475,
-0.6916870430603532,
0.6916870430603532,
-0.8037049589725231,
0.8037049589725231,
-0.8926024664975557,
0.8926024664975557,
-0.9558239495713977,
0.9558239495713977,
-0.9915651684209309,
0.9915651684209309
],
[
0,
-0.16035864564022537,
0.16035864564022537,
-0.31656409996362983,
0.31656409996362983,
-0.46457074137596094,
0.46457074137596094,
-0.600545304661681,
0.600545304661681,
-0.7209661773352294,
0.7209661773352294,
-0.8227146565371428,
0.8227146565371428,
-0.9031559036148179,
0.9031559036148179,
-0.96020815213483,
0.96020815213483,
-0.9924068438435844,
0.9924068438435844
],
[
-0.07652652113349734,
0.07652652113349734,
-0.22778585114164507,
0.22778585114164507,
-0.37370608871541955,
0.37370608871541955,
-0.5108670019508271,
0.5108670019508271,
-0.636053680726515,
0.636053680726515,
-0.7463319064601508,
0.7463319064601508,
-0.8391169718222188,
0.8391169718222188,
-0.912234428251326,
0.912234428251326,
-0.9639719272779138,
0.9639719272779138,
-0.9931285991850949,
0.9931285991850949
],
[
0,
-0.1455618541608951,
0.1455618541608951,
-0.2880213168024011,
0.2880213168024011,
-0.4243421202074388,
0.4243421202074388,
-0.5516188358872198,
0.5516188358872198,
-0.6671388041974123,
0.6671388041974123,
-0.7684399634756779,
0.7684399634756779,
-0.8533633645833173,
0.8533633645833173,
-0.9200993341504008,
0.9200993341504008,
-0.9672268385663063,
0.9672268385663063,
-0.9937521706203895,
0.9937521706203895
],
[
-0.06973927331972223,
0.06973927331972223,
-0.20786042668822127,
0.20786042668822127,
-0.34193582089208424,
0.34193582089208424,
-0.469355837986757,
0.469355837986757,
-0.5876404035069116,
0.5876404035069116,
-0.6944872631866827,
0.6944872631866827,
-0.7878168059792081,
0.7878168059792081,
-0.8658125777203002,
0.8658125777203002,
-0.926956772187174,
0.926956772187174,
-0.9700604978354287,
0.9700604978354287,
-0.9942945854823992,
0.9942945854823992
],
[
0,
-0.1332568242984661,
0.1332568242984661,
-0.26413568097034495,
0.26413568097034495,
-0.3903010380302908,
0.3903010380302908,
-0.5095014778460075,
0.5095014778460075,
-0.6196098757636461,
0.6196098757636461,
-0.7186613631319502,
0.7186613631319502,
-0.8048884016188399,
0.8048884016188399,
-0.8767523582704416,
0.8767523582704416,
-0.9329710868260161,
0.9329710868260161,
-0.9725424712181152,
0.9725424712181152,
-0.9947693349975522,
0.9947693349975522
],
[
-0.06405689286260563,
0.06405689286260563,
-0.1911188674736163,
0.1911188674736163,
-0.3150426796961634,
0.3150426796961634,
-0.4337935076260451,
0.4337935076260451,
-0.5454214713888396,
0.5454214713888396,
-0.6480936519369755,
0.6480936519369755,
-0.7401241915785544,
0.7401241915785544,
-0.820001985973903,
0.820001985973903,
-0.8864155270044011,
0.8864155270044011,
-0.9382745520027328,
0.9382745520027328,
-0.9747285559713095,
0.9747285559713095,
-0.9951872199970213,
0.9951872199970213
]
];
var cValues = [
[],
[],
[1, 1],
[
0.8888888888888888,
0.5555555555555556,
0.5555555555555556
],
[
0.6521451548625461,
0.6521451548625461,
0.34785484513745385,
0.34785484513745385
],
[
0.5688888888888889,
0.47862867049936647,
0.47862867049936647,
0.23692688505618908,
0.23692688505618908
],
[
0.3607615730481386,
0.3607615730481386,
0.46791393457269104,
0.46791393457269104,
0.17132449237917036,
0.17132449237917036
],
[
0.4179591836734694,
0.3818300505051189,
0.3818300505051189,
0.27970539148927664,
0.27970539148927664,
0.1294849661688697,
0.1294849661688697
],
[
0.362683783378362,
0.362683783378362,
0.31370664587788727,
0.31370664587788727,
0.22238103445337448,
0.22238103445337448,
0.10122853629037626,
0.10122853629037626
],
[
0.3302393550012598,
0.1806481606948574,
0.1806481606948574,
0.08127438836157441,
0.08127438836157441,
0.31234707704000286,
0.31234707704000286,
0.26061069640293544,
0.26061069640293544
],
[
0.29552422471475287,
0.29552422471475287,
0.26926671930999635,
0.26926671930999635,
0.21908636251598204,
0.21908636251598204,
0.1494513491505806,
0.1494513491505806,
0.06667134430868814,
0.06667134430868814
],
[
0.2729250867779006,
0.26280454451024665,
0.26280454451024665,
0.23319376459199048,
0.23319376459199048,
0.18629021092773426,
0.18629021092773426,
0.1255803694649046,
0.1255803694649046,
0.05566856711617366,
0.05566856711617366
],
[
0.24914704581340277,
0.24914704581340277,
0.2334925365383548,
0.2334925365383548,
0.20316742672306592,
0.20316742672306592,
0.16007832854334622,
0.16007832854334622,
0.10693932599531843,
0.10693932599531843,
0.04717533638651183,
0.04717533638651183
],
[
0.2325515532308739,
0.22628318026289723,
0.22628318026289723,
0.2078160475368885,
0.2078160475368885,
0.17814598076194574,
0.17814598076194574,
0.13887351021978725,
0.13887351021978725,
0.09212149983772845,
0.09212149983772845,
0.04048400476531588,
0.04048400476531588
],
[
0.2152638534631578,
0.2152638534631578,
0.2051984637212956,
0.2051984637212956,
0.18553839747793782,
0.18553839747793782,
0.15720316715819355,
0.15720316715819355,
0.12151857068790319,
0.12151857068790319,
0.08015808715976021,
0.08015808715976021,
0.03511946033175186,
0.03511946033175186
],
[
0.2025782419255613,
0.19843148532711158,
0.19843148532711158,
0.1861610000155622,
0.1861610000155622,
0.16626920581699392,
0.16626920581699392,
0.13957067792615432,
0.13957067792615432,
0.10715922046717194,
0.10715922046717194,
0.07036604748810812,
0.07036604748810812,
0.03075324199611727,
0.03075324199611727
],
[
0.1894506104550685,
0.1894506104550685,
0.18260341504492358,
0.18260341504492358,
0.16915651939500254,
0.16915651939500254,
0.14959598881657674,
0.14959598881657674,
0.12462897125553388,
0.12462897125553388,
0.09515851168249279,
0.09515851168249279,
0.062253523938647894,
0.062253523938647894,
0.027152459411754096,
0.027152459411754096
],
[
0.17944647035620653,
0.17656270536699264,
0.17656270536699264,
0.16800410215645004,
0.16800410215645004,
0.15404576107681028,
0.15404576107681028,
0.13513636846852548,
0.13513636846852548,
0.11188384719340397,
0.11188384719340397,
0.08503614831717918,
0.08503614831717918,
0.0554595293739872,
0.0554595293739872,
0.02414830286854793,
0.02414830286854793
],
[
0.1691423829631436,
0.1691423829631436,
0.16427648374583273,
0.16427648374583273,
0.15468467512626524,
0.15468467512626524,
0.14064291467065065,
0.14064291467065065,
0.12255520671147846,
0.12255520671147846,
0.10094204410628717,
0.10094204410628717,
0.07642573025488905,
0.07642573025488905,
0.0497145488949698,
0.0497145488949698,
0.02161601352648331,
0.02161601352648331
],
[
0.1610544498487837,
0.15896884339395434,
0.15896884339395434,
0.15276604206585967,
0.15276604206585967,
0.1426067021736066,
0.1426067021736066,
0.12875396253933621,
0.12875396253933621,
0.11156664554733399,
0.11156664554733399,
0.09149002162245,
0.09149002162245,
0.06904454273764123,
0.06904454273764123,
0.0448142267656996,
0.0448142267656996,
0.019461788229726478,
0.019461788229726478
],
[
0.15275338713072584,
0.15275338713072584,
0.14917298647260374,
0.14917298647260374,
0.14209610931838204,
0.14209610931838204,
0.13168863844917664,
0.13168863844917664,
0.11819453196151841,
0.11819453196151841,
0.10193011981724044,
0.10193011981724044,
0.08327674157670475,
0.08327674157670475,
0.06267204833410907,
0.06267204833410907,
0.04060142980038694,
0.04060142980038694,
0.017614007139152118,
0.017614007139152118
],
[
0.14608113364969041,
0.14452440398997005,
0.14452440398997005,
0.13988739479107315,
0.13988739479107315,
0.13226893863333747,
0.13226893863333747,
0.12183141605372853,
0.12183141605372853,
0.10879729916714838,
0.10879729916714838,
0.09344442345603386,
0.09344442345603386,
0.0761001136283793,
0.0761001136283793,
0.057134425426857205,
0.057134425426857205,
0.036953789770852494,
0.036953789770852494,
0.016017228257774335,
0.016017228257774335
],
[
0.13925187285563198,
0.13925187285563198,
0.13654149834601517,
0.13654149834601517,
0.13117350478706238,
0.13117350478706238,
0.12325237681051242,
0.12325237681051242,
0.11293229608053922,
0.11293229608053922,
0.10041414444288096,
0.10041414444288096,
0.08594160621706773,
0.08594160621706773,
0.06979646842452049,
0.06979646842452049,
0.052293335152683286,
0.052293335152683286,
0.03377490158481415,
0.03377490158481415,
0.0146279952982722,
0.0146279952982722
],
[
0.13365457218610619,
0.1324620394046966,
0.1324620394046966,
0.12890572218808216,
0.12890572218808216,
0.12304908430672953,
0.12304908430672953,
0.11499664022241136,
0.11499664022241136,
0.10489209146454141,
0.10489209146454141,
0.09291576606003515,
0.09291576606003515,
0.07928141177671895,
0.07928141177671895,
0.06423242140852585,
0.06423242140852585,
0.04803767173108467,
0.04803767173108467,
0.030988005856979445,
0.030988005856979445,
0.013411859487141771,
0.013411859487141771
],
[
0.12793819534675216,
0.12793819534675216,
0.1258374563468283,
0.1258374563468283,
0.12167047292780339,
0.12167047292780339,
0.1155056680537256,
0.1155056680537256,
0.10744427011596563,
0.10744427011596563,
0.09761865210411388,
0.09761865210411388,
0.08619016153195327,
0.08619016153195327,
0.0733464814110803,
0.0733464814110803,
0.05929858491543678,
0.05929858491543678,
0.04427743881741981,
0.04427743881741981,
0.028531388628933663,
0.028531388628933663,
0.0123412297999872,
0.0123412297999872
]
];
var binomialCoefficients = [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]];
// src/helpers/bezier-functions.ts
var cubicPoint = (xs, ys, t) => {
const x = (1 - t) * (1 - t) * (1 - t) * xs[0] + 3 * (1 - t) * (1 - t) * t * xs[1] + 3 * (1 - t) * t * t * xs[2] + t * t * t * xs[3];
const y = (1 - t) * (1 - t) * (1 - t) * ys[0] + 3 * (1 - t) * (1 - t) * t * ys[1] + 3 * (1 - t) * t * t * ys[2] + t * t * t * ys[3];
return { x, y };
};
var getDerivative = (derivative, t, vs) => {
const n = vs.length - 1;
let value;
if (n === 0) {
return 0;
}
if (derivative === 0) {
value = 0;
for (let k = 0;k <= n; k++) {
value += binomialCoefficients[n][k] * (1 - t) ** (n - k) * t ** k * vs[k];
}
return value;
}
const _vs = new Array(n);
for (let k = 0;k < n; k++) {
_vs[k] = n * (vs[k + 1] - vs[k]);
}
return getDerivative(derivative - 1, t, _vs);
};
function bFunc(xs, ys, t) {
const xbase = getDerivative(1, t, xs);
const ybase = getDerivative(1, t, ys);
const combined = xbase * xbase + ybase * ybase;
return Math.sqrt(combined);
}
var getCubicArcLength = ({
sx,
sy,
t
}) => {
let correctedT;
const n = 20;
const z = t / 2;
let sum = 0;
for (let i = 0;i < n; i++) {
correctedT = z * tValues[n][i] + z;
sum += cValues[n][i] * bFunc(sx, sy, correctedT);
}
return z * sum;
};
var quadraticPoint = (xs, ys, t) => {
const x = (1 - t) * (1 - t) * xs[0] + 2 * (1 - t) * t * xs[1] + t * t * xs[2];
const y = (1 - t) * (1 - t) * ys[0] + 2 * (1 - t) * t * ys[1] + t * t * ys[2];
return { x, y };
};
var cubicDerivative = (xs, ys, t) => {
const derivative = quadraticPoint([3 * (xs[1] - xs[0]), 3 * (xs[2] - xs[1]), 3 * (xs[3] - xs[2])], [3 * (ys[1] - ys[0]), 3 * (ys[2] - ys[1]), 3 * (ys[3] - ys[2])], t);
return derivative;
};
var getQuadraticArcLength = (xs, ys, t) => {
if (t === undefined) {
t = 1;
}
const ax = xs[0] - 2 * xs[1] + xs[2];
const ay = ys[0] - 2 * ys[1] + ys[2];
const bx = 2 * xs[1] - 2 * xs[0];
const by = 2 * ys[1] - 2 * ys[0];
const A = 4 * (ax * ax + ay * ay);
const B = 4 * (ax * bx + ay * by);
const C = bx * bx + by * by;
if (A === 0) {
return t * Math.sqrt((xs[2] - xs[0]) ** 2 + (ys[2] - ys[0]) ** 2);
}
const b = B / (2 * A);
const c = C / A;
const u = t + b;
const k = c - b * b;
const uuk = u * u + k > 0 ? Math.sqrt(u * u + k) : 0;
const bbk = b * b + k > 0 ? Math.sqrt(b * b + k) : 0;
const term = b + Math.sqrt(b * b + k) === 0 ? 0 : k * Math.log(Math.abs((u + uuk) / (b + bbk)));
return Math.sqrt(A) / 2 * (u * uuk - b * bbk + term);
};
var quadraticDerivative = (xs, ys, t) => {
return {
x: (1 - t) * 2 * (xs[1] - xs[0]) + t * 2 * (xs[2] - xs[1]),
y: (1 - t) * 2 * (ys[1] - ys[0]) + t * 2 * (ys[2] - ys[1])
};
};
var t2length = ({
length,
totalLength,
func
}) => {
let error = 1;
let t = length / totalLength;
let step = (length - func(t)) / totalLength;
let numIterations = 0;
while (error > 0.001) {
const increasedTLength = func(t + step);
const increasedTError = Math.abs(length - increasedTLength) / totalLength;
if (increasedTError < error) {
error = increasedTError;
t += step;
} else {
const decreasedTLength = func(t - step);
const decreasedTError = Math.abs(length - decreasedTLength) / totalLength;
if (decreasedTError < error) {
error = decreasedTError;
t -= step;
} else {
step /= 2;
}
}
numIterations++;
if (numIterations > 500) {
break;
}
}
return t;
};
// src/helpers/bezier.ts
var makeQuadratic = ({
startX,
startY,
cpx,
cpy,
x,
y
}) => {
const a = { x: startX, y: startY };
const b = { x: cpx, y: cpy };
const c = { x, y };
const length = getQuadraticArcLength([a.x, b.x, c.x, 0], [a.y, b.y, c.y, 0], 1);
const getTotalLength = () => {
return length;
};
const getPointAtLength = (len) => {
const xs = [a.x, b.x, c.x, 0];
const xy = [a.y, b.y, c.y, 0];
const t = t2length({
length: len,
totalLength: length,
func: (i) => getQuadraticArcLength(xs, xy, i)
});
return quadraticPoint(xs, xy, t);
};
const getTangentAtLength = (len) => {
const xs = [a.x, b.x, c.x, 0];
const xy = [a.y, b.y, c.y, 0];
const t = t2length({
length: len,
totalLength: length,
func: (i) => getQuadraticArcLength(xs, xy, i)
});
const derivative = quadraticDerivative(xs, xy, t);
const mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y);
let tangent;
if (mdl > 0) {
tangent = { x: derivative.x / mdl, y: derivative.y / mdl };
} else {
tangent = { x: 0, y: 0 };
}
return tangent;
};
const getC = () => {
return c;
};
return {
getPointAtLength,
getTangentAtLength,
getTotalLength,
getC,
type: "quadratic-bezier",
getD: () => ({ x: 0, y: 0 })
};
};
var makeCubic = ({
startX,
startY,
cp1x,
cp1y,
cp2x,
cp2y,
x,
y
}) => {
const a = { x: startX, y: startY };
const b = { x: cp1x, y: cp1y };
const c = { x: cp2x, y: cp2y };
const d = { x, y };
const length = getCubicArcLength({
sx: [a.x, b.x, c.x, d.x],
sy: [a.y, b.y, c.y, d.y],
t: 1
});
const getTotalLength = () => {
return length;
};
const getPointAtLength = (len) => {
const sx = [a.x, b.x, c.x, d.x];
const sy = [a.y, b.y, c.y, d.y];
const t = t2length({
length: len,
totalLength: length,
func: (i) => {
return getCubicArcLength({ sx, sy, t: i });
}
});
return cubicPoint(sx, sy, t);
};
const getTangentAtLength = (len) => {
const xs = [a.x, b.x, c.x, d.x];
const xy = [a.y, b.y, c.y, d.y];
const t = t2length({
length: len,
totalLength: length,
func: (i) => getCubicArcLength({ sx: xs, sy: xy, t: i })
});
const derivative = cubicDerivative(xs, xy, t);
const mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y);
let tangent;
if (mdl > 0) {
tangent = { x: derivative.x / mdl, y: derivative.y / mdl };
} else {
tangent = { x: 0, y: 0 };
}
return tangent;
};
const getC = () => {
return c;
};
const getD = () => {
return d;
};
return {
getPointAtLength,
getTangentAtLength,
getTotalLength,
getC,
getD,
type: "cubic-bezier"
};
};
// src/helpers/linear.ts
var makeLinearPosition = ({
x0,
x1,
y0,
y1
}) => {
return {
getTotalLength: () => {
return Math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2);
},
getPointAtLength: (pos) => {
let fraction = pos / Math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2);
fraction = Number.isNaN(fraction) ? 1 : fraction;
const newDeltaX = (x1 - x0) * fraction;
const newDeltaY = (y1 - y0) * fraction;
return { x: x0 + newDeltaX, y: y0 + newDeltaY };
},
getTangentAtLength: () => {
const module = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
return { x: (x1 - x0) / module, y: (y1 - y0) / module };
},
type: "linear"
};
};
// src/helpers/reduced-analysis.ts
var conductAnalysis = (instructions) => {
let currentPoint = { x: 0, y: 0 };
let moveStart = { x: 0, y: 0 };
const segments = [];
for (let i = 0;i < instructions.length; i++) {
const instruction = instructions[i];
if (instruction.type === "M") {
currentPoint = { x: instruction.x, y: instruction.y };
moveStart = { x: currentPoint.x, y: currentPoint.y };
segments.push({
startPoint: { x: instruction.x, y: instruction.y },
instructionsAndInfo: [
{
instruction,
function: null,
length: 0,
startPoint: currentPoint
}
]
});
}
if (instruction.type === "L") {
if (segments.length > 0) {
const length = Math.sqrt((currentPoint.x - instruction.x) ** 2 + (currentPoint.y - instruction.y) ** 2);
segments[segments.length - 1].instructionsAndInfo.push({
instruction,
length,
function: makeLinearPosition({
x0: currentPoint.x,
x1: instruction.x,
y0: currentPoint.y,
y1: instruction.y
}),
startPoint: currentPoint
});
}
currentPoint = { x: instruction.x, y: instruction.y };
}
if (instruction.type === "Z") {
if (segments.length > 0) {
const length = Math.sqrt((segments[segments.length - 1].startPoint.x - currentPoint.x) ** 2 + (segments[segments.length - 1].startPoint.y - currentPoint.y) ** 2);
segments[segments.length - 1].instructionsAndInfo.push({
instruction,
function: makeLinearPosition({
x0: currentPoint.x,
x1: moveStart.x,
y0: currentPoint.y,
y1: moveStart.y
}),
length,
startPoint: { ...currentPoint }
});
}
currentPoint = { x: moveStart.x, y: moveStart.y };
}
if (instruction.type === "C") {
const curve = makeCubic({
startX: currentPoint.x,
startY: currentPoint.y,
cp1x: instruction.cp1x,
cp1y: instruction.cp1y,
cp2x: instruction.cp2x,
cp2y: instruction.cp2y,
x: instruction.x,
y: instruction.y
});
const length = curve.getTotalLength();
if (segments.length > 0) {
segments[segments.length - 1].instructionsAndInfo.push({
instruction,
length,
function: curve,
startPoint: { ...currentPoint }
});
}
currentPoint = { x: instruction.x, y: instruction.y };
}
}
return segments;
};
// src/parse-path.ts
var length = {
a: 7,
A: 7,
C: 6,
c: 6,
H: 1,
h: 1,
L: 2,
l: 2,
M: 2,
m: 2,
Q: 4,
q: 4,
S: 4,
s: 4,
T: 2,
t: 2,
V: 1,
v: 1,
Z: 0,
z: 0
};
var chunkExact = (array, instruction) => {
const chunks = [];
const expectedSize = length[instruction];
if (array.length % expectedSize !== 0) {
throw new Error(`Expected number of arguments of SVG instruction "${instruction} ${array.join(" ")}" to be a multiple of ${expectedSize}`);
}
for (let i = 0;i < array.length; i += expectedSize) {
chunks.push(array.slice(i, i + expectedSize));
}
return chunks;
};
var makeInstructions = (arr, instruction, cb) => {
return chunkExact(arr, instruction).map((args) => {
return cb(args);
});
};
var segmentRegExp = /([astvzqmhlc])([^astvzqmhlc]*)/gi;
var numberRegExp = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;
var parseValues = (args, instructionType) => {
const numbers = args.match(numberRegExp);
if (!numbers) {
if (instructionType === "Z" || instructionType === "z") {
return [];
}
throw new Error(`Malformed path data: ${instructionType} was expected to have numbers afterwards`);
}
const expectedArguments = length[instructionType];
if (numbers.length % expectedArguments !== 0) {
throw new Error(`Malformed path data: ${instructionType} was expected to have a multiple of ${expectedArguments} numbers, but got "${instructionType} ${numbers.join(" ")} instead"`);
}
return numbers.map(Number);
};
var parsePath = (path) => {
if (!path) {
throw new Error("No path provided");
}
const segments = path.match(segmentRegExp);
if (!segments) {
throw new Error(`No path elements found in string ${path}`);
}
return segments.map((segmentString) => {
const command = segmentString.charAt(0);
const args = parseValues(segmentString.substring(1), command);
if (command === "M" && args.length > 2) {
const segmentsArray = [];
segmentsArray.push({
type: command,
x: args[0],
y: args[1]
});
segmentsArray.push(...makeInstructions(args.slice(2), "L", (numbers) => ({
type: "L",
x: numbers[0],
y: numbers[1]
})));
return segmentsArray;
}
if (command === "m" && args.length > 2) {
const segmentsArray = [];
segmentsArray.push({
type: command,
dx: args[0],
dy: args[1]
});
segmentsArray.push(...makeInstructions(args.slice(2), "l", (numbers) => ({
type: "l",
dx: numbers[0],
dy: numbers[1]
})));
return segmentsArray;
}
if (command === "Z" || command === "z") {
return [
{
type: "Z"
}
];
}
if (command === "A") {
return makeInstructions(args, command, (numbers) => ({
type: command,
rx: numbers[0],
ry: numbers[1],
xAxisRotation: numbers[2],
largeArcFlag: numbers[3] === 1,
sweepFlag: numbers[4] === 1,
x: numbers[5],
y: numbers[6]
}));
}
if (command === "a") {
return makeInstructions(args, command, (numbers) => ({
type: command,
rx: numbers[0],
ry: numbers[1],
xAxisRotation: numbers[2],
largeArcFlag: numbers[3] === 1,
sweepFlag: numbers[4] === 1,
dx: numbers[5],
dy: numbers[6]
}));
}
if (command === "C") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cp1x: numbers[0],
cp1y: numbers[1],
cp2x: numbers[2],
cp2y: numbers[3],
x: numbers[4],
y: numbers[5]
}));
}
if (command === "c") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cp1dx: numbers[0],
cp1dy: numbers[1],
cp2dx: numbers[2],
cp2dy: numbers[3],
dx: numbers[4],
dy: numbers[5]
}));
}
if (command === "S") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cpx: numbers[0],
cpy: numbers[1],
x: numbers[2],
y: numbers[3]
}));
}
if (command === "s") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cpdx: numbers[0],
cpdy: numbers[1],
dx: numbers[2],
dy: numbers[3]
}));
}
if (command === "H") {
return makeInstructions(args, command, (numbers) => ({
type: command,
x: numbers[0]
}));
}
if (command === "h") {
return makeInstructions(args, command, (numbers) => ({
type: command,
dx: numbers[0]
}));
}
if (command === "V") {
return makeInstructions(args, command, (numbers) => ({
type: command,
y: numbers[0]
}));
}
if (command === "v") {
return makeInstructions(args, command, (numbers) => ({
type: command,
dy: numbers[0]
}));
}
if (command === "L") {
return makeInstructions(args, command, (numbers) => ({
type: command,
x: numbers[0],
y: numbers[1]
}));
}
if (command === "M") {
return makeInstructions(args, command, (numbers) => ({
type: command,
x: numbers[0],
y: numbers[1]
}));
}
if (command === "m") {
return makeInstructions(args, command, (numbers) => ({
type: command,
dx: numbers[0],
dy: numbers[1]
}));
}
if (command === "l") {
return makeInstructions(args, command, (numbers) => ({
type: command,
dx: numbers[0],
dy: numbers[1]
}));
}
if (command === "Q") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cpx: numbers[0],
cpy: numbers[1],
x: numbers[2],
y: numbers[3]
}));
}
if (command === "q") {
return makeInstructions(args, command, (numbers) => ({
type: command,
cpdx: numbers[0],
cpdy: numbers[1],
dx: numbers[2],
dy: numbers[3]
}));
}
if (command === "T") {
return makeInstructions(args, command, (numbers) => ({
type: command,
x: numbers[0],
y: numbers[1]
}));
}
if (command === "t") {
return makeInstructions(args, command, (numbers) => ({
type: command,
dx: numbers[0],
dy: numbers[1]
}));
}
throw new Error(`Invalid path element ${segmentString}`);
}, []).flat(1);
};
// src/helpers/convert-q-to-c-instruction.ts
var convertQToCInstruction = (instruction, startPoint) => {
const cp1x = startPoint.x + 2 / 3 * (instruction.cpx - startPoint.x);
const cp1y = startPoint.y + 2 / 3 * (instruction.cpy - startPoint.y);
const cp2x = instruction.x + 2 / 3 * (instruction.cpx - instruction.x);
const cp2y = instruction.y + 2 / 3 * (instruction.cpy - instruction.y);
return {
type: "C",
cp1x,
cp1y,
cp2x,
cp2y,
x: instruction.x,
y: instruction.y
};
};
// src/helpers/iterate.ts
var iterateOverSegments = ({
segments,
iterate
}) => {
let x = 0;
let y = 0;
let initialX = 0;
let initialY = 0;
let cpX = null;
let cpY = null;
const newSegments = segments.map((s, i) => {
const newSeg = iterate({
segment: s,
x,
y,
prevSegment: segments[i - 1] ?? null,
initialX,
initialY,
cpX,
cpY
});
switch (s.type) {
case "M":
initialX = s.x;
initialY = s.y;
x = s.x;
y = s.y;
cpX = null;
cpY = null;
break;
case "Q":
x = s.x;
y = s.y;
cpX = s.cpx;
cpY = s.cpy;
break;
case "A":
x = s.x;
y = s.y;
cpX = null;
cpY = null;
break;
case "C":
x = s.x;
y = s.y;
cpX = s.cp2x;
cpY = s.cp2y;
break;
case "S":
x = s.x;
y = s.y;
cpX = s.cpx;
cpY = s.cpy;
break;
case "T":
if (cpX !== null && cpY !== null) {
cpX = x - (cpX - x);
cpY = y - (cpY - y);
}
x = s.x;
y = s.y;
break;
case "L":
x = s.x;
y = s.y;
cpX = null;
cpY = null;
break;
case "V":
y = s.y;
cpX = null;
cpY = null;
break;
case "H":
x = s.x;
cpX = null;
cpY = null;
break;
case "Z":
x = initialX;
y = initialY;
cpX = null;
cpY = null;
break;
default:
throw new Error(`Unexpected instruction ${s.type}`);
}
return newSeg;
});
return newSegments.flat(1);
};
// src/helpers/remove-a-s-t-curves.ts
var TAU = Math.PI * 2;
function approximate_unit_arc(theta1, delta_theta) {
const alpha = 4 / 3 * Math.tan(delta_theta / 4);
const x1 = Math.cos(theta1);
const y1 = Math.sin(theta1);
const x2 = Math.cos(theta1 + delta_theta);
const y2 = Math.sin(theta1 + delta_theta);
return [
x1,
y1,
x1 - y1 * alpha,
y1 + x1 * alpha,
x2 + y2 * alpha,
y2 - x2 * alpha,
x2,
y2
];
}
function unit_vector_angle(ux, uy, vx, vy) {
const sign = ux * vy - uy * vx < 0 ? -1 : 1;
let dot = ux * vx + uy * vy;
if (dot > 1) {
dot = 1;
}
if (dot < -1) {
dot = -1;
}
return sign * Math.acos(dot);
}
function get_arc_center({
x1,
y1,
x2,
y2,
largeArcFlag,
sweepFlag,
rx,
ry,
sin_phi,
cos_phi
}) {
const x1p = cos_phi * (x1 - x2) / 2 + sin_phi * (y1 - y2) / 2;
const y1p = -sin_phi * (x1 - x2) / 2 + cos_phi * (y1 - y2) / 2;
const rx_sq = rx * rx;
const ry_sq = ry * ry;
const x1p_sq = x1p * x1p;
const y1p_sq = y1p * y1p;
let radicant = rx_sq * ry_sq - rx_sq * y1p_sq - ry_sq * x1p_sq;
if (radicant < 0) {
radicant = 0;
}
radicant /= rx_sq * y1p_sq + ry_sq * x1p_sq;
radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1);
const cxp = radicant * rx / ry * y1p;
const cyp = radicant * -ry / rx * x1p;
const cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2;
const cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2;
const v1x = (x1p - cxp) / rx;
const v1y = (y1p - cyp) / ry;
const v2x = (-x1p - cxp) / rx;
const v2y = (-y1p - cyp) / ry;
const theta1 = unit_vector_angle(1, 0, v1x, v1y);
let delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
if (sweepFlag === false && delta_theta > 0) {
delta_theta -= TAU;
}
if (sweepFlag === true && delta_theta < 0) {
delta_theta += TAU;
}
return [cx, cy, theta1, delta_theta];
}
function arcToCircle({
x1,
y1,
x2,
y2,
largeArcFlag,
sweepFlag,
rx,
ry,
phi
}) {
const sin_phi = Math.sin(phi * TAU / 360);
const cos_phi = Math.cos(phi * TAU / 360);
const x1p = cos_phi * (x1 - x2) / 2 + sin_phi * (y1 - y2) / 2;
const y1p = -sin_phi * (x1 - x2) / 2 + cos_phi * (y1 - y2) / 2;
if (x1p === 0 && y1p === 0) {
return [];
}
if (rx === 0 || ry === 0) {
return [];
}
rx = Math.abs(rx);
ry = Math.abs(ry);
const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
if (lambda > 1) {
rx *= Math.sqrt(lambda);
ry *= Math.sqrt(lambda);
}
const cc = get_arc_center({
x1,
y1,
x2,
y2,
largeArcFlag,
sweepFlag,
rx,
ry,
sin_phi,
cos_phi
});
const result = [];
let theta1 = cc[2];
let delta_theta = cc[3];
const segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
delta_theta /= segments;
for (let i = 0;i < segments; i++) {
result.push(approximate_unit_arc(theta1, delta_theta));
theta1 += delta_theta;
}
return result.map((curve) => {
for (let i = 0;i < curve.length; i += 2) {
let x = curve[i + 0];
let y = curve[i + 1];
x *= rx;
y *= ry;
const xp = cos_phi * x - sin_phi * y;
const yp = sin_phi * x + cos_phi * y;
curve[i + 0] = xp + cc[0];
curve[i + 1] = yp + cc[1];
}
return curve;
});
}
var removeATSHVQInstructions = (segments) => {
return iterateOverSegments({
segments,
iterate: ({ segment, prevSegment, x, y, cpX, cpY }) => {
if (segment.type === "H") {
return [{ type: "L", x: segment.x, y }];
}
if (segment.type === "V") {
return [{ type: "L", x, y: segment.y }];
}
if (segment.type === "A") {
const nextX = segment.x;
const nextY = segment.y;
const new_segments = arcToCircle({
x1: x,
y1: y,
x2: nextX,
y2: nextY,
largeArcFlag: segment.largeArcFlag,
sweepFlag: segment.sweepFlag,
rx: segment.rx,
ry: segment.ry,
phi: segment.xAxisRotation
});
if (new_segments.length === 0) {
return [
{
type: "L",
x: segment.x,
y: segment.y
}
];
}
const result = new_segments.map((_s) => {
return {
type: "C",
cp1x: _s[2],
cp1y: _s[3],
cp2x: _s[4],
cp2y: _s[5],
x: _s[6],
y: _s[7]
};
});
return result;
}
if (segment.type === "T") {
let prevControlX = 0;
let prevControlY = 0;
if (prevSegment && (prevSegment.type === "Q" || prevSegment.type === "T")) {
prevControlX = cpX;
prevControlY = cpY;
} else {
prevControlX = x;
prevControlY = y;
}
const vectorX = prevControlX - x;
const vectorY = prevControlY - y;
const newControlX = x - vectorX;
const newControlY = y - vectorY;
return [
convertQToCInstruction({
type: "Q",
cpx: newControlX,
cpy: newControlY,
x: segment.x,
y: segment.y
}, { x, y })
];
}
if (segment.type === "S") {
let prevControlX = 0;
let prevControlY = 0;
if (prevSegment && prevSegment.type === "C") {
prevControlX = prevSegment.cp2x;
prevControlY = prevSegment.cp2y;
} else if (prevSegment && prevSegment.type === "S") {
prevControlX = prevSegment.cpx;
prevControlY = prevSegment.cpy;
} else {
prevControlX = x;
prevControlY = y;
}
const vectorX = prevControlX - x;
const vectorY = prevControlY - y;
const newControlX = x - vectorX;
const newControlY = y - vectorY;
return [
{
type: "C",
cp1x: newControlX,
cp1y: newControlY,
cp2x: segment.cpx,
cp2y: segment.cpy,
x: segment.x,
y: segment.y
}
];
}
if (segment.type === "Q") {
return [convertQToCInstruction(segment, { x, y })];
}
return [segment];
}
});
};
// src/serialize-instructions.ts
var serializeInstruction = (instruction) => {
if (instruction.type === "A") {
return `A ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "a") {
return `a ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "C") {
return `C ${instruction.cp1x} ${instruction.cp1y} ${instruction.cp2x} ${instruction.cp2y} ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "c") {
return `c ${instruction.cp1dx} ${instruction.cp1dy} ${instruction.cp2dx} ${instruction.cp2dy} ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "S") {
return `S ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "s") {
return `s ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "Q") {
return `Q ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "q") {
return `q ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "Z") {
return "Z";
}
if (instruction.type === "H") {
return `H ${instruction.x}`;
}
if (instruction.type === "h") {
return `h ${instruction.dx}`;
}
if (instruction.type === "V") {
return `V ${instruction.y}`;
}
if (instruction.type === "v") {
return `v ${instruction.dy}`;
}
if (instruction.type === "L") {
return `L ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "l") {
return `l ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "M") {
return `M ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "m") {
return `m ${instruction.dx} ${instruction.dy}`;
}
if (instruction.type === "T") {
return `T ${instruction.x} ${instruction.y}`;
}
if (instruction.type === "t") {
return `t ${instruction.dx} ${instruction.dy}`;
}
throw new Error(`Unknown instruction type: ${instruction.type}`);
};
var serializeInstructions = (path) => {
return path.map((p) => {
return serializeInstruction(p);
}).join(" ");
};
// src/normalize-path.ts
var normalizeInstructions = (instructions) => {
const normalized = [];
let x = 0;
let y = 0;
let moveX = 0;
let moveY = 0;
for (let i = 0;i < instructions.length; i++) {
const instruction = instructions[i];
if (instruction.type === "M") {
moveX = instruction.x;
moveY = instruction.y;
} else if (instruction.type === "m") {
moveX += instruction.dx;
moveY += instruction.dy;
}
if (instruction.type === "A" || instruction.type === "C" || instruction.type === "L" || instruction.type === "M" || instruction.type === "Q" || instruction.type === "S" || instruction.type === "T") {
normalized.push(instruction);
x = instruction.x;
y = instruction.y;
continue;
}
if (instruction.type === "a" || instruction.type === "c" || instruction.type === "l" || instruction.type === "m" || instruction.type === "q" || instruction.type === "s" || instruction.type === "t") {
const currentX = x;
const currentY = y;
x += instruction.dx;
y += instruction.dy;
if (instruction.type === "a") {
normalized.push({
type: "A",
largeArcFlag: instruction.largeArcFlag,
rx: instruction.rx,
ry: instruction.ry,
sweepFlag: instruction.sweepFlag,
xAxisRotation: instruction.xAxisRotation,
x,
y
});
continue;
}
if (instruction.type === "c") {
normalized.push({
type: "C",
cp1x: instruction.cp1dx + currentX,
cp1y: instruction.cp1dy + currentY,
cp2x: instruction.cp2dx + currentX,
cp2y: instruction.cp2dy + currentY,
x,
y
});
continue;
}
if (instruction.type === "l") {
normalized.push({
type: "L",
x,
y
});
continue;
}
if (instruction.type === "m") {
normalized.push({
type: "M",
x,
y
});
continue;
}
if (instruction.type === "q") {
normalized.push({
type: "Q",
cpx: instruction.cpdx + currentX,
cpy: instruction.cpdy + currentY,
x,
y
});
continue;
}
if (instruction.type === "s") {
normalized.push({
type: "S",
cpx: instruction.cpdx + currentX,
cpy: instruction.cpdy + currentY,
x,
y
});
continue;
}
if (instruction.type === "t") {
normalized.push({
type: "T",
x,
y
});
continue;
}
}
if (instruction.type === "H") {
normalized.push(instruction);
x = instruction.x;
continue;
}
if (instruction.type === "V") {
normalized.push(instruction);
y = instruction.y;
continue;
}
if (instruction.type === "Z") {
normalized.push(instruction);
x = moveX;
y = moveY;
continue;
}
if (instruction.type === "h") {
x += instruction.dx;
normalized.push({
type: "H",
x
});
continue;
}
if (instruction.type === "v") {
y += instruction.dy;
normalized.push({
type: "V",
y
});
continue;
}
throw new Error("Unknown instruction type: " + instruction.type);
}
return normalized;
};
var normalizePath = (path) => {
const instructions = parsePath(path);
const normalized = normalizeInstructions(instructions);
return serializeInstructions(normalized);
};
// src/reduce-instructions.ts
var reduceInstructions = (instruction) => {
const simplified = normalizeInstructions(instruction);
return removeATSHVQInstructions(simplified);
};
// src/cut-path.ts
var cutPath = (d, length2) => {
const parsed = parsePath(d);
const reduced = reduceInstructions(parsed);
const constructed = conductAnalysis(reduced);
const newInstructions = [];
let summedUpLength = 0;
for (const segment of constructed) {
for (const instructionAndInfo of segment.instructionsAndInfo) {
if (summedUpLength + instructionAndInfo.length > length2) {
const remainingLength = length2 - summedUpLength;
const progress = remainingLength / instructionAndInfo.length;
const cut = cutInstruction({
instruction: instructionAndInfo.instruction,
lastPoint: instructionAndInfo.startPoint,
progress
});
newInstructions.push(cut);
return serializeInstructions(newInstructions);
}
summedUpLength += instructionAndInfo.length;
newInstructions.push(instructionAndInfo.instruction);
if (summedUpLength === length2) {
return serializeInstructions(newInstructions);
}
}
}
return serializeInstructions(newInstructions);
};
// src/debug-path.ts
var debugPath = (d) => {
const instructions = normalizeInstructions(parsePath(d));
return instructions.map((inst, i) => {
if (inst.type === "Z") {
return null;
}
if (inst.type === "H" || inst.type === "V") {
return null;
}
const topLeft = [inst.x - 5, inst.y - 5];
const topRight = [inst.x + 5, inst.y - 5];
const bottomLeft = [inst.x - 5, inst.y + 5];
const bottomRight = [inst.x + 5, inst.y + 5];
const triangle = [
{
type: "M",
x: topLeft[0],
y: topLeft[1]
},
{
type: "L",
x: topRight[0],
y: topRight[1]
},
{
type: "L",
x: bottomRight[0],
y: bottomRight[1]
},
{
type: "L",
x: bottomLeft[0],
y: bottomLeft[1]
},
{
type: "Z"
}
];
return {
d: serializeInstructions(triangle),
color: i === instructions.length - 1 ? "red" : inst.type === "M" ? "blue" : "green"
};
}).filter(Boolean);
};
// src/get-bounding-box.ts
var CBEZIER_MINMAX_EPSILON = 0.00000001;
function minmaxQ(A) {
const min = Math.min(A[0], A[2]);
const max = Math.max(A[0], A[2]);
if (A[1]