@weasel-js/geom 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -16
- package/dist/booleans/index.d.ts +22 -3
- package/dist/booleans/index.js +41 -2
- package/dist/booleans/index.js.map +1 -1
- package/dist/{chunk-MDT7F32A.js → chunk-7WFFCHRL.js} +7 -5
- package/dist/chunk-7WFFCHRL.js.map +1 -0
- package/dist/{chunk-WQMYOCFB.js → chunk-IDXY2NCA.js} +24 -14
- package/dist/chunk-IDXY2NCA.js.map +1 -0
- package/dist/chunk-NJ3IGAKR.js +16 -0
- package/dist/chunk-NJ3IGAKR.js.map +1 -0
- package/dist/cubicMath-BW-HJrCE.d.ts +16 -0
- package/dist/curves/index.d.ts +1 -1
- package/dist/curves/index.js +1 -1
- package/dist/index.d.ts +516 -208
- package/dist/index.js +1184 -541
- package/dist/index.js.map +1 -1
- package/dist/{path-Bf9KeVxC.d.ts → path-ljHxobyu.d.ts} +1 -1
- package/dist/tessellate/index.d.ts +4 -1
- package/dist/tessellate/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-MDT7F32A.js.map +0 -1
- package/dist/chunk-WQMYOCFB.js.map +0 -1
- package/dist/chunk-XS6ERH3X.js +0 -34
- package/dist/chunk-XS6ERH3X.js.map +0 -1
- package/dist/cubicMath-CFXbq6vp.d.ts +0 -116
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { PORT_REACH, portControls, portCurvePoints } from './chunk-YQADYJJ7.js';
|
|
2
2
|
export { PORT_REACH } from './chunk-YQADYJJ7.js';
|
|
3
|
-
import { cubicPointAt, splitCubicAtT
|
|
4
|
-
export { cubicPointAt,
|
|
3
|
+
import { cubicPointAt, splitCubicAtT } from './chunk-NJ3IGAKR.js';
|
|
4
|
+
export { cubicPointAt, splitCubicAtT } from './chunk-NJ3IGAKR.js';
|
|
5
5
|
import { cubicEvalAt, elevateQuadraticToCubic, cubicBounds } from './chunk-URQMDR6Q.js';
|
|
6
6
|
export { cubicBounds, cubicEvalAt, elevateQuadraticToCubic, quadraticEvalAt, splitCubicAt, splitLineAt, splitQuadraticAt } from './chunk-URQMDR6Q.js';
|
|
7
|
-
import { extractPolylines, rectToContour } from './chunk-
|
|
8
|
-
export { boundsOfCoords, boxContainsBox, boxContainsPoint, rectToContour, unionBox } from './chunk-
|
|
9
|
-
import { fillsOpenSubpaths, pointInPolygon, pointSegmentDist2, flattenQuadratic, flattenCubic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-
|
|
10
|
-
export { DEFAULT_FLATTEN_TOLERANCE, defaultOpenFill, fillsOpenSubpaths, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pointInPolygon, pointSegmentDist2, segmentsCross, setDefaultOpenFill } from './chunk-
|
|
7
|
+
import { extractPolylines, rectToContour } from './chunk-7WFFCHRL.js';
|
|
8
|
+
export { boundsOfCoords, boxContainsBox, boxContainsPoint, rectToContour, unionBox } from './chunk-7WFFCHRL.js';
|
|
9
|
+
import { fillsOpenSubpaths, pointInPolygon, pointSegmentDist2, flattenQuadratic, flattenCubic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-IDXY2NCA.js';
|
|
10
|
+
export { DEFAULT_FLATTEN_TOLERANCE, defaultOpenFill, fillsOpenSubpaths, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pointInPolygon, pointSegmentDist2, segmentsCross, setDefaultOpenFill } from './chunk-IDXY2NCA.js';
|
|
11
11
|
import { SINGULAR_RATIO } from './chunk-755Y4YZS.js';
|
|
12
12
|
export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-755Y4YZS.js';
|
|
13
13
|
import { forEachSegment, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z, pathCommandCoordCount } from './chunk-OXH3NOXC.js';
|
|
@@ -19,7 +19,7 @@ function normalizeZoom(zoom) {
|
|
|
19
19
|
return zoom >= ZOOM_FLOOR && zoom < Infinity ? zoom : ZOOM_FLOOR;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
// src/
|
|
22
|
+
// src/affine.ts
|
|
23
23
|
function identity() {
|
|
24
24
|
return [1, 0, 0, 1, 0, 0];
|
|
25
25
|
}
|
|
@@ -66,6 +66,16 @@ function boxToBox(sx, sy, sw, sh, dx, dy, dw, dh) {
|
|
|
66
66
|
function rotateAboutPoint(cx, cy, rad) {
|
|
67
67
|
return multiply(translate(cx, cy), multiply(rotate(rad), translate(-cx, -cy)));
|
|
68
68
|
}
|
|
69
|
+
function transformCoords(coords, m) {
|
|
70
|
+
const out = new Float64Array(coords.length);
|
|
71
|
+
const a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
|
|
72
|
+
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
73
|
+
const x = coords[i], y = coords[i + 1];
|
|
74
|
+
out[i] = a * x + c * y + e;
|
|
75
|
+
out[i + 1] = b * x + d * y + f;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
69
79
|
|
|
70
80
|
// src/nearest.ts
|
|
71
81
|
function nearestOnLine(px, py, x0, y0, x1, y1) {
|
|
@@ -397,18 +407,6 @@ function unionBoundsPath(paths) {
|
|
|
397
407
|
return { kind: "rect", x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
398
408
|
}
|
|
399
409
|
|
|
400
|
-
// src/affine.ts
|
|
401
|
-
function transformCoords(coords, m) {
|
|
402
|
-
const out = new Float64Array(coords.length);
|
|
403
|
-
const a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
|
|
404
|
-
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
405
|
-
const x = coords[i], y = coords[i + 1];
|
|
406
|
-
out[i] = a * x + c * y + e;
|
|
407
|
-
out[i + 1] = b * x + d * y + f;
|
|
408
|
-
}
|
|
409
|
-
return out;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
410
|
// src/paths/transformPath.ts
|
|
413
411
|
var AXIS_ALIGNED_EPSILON = 1e-9;
|
|
414
412
|
function transformPath(path, m) {
|
|
@@ -1078,15 +1076,26 @@ function measureError(samples, fit) {
|
|
|
1078
1076
|
return { worstIndex, worstError };
|
|
1079
1077
|
}
|
|
1080
1078
|
function fitOneCubic(samples) {
|
|
1079
|
+
const n = samples.length;
|
|
1080
|
+
return fitWithTangents(
|
|
1081
|
+
samples,
|
|
1082
|
+
unit(sub2(samples[1], samples[0])),
|
|
1083
|
+
unit(sub2(samples[n - 2], samples[n - 1])),
|
|
1084
|
+
4
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
function fitCubicWithTangents(samples, tStart, tEnd, opts = {}) {
|
|
1088
|
+
const { cp1, cp2 } = fitWithTangents(samples, tStart, tEnd, opts.passes ?? 4, opts.params);
|
|
1089
|
+
return { cp1, cp2 };
|
|
1090
|
+
}
|
|
1091
|
+
function fitWithTangents(samples, tStart, tEnd, passes, params) {
|
|
1081
1092
|
const n = samples.length;
|
|
1082
1093
|
const a = samples[0];
|
|
1083
1094
|
const e = samples[n - 1];
|
|
1084
|
-
const
|
|
1085
|
-
const tEnd = unit(sub2(samples[n - 2], e));
|
|
1086
|
-
const ts = chordLengthParam(samples);
|
|
1095
|
+
const ts = params ? [...params] : chordLengthParam(samples);
|
|
1087
1096
|
if (ts === null) return { cp1: { ...a }, cp2: { ...e }, end: e, ts: samples.map(() => 0) };
|
|
1088
1097
|
let fit = solveLS(samples, ts, a, e, tStart, tEnd);
|
|
1089
|
-
for (let pass = 0; pass <
|
|
1098
|
+
for (let pass = 0; pass < passes; pass++) {
|
|
1090
1099
|
reparameterize(samples, ts, a, e, fit);
|
|
1091
1100
|
fit = solveLS(samples, ts, a, e, tStart, tEnd);
|
|
1092
1101
|
}
|
|
@@ -1189,127 +1198,920 @@ function emitStraightCubic(b, a, c) {
|
|
|
1189
1198
|
b.curveTo(cp1x, cp1y, cp2x, cp2y, c.x, c.y);
|
|
1190
1199
|
}
|
|
1191
1200
|
|
|
1192
|
-
// src/
|
|
1193
|
-
|
|
1201
|
+
// src/paths/spanFit.ts
|
|
1202
|
+
var SAMPLES_PER_SEGMENT = 16;
|
|
1203
|
+
var SPLIT_SEARCH_STEPS = 40;
|
|
1204
|
+
function fitCubicThroughDeletion(prev, removed, next) {
|
|
1205
|
+
const first = segmentControls(prev, removed);
|
|
1206
|
+
const second = segmentControls(removed, next);
|
|
1207
|
+
const samples = [...sampleCubic(first), ...sampleCubic(second).slice(1)];
|
|
1208
|
+
const tStart = startTangent(first);
|
|
1209
|
+
const tEnd = startTangent(reversed(second));
|
|
1210
|
+
const fitAt = (s) => {
|
|
1211
|
+
const params = splitParams(s);
|
|
1212
|
+
const fit = fitCubicWithTangents(samples, tStart, tEnd, { params, passes: 0 });
|
|
1213
|
+
return { fit, error: squaredError(samples, params, prev, fit.cp1, fit.cp2, next) };
|
|
1214
|
+
};
|
|
1215
|
+
let lo = 0.02;
|
|
1216
|
+
let hi = 0.98;
|
|
1217
|
+
const phi = (Math.sqrt(5) - 1) / 2;
|
|
1218
|
+
let m1 = hi - phi * (hi - lo);
|
|
1219
|
+
let m2 = lo + phi * (hi - lo);
|
|
1220
|
+
let e1 = fitAt(m1).error;
|
|
1221
|
+
let e2 = fitAt(m2).error;
|
|
1222
|
+
for (let i = 0; i < SPLIT_SEARCH_STEPS; i++) {
|
|
1223
|
+
if (e1 < e2) {
|
|
1224
|
+
hi = m2;
|
|
1225
|
+
m2 = m1;
|
|
1226
|
+
e2 = e1;
|
|
1227
|
+
m1 = hi - phi * (hi - lo);
|
|
1228
|
+
e1 = fitAt(m1).error;
|
|
1229
|
+
} else {
|
|
1230
|
+
lo = m1;
|
|
1231
|
+
m1 = m2;
|
|
1232
|
+
e1 = e2;
|
|
1233
|
+
m2 = lo + phi * (hi - lo);
|
|
1234
|
+
e2 = fitAt(m2).error;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
const { cp1, cp2 } = fitCubicWithTangents(samples, tStart, tEnd, {
|
|
1238
|
+
params: splitParams((lo + hi) / 2)
|
|
1239
|
+
});
|
|
1240
|
+
return { c1: cp1, c2: cp2 };
|
|
1241
|
+
}
|
|
1242
|
+
function splitParams(s) {
|
|
1243
|
+
const out = [];
|
|
1244
|
+
for (let i = 0; i <= SAMPLES_PER_SEGMENT; i++) out.push(s * i / SAMPLES_PER_SEGMENT);
|
|
1245
|
+
for (let i = 1; i <= SAMPLES_PER_SEGMENT; i++) out.push(s + (1 - s) * i / SAMPLES_PER_SEGMENT);
|
|
1246
|
+
return out;
|
|
1247
|
+
}
|
|
1248
|
+
function squaredError(samples, params, p0, p1, p2, p3) {
|
|
1249
|
+
let sum = 0;
|
|
1250
|
+
for (let i = 0; i < samples.length; i++) {
|
|
1251
|
+
const q = cubicPointAt(p0, p1, p2, p3, params[i]);
|
|
1252
|
+
sum += (q.x - samples[i].x) ** 2 + (q.y - samples[i].y) ** 2;
|
|
1253
|
+
}
|
|
1254
|
+
return sum;
|
|
1255
|
+
}
|
|
1256
|
+
function segmentControls(a, b) {
|
|
1257
|
+
return [
|
|
1258
|
+
{ x: a.x, y: a.y },
|
|
1259
|
+
a.outHandle ?? { x: a.x, y: a.y },
|
|
1260
|
+
b.inHandle ?? { x: b.x, y: b.y },
|
|
1261
|
+
{ x: b.x, y: b.y }
|
|
1262
|
+
];
|
|
1263
|
+
}
|
|
1264
|
+
function sampleCubic([p0, p1, p2, p3]) {
|
|
1265
|
+
const out = [];
|
|
1266
|
+
for (let i = 0; i <= SAMPLES_PER_SEGMENT; i++) {
|
|
1267
|
+
out.push(cubicPointAt(p0, p1, p2, p3, i / SAMPLES_PER_SEGMENT));
|
|
1268
|
+
}
|
|
1269
|
+
return out;
|
|
1270
|
+
}
|
|
1271
|
+
function reversed([p0, p1, p2, p3]) {
|
|
1272
|
+
return [p3, p2, p1, p0];
|
|
1273
|
+
}
|
|
1274
|
+
function startTangent([p0, ...rest]) {
|
|
1275
|
+
for (const p of rest) {
|
|
1276
|
+
const dx = p.x - p0.x;
|
|
1277
|
+
const dy = p.y - p0.y;
|
|
1278
|
+
const len = Math.hypot(dx, dy);
|
|
1279
|
+
if (len > 1e-9) return { x: dx / len, y: dy / len };
|
|
1280
|
+
}
|
|
1281
|
+
return { x: 0, y: 0 };
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// src/paths/anchors.ts
|
|
1285
|
+
function pathToAnchors(path) {
|
|
1194
1286
|
const { commands, coords } = path;
|
|
1287
|
+
const anchors = [];
|
|
1195
1288
|
const closed = [];
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
forEachSegment(commands, coords, (cmd, ci, curX, curY, _i, opensSubpath) => {
|
|
1199
|
-
if (opensSubpath) sub3 = [curX, curY];
|
|
1289
|
+
let current = null;
|
|
1290
|
+
forEachSegment(commands, coords, (cmd, ci) => {
|
|
1200
1291
|
switch (cmd) {
|
|
1201
|
-
case PATH_M:
|
|
1202
|
-
if (
|
|
1203
|
-
|
|
1292
|
+
case PATH_M: {
|
|
1293
|
+
if (current) {
|
|
1294
|
+
anchors.push(current);
|
|
1295
|
+
closed.push(false);
|
|
1296
|
+
}
|
|
1297
|
+
current = [{ x: coords[ci], y: coords[ci + 1] }];
|
|
1204
1298
|
break;
|
|
1205
|
-
|
|
1206
|
-
|
|
1299
|
+
}
|
|
1300
|
+
case PATH_L: {
|
|
1301
|
+
if (!current) throw new Error("pathToAnchors: L without prior M");
|
|
1302
|
+
current.push({ x: coords[ci], y: coords[ci + 1] });
|
|
1207
1303
|
break;
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
coords[ci +
|
|
1215
|
-
coords[ci +
|
|
1216
|
-
coords[ci +
|
|
1217
|
-
|
|
1218
|
-
tolerance,
|
|
1219
|
-
sub3
|
|
1220
|
-
);
|
|
1304
|
+
}
|
|
1305
|
+
case PATH_C: {
|
|
1306
|
+
if (!current) throw new Error("pathToAnchors: C without prior M");
|
|
1307
|
+
const prev = current[current.length - 1];
|
|
1308
|
+
prev.outHandle = { x: coords[ci], y: coords[ci + 1] };
|
|
1309
|
+
current.push({
|
|
1310
|
+
x: coords[ci + 4],
|
|
1311
|
+
y: coords[ci + 5],
|
|
1312
|
+
inHandle: { x: coords[ci + 2], y: coords[ci + 3] }
|
|
1313
|
+
});
|
|
1221
1314
|
break;
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
coords[ci + 3],
|
|
1230
|
-
tolerance,
|
|
1231
|
-
sub3
|
|
1232
|
-
);
|
|
1315
|
+
}
|
|
1316
|
+
case PATH_Q: {
|
|
1317
|
+
if (!current) throw new Error("pathToAnchors: Q without prior M");
|
|
1318
|
+
const handle = { x: coords[ci], y: coords[ci + 1] };
|
|
1319
|
+
const prev = current[current.length - 1];
|
|
1320
|
+
prev.outHandle = handle;
|
|
1321
|
+
current.push({ x: coords[ci + 2], y: coords[ci + 3], inHandle: { ...handle } });
|
|
1233
1322
|
break;
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1323
|
+
}
|
|
1324
|
+
case PATH_Z: {
|
|
1325
|
+
if (current) {
|
|
1326
|
+
foldClosingCurve(current);
|
|
1327
|
+
anchors.push(current);
|
|
1328
|
+
closed.push(true);
|
|
1329
|
+
current = null;
|
|
1330
|
+
}
|
|
1238
1331
|
break;
|
|
1332
|
+
}
|
|
1239
1333
|
default:
|
|
1240
|
-
throw new Error(`
|
|
1334
|
+
throw new Error(`pathToAnchors: unknown command ${cmd}`);
|
|
1241
1335
|
}
|
|
1242
1336
|
});
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (!fillsOpenSubpaths(path)) return flat;
|
|
1249
|
-
return {
|
|
1250
|
-
closed: [...flat.closed, ...flat.open.filter((sub3) => sub3.length >= 6)],
|
|
1251
|
-
open: flat.open.filter((sub3) => sub3.length < 6)
|
|
1252
|
-
};
|
|
1337
|
+
if (current) {
|
|
1338
|
+
anchors.push(current);
|
|
1339
|
+
closed.push(false);
|
|
1340
|
+
}
|
|
1341
|
+
return { anchors, closed };
|
|
1253
1342
|
}
|
|
1254
|
-
function
|
|
1255
|
-
|
|
1343
|
+
function foldClosingCurve(sub3) {
|
|
1344
|
+
if (sub3.length < 2) return;
|
|
1345
|
+
const first = sub3[0];
|
|
1346
|
+
const last = sub3[sub3.length - 1];
|
|
1347
|
+
if (!last.inHandle || last.x !== first.x || last.y !== first.y) return;
|
|
1348
|
+
sub3.pop();
|
|
1349
|
+
first.inHandle = last.inHandle;
|
|
1256
1350
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1351
|
+
function anchorsToPath(anchors, closed, like) {
|
|
1352
|
+
const b = new PathBuilder();
|
|
1353
|
+
for (let s = 0; s < anchors.length; s++) {
|
|
1354
|
+
const sub3 = anchors[s];
|
|
1355
|
+
if (sub3.length === 0) continue;
|
|
1356
|
+
b.moveTo(sub3[0].x, sub3[0].y);
|
|
1357
|
+
for (let i = 1; i < sub3.length; i++) {
|
|
1358
|
+
const prev = sub3[i - 1];
|
|
1359
|
+
const cur = sub3[i];
|
|
1360
|
+
const hasHandle = prev.outHandle != null || cur.inHandle != null;
|
|
1361
|
+
if (!hasHandle) {
|
|
1362
|
+
b.lineTo(cur.x, cur.y);
|
|
1363
|
+
} else {
|
|
1364
|
+
const c1 = prev.outHandle ?? { x: prev.x, y: prev.y };
|
|
1365
|
+
const c2 = cur.inHandle ?? { x: cur.x, y: cur.y };
|
|
1366
|
+
b.curveTo(c1.x, c1.y, c2.x, c2.y, cur.x, cur.y);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (closed[s]) {
|
|
1370
|
+
const last = sub3[sub3.length - 1];
|
|
1371
|
+
const first = sub3[0];
|
|
1372
|
+
const hasHandle = last.outHandle != null || first.inHandle != null;
|
|
1373
|
+
if (hasHandle) {
|
|
1374
|
+
const c1 = last.outHandle ?? { x: last.x, y: last.y };
|
|
1375
|
+
const c2 = first.inHandle ?? { x: first.x, y: first.y };
|
|
1376
|
+
b.curveTo(c1.x, c1.y, c2.x, c2.y, first.x, first.y);
|
|
1377
|
+
}
|
|
1378
|
+
b.close();
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const built = b.build();
|
|
1382
|
+
return like ? { ...like, commands: built.commands, coords: built.coords } : built;
|
|
1268
1383
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1384
|
+
var SMOOTH_THRESHOLD = 1e-3;
|
|
1385
|
+
function isAnchorSmooth(a) {
|
|
1386
|
+
if (!a.inHandle || !a.outHandle) return false;
|
|
1387
|
+
const inDX = a.inHandle.x - a.x;
|
|
1388
|
+
const inDY = a.inHandle.y - a.y;
|
|
1389
|
+
const outDX = a.outHandle.x - a.x;
|
|
1390
|
+
const outDY = a.outHandle.y - a.y;
|
|
1391
|
+
const inLen = Math.hypot(inDX, inDY);
|
|
1392
|
+
const outLen = Math.hypot(outDX, outDY);
|
|
1393
|
+
if (inLen === 0 || outLen === 0) return false;
|
|
1394
|
+
const cross2 = (inDX * outDY - inDY * outDX) / (inLen * outLen);
|
|
1395
|
+
return Math.abs(cross2) < SMOOTH_THRESHOLD;
|
|
1271
1396
|
}
|
|
1272
|
-
function
|
|
1273
|
-
|
|
1274
|
-
const
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
const reach = slop + r * st.s1;
|
|
1280
|
-
if (dCenter2 > reach * reach) return false;
|
|
1281
|
-
const wx = bx - ax, wy = by - ay;
|
|
1282
|
-
const wl = Math.hypot(wx, wy);
|
|
1283
|
-
if (wl > 0) {
|
|
1284
|
-
const nx = -wy / wl * r, ny = wx / wl * r;
|
|
1285
|
-
const ox = m.a * nx + m.c * ny, oy = m.b * nx + m.d * ny;
|
|
1286
|
-
if (quadWithinPx(px0, py0, [
|
|
1287
|
-
sax + ox,
|
|
1288
|
-
say + oy,
|
|
1289
|
-
sbx + ox,
|
|
1290
|
-
sby + oy,
|
|
1291
|
-
sbx - ox,
|
|
1292
|
-
sby - oy,
|
|
1293
|
-
sax - ox,
|
|
1294
|
-
say - oy
|
|
1295
|
-
], slop2)) return true;
|
|
1397
|
+
function countPathAnchors(path) {
|
|
1398
|
+
if (path.kind === "rect") return 4;
|
|
1399
|
+
const cmds = path.commands;
|
|
1400
|
+
let n = 0;
|
|
1401
|
+
for (let i = 0; i < cmds.length; i++) {
|
|
1402
|
+
const c = cmds[i];
|
|
1403
|
+
if (c === PATH_M || c === PATH_L || c === PATH_C || c === PATH_Q) n++;
|
|
1296
1404
|
}
|
|
1297
|
-
return
|
|
1405
|
+
return n;
|
|
1298
1406
|
}
|
|
1299
|
-
function
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1407
|
+
function segmentEnds(anchors, closed, sub3, segIdx) {
|
|
1408
|
+
const s = anchors[sub3];
|
|
1409
|
+
if (!s || segIdx < 0) return null;
|
|
1410
|
+
if (segIdx + 1 < s.length) return { a: s[segIdx], b: s[segIdx + 1] };
|
|
1411
|
+
if (closed?.[sub3] && s.length > 1 && segIdx === s.length - 1) return { a: s[segIdx], b: s[0] };
|
|
1412
|
+
return null;
|
|
1413
|
+
}
|
|
1414
|
+
function isStraightSegment(a, b) {
|
|
1415
|
+
return a.outHandle == null && b.inHandle == null;
|
|
1416
|
+
}
|
|
1417
|
+
function nearestOnSegment(a, b, x, y) {
|
|
1418
|
+
const p1 = a.outHandle ?? a;
|
|
1419
|
+
const p2 = b.inHandle ?? b;
|
|
1420
|
+
const hit = isStraightSegment(a, b) ? nearestOnLine(x, y, a.x, a.y, b.x, b.y) : nearestOnCubic(x, y, a.x, a.y, p1.x, p1.y, p2.x, p2.y, b.x, b.y);
|
|
1421
|
+
return { t: hit.t, d2: hit.dist * hit.dist };
|
|
1422
|
+
}
|
|
1423
|
+
function nearestSegmentT(anchors, wx, wy, closed) {
|
|
1424
|
+
let bestD2 = Infinity;
|
|
1425
|
+
let best = null;
|
|
1426
|
+
for (let s = 0; s < anchors.length; s++) {
|
|
1427
|
+
const segCount = anchors[s].length - (closed?.[s] ? 0 : 1);
|
|
1428
|
+
for (let i = 0; i < segCount; i++) {
|
|
1429
|
+
const ends = segmentEnds(anchors, closed, s, i);
|
|
1430
|
+
if (!ends) continue;
|
|
1431
|
+
const hit = nearestOnSegment(ends.a, ends.b, wx, wy);
|
|
1432
|
+
if (hit.d2 < bestD2) {
|
|
1433
|
+
bestD2 = hit.d2;
|
|
1434
|
+
best = { sub: s, segIdx: i, t: hit.t };
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return best;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
// src/paths/simplifyPath.ts
|
|
1442
|
+
var CUBIC_SAMPLES2 = 12;
|
|
1443
|
+
var MAX_LINE_SAMPLES = 8;
|
|
1444
|
+
var LONG_STRAIGHT = 4;
|
|
1445
|
+
function simplifyPath(path, tolerance, opts = {}) {
|
|
1446
|
+
const tol = Math.max(tolerance, 1e-6);
|
|
1447
|
+
const cosCorner = Math.cos((opts.cornerAngle ?? 40) * Math.PI / 180);
|
|
1448
|
+
const { anchors, closed } = pathToAnchors(path);
|
|
1449
|
+
const out = [];
|
|
1450
|
+
const outClosed = [];
|
|
1451
|
+
anchors.forEach((sub3, s) => {
|
|
1452
|
+
if (sub3.length < 2) return;
|
|
1453
|
+
out.push(simplifySubpath(sub3, closed[s], tol, cosCorner));
|
|
1454
|
+
outClosed.push(closed[s]);
|
|
1455
|
+
});
|
|
1456
|
+
return anchorsToPath(out, outClosed, path);
|
|
1457
|
+
}
|
|
1458
|
+
function simplifySubpath(sub3, closed, tol, cosCorner) {
|
|
1459
|
+
const n = sub3.length;
|
|
1460
|
+
const breaks = /* @__PURE__ */ new Set();
|
|
1461
|
+
for (let i = 0; i < n; i++) {
|
|
1462
|
+
if (isCorner(sub3, i, closed, cosCorner)) breaks.add(i);
|
|
1463
|
+
if (isLongStraight(sub3, i, closed)) {
|
|
1464
|
+
breaks.add(i);
|
|
1465
|
+
breaks.add((i + 1) % n);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
const corners = [...breaks].sort((a, b) => a - b);
|
|
1469
|
+
const result = [];
|
|
1470
|
+
if (closed && corners.length === 0) {
|
|
1471
|
+
const pts = sampleRun(sub3, 0, n, tol);
|
|
1472
|
+
const t = unit2(sub22(pts[1], pts[pts.length - 2]));
|
|
1473
|
+
fitRun(pts, t, neg(t), tol, result, true);
|
|
1474
|
+
return result;
|
|
1475
|
+
}
|
|
1476
|
+
const stops = closed ? [...corners, corners[0] + n] : corners;
|
|
1477
|
+
for (let k = 0; k + 1 < stops.length; k++) {
|
|
1478
|
+
const pts = sampleRun(sub3, stops[k], stops[k + 1], tol);
|
|
1479
|
+
const last = closed && k + 2 === stops.length;
|
|
1480
|
+
fitRun(pts, unit2(sub22(pts[1], pts[0])), unit2(sub22(pts[pts.length - 2], pts[pts.length - 1])), tol, result, last);
|
|
1481
|
+
}
|
|
1482
|
+
return result;
|
|
1483
|
+
}
|
|
1484
|
+
function isCorner(sub3, i, closed, cosCorner) {
|
|
1485
|
+
const n = sub3.length;
|
|
1486
|
+
const a = sub3[i];
|
|
1487
|
+
const prev = sub3[(i - 1 + n) % n];
|
|
1488
|
+
const next = sub3[(i + 1) % n];
|
|
1489
|
+
if (!closed && (i === 0 || i === n - 1)) return true;
|
|
1490
|
+
const from = a.inHandle && !same(a.inHandle, a) ? a.inHandle : prev.outHandle && !same(prev.outHandle, a) ? prev.outHandle : prev;
|
|
1491
|
+
const to = a.outHandle && !same(a.outHandle, a) ? a.outHandle : next.inHandle && !same(next.inHandle, a) ? next.inHandle : next;
|
|
1492
|
+
const d1 = unit2(sub22(a, from));
|
|
1493
|
+
const d2 = unit2(sub22(to, a));
|
|
1494
|
+
return d1.x * d2.x + d1.y * d2.y < cosCorner;
|
|
1495
|
+
}
|
|
1496
|
+
function isLongStraight(sub3, i, closed) {
|
|
1497
|
+
const n = sub3.length;
|
|
1498
|
+
const len = (k) => {
|
|
1499
|
+
if (!closed && (k < 0 || k >= n - 1)) return 0;
|
|
1500
|
+
const a2 = sub3[(k + n) % n];
|
|
1501
|
+
const b2 = sub3[(k + 1) % n];
|
|
1502
|
+
return Math.hypot(b2.x - a2.x, b2.y - a2.y);
|
|
1503
|
+
};
|
|
1504
|
+
if (!closed && i >= n - 1) return false;
|
|
1505
|
+
const a = sub3[i];
|
|
1506
|
+
const b = sub3[(i + 1) % n];
|
|
1507
|
+
if (a.outHandle || b.inHandle) return false;
|
|
1508
|
+
return len(i) >= LONG_STRAIGHT * Math.max(len(i - 1), len(i + 1));
|
|
1509
|
+
}
|
|
1510
|
+
function sampleRun(sub3, from, to, tol) {
|
|
1511
|
+
const n = sub3.length;
|
|
1512
|
+
const pts = [{ x: sub3[from % n].x, y: sub3[from % n].y }];
|
|
1513
|
+
for (let i = from; i < to; i++) {
|
|
1514
|
+
const a = sub3[i % n];
|
|
1515
|
+
const b = sub3[(i + 1) % n];
|
|
1516
|
+
if (!a.outHandle && !b.inHandle) {
|
|
1517
|
+
const len = Math.hypot(b.x - a.x, b.y - a.y);
|
|
1518
|
+
const steps = Math.min(MAX_LINE_SAMPLES, Math.max(1, Math.floor(len / (4 * tol))));
|
|
1519
|
+
for (let k = 1; k <= steps; k++) pts.push({ x: a.x + (b.x - a.x) * k / steps, y: a.y + (b.y - a.y) * k / steps });
|
|
1520
|
+
} else {
|
|
1521
|
+
const c1 = a.outHandle ?? a;
|
|
1522
|
+
const c2 = b.inHandle ?? b;
|
|
1523
|
+
for (let k = 1; k <= CUBIC_SAMPLES2; k++) pts.push(cubicPointAt(a, c1, c2, b, k / CUBIC_SAMPLES2));
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
return dedupe(pts);
|
|
1527
|
+
}
|
|
1528
|
+
function fitRun(pts, tStart, tEnd, tol, out, closing) {
|
|
1529
|
+
if (out.length === 0) out.push({ x: pts[0].x, y: pts[0].y });
|
|
1530
|
+
const segs = [];
|
|
1531
|
+
fitRecursive2(pts, tStart, tEnd, tol, segs);
|
|
1532
|
+
segs.forEach((seg, i) => {
|
|
1533
|
+
const prev = out[out.length - 1];
|
|
1534
|
+
if (seg.c1) prev.outHandle = seg.c1;
|
|
1535
|
+
const isLast = i === segs.length - 1;
|
|
1536
|
+
if (closing && isLast) {
|
|
1537
|
+
if (seg.c2) out[0].inHandle = seg.c2;
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
out.push(seg.c2 ? { x: seg.end.x, y: seg.end.y, inHandle: seg.c2 } : { x: seg.end.x, y: seg.end.y });
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
function fitRecursive2(pts, tStart, tEnd, tol, out) {
|
|
1544
|
+
const a = pts[0];
|
|
1545
|
+
const e = pts[pts.length - 1];
|
|
1546
|
+
if (pts.length <= 2 || worstFromLine(pts, a, e).dist <= tol) {
|
|
1547
|
+
out.push({ end: e });
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const { cp1, cp2 } = fitCubicWithTangents(pts, tStart, tEnd);
|
|
1551
|
+
const worst = worstFromCubic(pts, a, cp1, cp2, e);
|
|
1552
|
+
if (worst.dist <= tol) {
|
|
1553
|
+
out.push({ c1: cp1, c2: cp2, end: e });
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
const k = worst.index;
|
|
1557
|
+
const center = unit2(sub22(pts[k + 1], pts[k - 1]));
|
|
1558
|
+
fitRecursive2(pts.slice(0, k + 1), tStart, neg(center), tol, out);
|
|
1559
|
+
fitRecursive2(pts.slice(k), center, tEnd, tol, out);
|
|
1560
|
+
}
|
|
1561
|
+
function worstFromLine(pts, a, e) {
|
|
1562
|
+
let index = 1, dist2 = 0;
|
|
1563
|
+
for (let i = 1; i < pts.length - 1; i++) {
|
|
1564
|
+
const d = nearestOnLine(pts[i].x, pts[i].y, a.x, a.y, e.x, e.y).dist;
|
|
1565
|
+
if (d > dist2) {
|
|
1566
|
+
dist2 = d;
|
|
1567
|
+
index = i;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
return { index, dist: dist2 };
|
|
1571
|
+
}
|
|
1572
|
+
function worstFromCubic(pts, a, c1, c2, e) {
|
|
1573
|
+
let index = 1, dist2 = 0;
|
|
1574
|
+
for (let i = 1; i < pts.length - 1; i++) {
|
|
1575
|
+
const d = nearestOnCubic(pts[i].x, pts[i].y, a.x, a.y, c1.x, c1.y, c2.x, c2.y, e.x, e.y).dist;
|
|
1576
|
+
if (d > dist2) {
|
|
1577
|
+
dist2 = d;
|
|
1578
|
+
index = i;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
return { index, dist: dist2 };
|
|
1582
|
+
}
|
|
1583
|
+
function dedupe(pts) {
|
|
1584
|
+
return pts.filter((p, i) => i === 0 || !same(p, pts[i - 1]));
|
|
1585
|
+
}
|
|
1586
|
+
var same = (p, q) => p.x === q.x && p.y === q.y;
|
|
1587
|
+
var sub22 = (p, q) => ({ x: p.x - q.x, y: p.y - q.y });
|
|
1588
|
+
var neg = (p) => ({ x: -p.x, y: -p.y });
|
|
1589
|
+
function unit2(p) {
|
|
1590
|
+
const len = Math.hypot(p.x, p.y);
|
|
1591
|
+
return len === 0 ? { x: 0, y: 0 } : { x: p.x / len, y: p.y / len };
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// src/pxExtent.ts
|
|
1595
|
+
function pxExtent(px, scale3, rotation = 0) {
|
|
1596
|
+
if (!rotation) {
|
|
1597
|
+
return {
|
|
1598
|
+
x: px / Math.abs(scale3.x),
|
|
1599
|
+
y: px / Math.abs(scale3.y)
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
const c = Math.cos(rotation), s = Math.sin(rotation);
|
|
1603
|
+
return {
|
|
1604
|
+
x: px * Math.hypot(c / scale3.x, s / scale3.y),
|
|
1605
|
+
y: px * Math.hypot(s / scale3.x, c / scale3.y)
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
function scaleDelta(dx, dy, scale3) {
|
|
1609
|
+
return { x: dx * scale3.x, y: dy * scale3.y };
|
|
1610
|
+
}
|
|
1611
|
+
function withinPxBox(dx, dy, px, scale3) {
|
|
1612
|
+
const s = scaleDelta(dx, dy, scale3);
|
|
1613
|
+
return Math.abs(s.x) <= px && Math.abs(s.y) <= px;
|
|
1614
|
+
}
|
|
1615
|
+
function withinPxRadius(dx, dy, px, scale3) {
|
|
1616
|
+
const s = scaleDelta(dx, dy, scale3);
|
|
1617
|
+
return s.x * s.x + s.y * s.y <= px * px;
|
|
1618
|
+
}
|
|
1619
|
+
function standoff(anchor, normal, px, scale3) {
|
|
1620
|
+
const k = Math.sign(scale3.x * scale3.y) || 1;
|
|
1621
|
+
let nx = normal.x * scale3.y * k;
|
|
1622
|
+
let ny = normal.y * scale3.x * k;
|
|
1623
|
+
const l = Math.hypot(nx, ny) || 1;
|
|
1624
|
+
nx /= l;
|
|
1625
|
+
ny /= l;
|
|
1626
|
+
return { x: anchor.x + nx * px / scale3.x, y: anchor.y + ny * px / scale3.y, nx, ny };
|
|
1627
|
+
}
|
|
1628
|
+
function screenAngleOf(rotation, scale3) {
|
|
1629
|
+
return Math.atan2(Math.sin(rotation) * scale3.y, Math.cos(rotation) * scale3.x);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// src/paths/anchorOrigins.ts
|
|
1633
|
+
var at = (x) => ({ x, y: x });
|
|
1634
|
+
var keyOf = (p) => `${p.x},${p.y}`;
|
|
1635
|
+
function heldBy(path, set) {
|
|
1636
|
+
const coords = new Float32Array(path.coords.length);
|
|
1637
|
+
for (let i = 0; i < coords.length; i++) coords[i] = i >> 1;
|
|
1638
|
+
const indexed = pathToAnchors({ ...path, coords }).anchors;
|
|
1639
|
+
return indexed.map((sub3, s) => {
|
|
1640
|
+
if (sub3.length === set.anchors[s].length + 1) sub3[0].inHandle = sub3.pop().inHandle;
|
|
1641
|
+
return sub3.map((a) => ({ point: a.x, in: a.inHandle?.x, out: a.outHandle?.x }));
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
function writtenFrom(set) {
|
|
1645
|
+
let flat = 0;
|
|
1646
|
+
const coded = set.anchors.map((sub3) => sub3.map((a) => {
|
|
1647
|
+
const k = 3 * flat++;
|
|
1648
|
+
return {
|
|
1649
|
+
...at(k),
|
|
1650
|
+
...a.inHandle ? { inHandle: at(k + 1) } : {},
|
|
1651
|
+
...a.outHandle ? { outHandle: at(k + 2) } : {}
|
|
1652
|
+
};
|
|
1653
|
+
}));
|
|
1654
|
+
return anchorsToPath(coded, set.closed).coords;
|
|
1655
|
+
}
|
|
1656
|
+
function neighbor(sub3, closed, i, step) {
|
|
1657
|
+
for (let n = 1; n < sub3.length; n++) {
|
|
1658
|
+
let j = i + step * n;
|
|
1659
|
+
if (j < 0 || j >= sub3.length) {
|
|
1660
|
+
if (!closed) return -1;
|
|
1661
|
+
j = (j + sub3.length) % sub3.length;
|
|
1662
|
+
}
|
|
1663
|
+
if (sub3[j]) return j;
|
|
1664
|
+
}
|
|
1665
|
+
return -1;
|
|
1666
|
+
}
|
|
1667
|
+
function blended(anchors, held, closed, i) {
|
|
1668
|
+
const p = neighbor(held, closed, i, -1);
|
|
1669
|
+
const n = neighbor(held, closed, i, 1);
|
|
1670
|
+
if (p === -1 && n === -1) return null;
|
|
1671
|
+
const a = held[p === -1 ? n : p].point;
|
|
1672
|
+
const b = held[n === -1 ? p : n].point;
|
|
1673
|
+
if (p === -1 || n === -1 || a === b) return { a, b: a, t: 0 };
|
|
1674
|
+
const dp = Math.hypot(anchors[i].x - anchors[p].x, anchors[i].y - anchors[p].y);
|
|
1675
|
+
const dn = Math.hypot(anchors[i].x - anchors[n].x, anchors[i].y - anchors[n].y);
|
|
1676
|
+
return { a, b, t: dp + dn > 0 ? dp / (dp + dn) : 0 };
|
|
1677
|
+
}
|
|
1678
|
+
function copied(anchor, byPlace) {
|
|
1679
|
+
const was = byPlace.get(keyOf(anchor));
|
|
1680
|
+
if (!was) return void 0;
|
|
1681
|
+
const handle = (h) => h ? byPlace.get(`${keyOf(anchor)}:${keyOf(h)}`)?.point : void 0;
|
|
1682
|
+
return { point: was.point, in: handle(anchor.inHandle), out: handle(anchor.outHandle) };
|
|
1683
|
+
}
|
|
1684
|
+
function editAnchorSetTracked(path, edit) {
|
|
1685
|
+
const set = pathToAnchors(path);
|
|
1686
|
+
const byAnchor = /* @__PURE__ */ new Map();
|
|
1687
|
+
const byPlace = /* @__PURE__ */ new Map();
|
|
1688
|
+
heldBy(path, set).forEach((sub3, s) => sub3.forEach((held2, i) => {
|
|
1689
|
+
const anchor = set.anchors[s][i];
|
|
1690
|
+
byAnchor.set(anchor, held2);
|
|
1691
|
+
if (byPlace.has(keyOf(anchor))) return;
|
|
1692
|
+
if (anchor.inHandle) byPlace.set(`${keyOf(anchor)}:${keyOf(anchor.inHandle)}`, { point: held2.in });
|
|
1693
|
+
if (anchor.outHandle) byPlace.set(`${keyOf(anchor)}:${keyOf(anchor.outHandle)}`, { point: held2.out });
|
|
1694
|
+
byPlace.set(keyOf(anchor), { point: held2.point });
|
|
1695
|
+
}));
|
|
1696
|
+
if (edit(set) === false) return null;
|
|
1697
|
+
const held = [];
|
|
1698
|
+
const own = [];
|
|
1699
|
+
set.anchors.forEach((sub3, s) => {
|
|
1700
|
+
const subHeld = sub3.map((a) => byAnchor.get(a) ?? copied(a, byPlace));
|
|
1701
|
+
sub3.forEach((_, i) => {
|
|
1702
|
+
const h = subHeld[i];
|
|
1703
|
+
held.push(h);
|
|
1704
|
+
own.push(h ? { a: h.point, b: h.point, t: 0 } : blended(sub3, subHeld, set.closed[s], i));
|
|
1705
|
+
});
|
|
1706
|
+
});
|
|
1707
|
+
const origins = Array.from(writtenFrom(set).filter((_, i) => i % 2 === 0), (code) => {
|
|
1708
|
+
const anchor = Math.floor(code / 3);
|
|
1709
|
+
const handle = code % 3 === 1 ? held[anchor]?.in : code % 3 === 2 ? held[anchor]?.out : void 0;
|
|
1710
|
+
return handle === void 0 ? own[anchor] : { a: handle, b: handle, t: 0 };
|
|
1711
|
+
});
|
|
1712
|
+
return { path: anchorsToPath(set.anchors, set.closed, path), origins };
|
|
1713
|
+
}
|
|
1714
|
+
function remapPointValues(values, origins) {
|
|
1715
|
+
return origins.map((o) => {
|
|
1716
|
+
if (!o) return 0;
|
|
1717
|
+
const a = values[o.a] ?? 0;
|
|
1718
|
+
return o.t === 0 ? a : a + ((values[o.b] ?? 0) - a) * o.t;
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/paths/anchorEdits.ts
|
|
1723
|
+
function anchorCount(set) {
|
|
1724
|
+
let n = 0;
|
|
1725
|
+
for (const sub3 of set.anchors) n += sub3.length;
|
|
1726
|
+
return n;
|
|
1727
|
+
}
|
|
1728
|
+
function locateAnchor(set, flatIndex) {
|
|
1729
|
+
if (flatIndex < 0) return null;
|
|
1730
|
+
let remaining = flatIndex;
|
|
1731
|
+
for (let sub3 = 0; sub3 < set.anchors.length; sub3++) {
|
|
1732
|
+
const len = set.anchors[sub3].length;
|
|
1733
|
+
if (remaining < len) return { sub: sub3, idx: remaining };
|
|
1734
|
+
remaining -= len;
|
|
1735
|
+
}
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1738
|
+
function flatAnchorIndex(set, sub3, idx) {
|
|
1739
|
+
if (sub3 < 0 || sub3 >= set.anchors.length) return -1;
|
|
1740
|
+
if (idx < 0 || idx >= set.anchors[sub3].length) return -1;
|
|
1741
|
+
let base = 0;
|
|
1742
|
+
for (let s = 0; s < sub3; s++) base += set.anchors[s].length;
|
|
1743
|
+
return base + idx;
|
|
1744
|
+
}
|
|
1745
|
+
function anchorAt(set, flatIndex) {
|
|
1746
|
+
const loc = locateAnchor(set, flatIndex);
|
|
1747
|
+
if (!loc) return null;
|
|
1748
|
+
return set.anchors[loc.sub][loc.idx] ?? null;
|
|
1749
|
+
}
|
|
1750
|
+
function editAnchorSet(path, edit) {
|
|
1751
|
+
return editAnchorSetTracked(path, edit)?.path ?? null;
|
|
1752
|
+
}
|
|
1753
|
+
function translateAnchorBy(set, flatIndex, dx, dy) {
|
|
1754
|
+
const a = anchorAt(set, flatIndex);
|
|
1755
|
+
if (!a) return false;
|
|
1756
|
+
a.x += dx;
|
|
1757
|
+
a.y += dy;
|
|
1758
|
+
if (a.inHandle) {
|
|
1759
|
+
a.inHandle.x += dx;
|
|
1760
|
+
a.inHandle.y += dy;
|
|
1761
|
+
}
|
|
1762
|
+
if (a.outHandle) {
|
|
1763
|
+
a.outHandle.x += dx;
|
|
1764
|
+
a.outHandle.y += dy;
|
|
1765
|
+
}
|
|
1766
|
+
return true;
|
|
1767
|
+
}
|
|
1768
|
+
function moveHandleTo(set, flatIndex, side, toX, toY, breakSmoothness) {
|
|
1769
|
+
const a = anchorAt(set, flatIndex);
|
|
1770
|
+
if (!a) return false;
|
|
1771
|
+
const wasSmooth = isAnchorSmooth(a);
|
|
1772
|
+
const target = { x: toX, y: toY };
|
|
1773
|
+
if (side === "out") a.outHandle = target;
|
|
1774
|
+
else a.inHandle = target;
|
|
1775
|
+
const oppositeSide = side === "out" ? "in" : "out";
|
|
1776
|
+
const opposite = oppositeSide === "in" ? a.inHandle : a.outHandle;
|
|
1777
|
+
if (!breakSmoothness && wasSmooth && opposite) {
|
|
1778
|
+
const mirrored = { x: 2 * a.x - target.x, y: 2 * a.y - target.y };
|
|
1779
|
+
if (oppositeSide === "in") a.inHandle = mirrored;
|
|
1780
|
+
else a.outHandle = mirrored;
|
|
1781
|
+
}
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1784
|
+
function insertAnchorOnSegment(set, args) {
|
|
1785
|
+
const ends = segmentEnds(set.anchors, set.closed, args.sub, args.segIdx);
|
|
1786
|
+
if (!ends) return -1;
|
|
1787
|
+
const { a, b } = ends;
|
|
1788
|
+
const at2 = args.segIdx + 1;
|
|
1789
|
+
if (isStraightSegment(a, b)) {
|
|
1790
|
+
set.anchors[args.sub].splice(at2, 0, {
|
|
1791
|
+
x: a.x + (b.x - a.x) * args.t,
|
|
1792
|
+
y: a.y + (b.y - a.y) * args.t
|
|
1793
|
+
});
|
|
1794
|
+
return flatAnchorIndex(set, args.sub, at2);
|
|
1795
|
+
}
|
|
1796
|
+
const p0 = a, p1 = a.outHandle ?? a, p2 = b.inHandle ?? b, p3 = b;
|
|
1797
|
+
const { left, right } = splitCubicAtT(p0, p1, p2, p3, args.t);
|
|
1798
|
+
a.outHandle = { x: left[1].x, y: left[1].y };
|
|
1799
|
+
b.inHandle = { x: right[2].x, y: right[2].y };
|
|
1800
|
+
set.anchors[args.sub].splice(at2, 0, {
|
|
1801
|
+
x: left[3].x,
|
|
1802
|
+
y: left[3].y,
|
|
1803
|
+
inHandle: { x: left[2].x, y: left[2].y },
|
|
1804
|
+
outHandle: { x: right[1].x, y: right[1].y }
|
|
1805
|
+
});
|
|
1806
|
+
return flatAnchorIndex(set, args.sub, at2);
|
|
1807
|
+
}
|
|
1808
|
+
function segmentAt(set, x, y, opts) {
|
|
1809
|
+
const scale3 = opts.scale ?? { x: 1, y: 1 };
|
|
1810
|
+
const onScreen = (p) => ({ x: p.x * scale3.x, y: p.y * scale3.y });
|
|
1811
|
+
const screenAnchors = set.anchors.map((sub3) => sub3.map((a) => ({
|
|
1812
|
+
...onScreen(a),
|
|
1813
|
+
...a.inHandle ? { inHandle: onScreen(a.inHandle) } : {},
|
|
1814
|
+
...a.outHandle ? { outHandle: onScreen(a.outHandle) } : {}
|
|
1815
|
+
})));
|
|
1816
|
+
const hit = nearestSegmentT(screenAnchors, x * scale3.x, y * scale3.y, set.closed);
|
|
1817
|
+
if (!hit) return null;
|
|
1818
|
+
const ends = segmentEnds(set.anchors, set.closed, hit.sub, hit.segIdx);
|
|
1819
|
+
const point = pointOnSegment(ends.a, ends.b, hit.t);
|
|
1820
|
+
const tol = opts.tolerancePx;
|
|
1821
|
+
if (!withinPxRadius(point.x - x, point.y - y, tol, scale3)) return null;
|
|
1822
|
+
if (withinPxRadius(point.x - ends.a.x, point.y - ends.a.y, tol, scale3)) return null;
|
|
1823
|
+
if (withinPxRadius(point.x - ends.b.x, point.y - ends.b.y, tol, scale3)) return null;
|
|
1824
|
+
return { sub: hit.sub, segIdx: hit.segIdx, t: hit.t, x: point.x, y: point.y };
|
|
1825
|
+
}
|
|
1826
|
+
function pointOnSegment(a, b, t) {
|
|
1827
|
+
if (isStraightSegment(a, b)) return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
1828
|
+
return cubicPointAt(a, a.outHandle ?? a, b.inHandle ?? b, b, t);
|
|
1829
|
+
}
|
|
1830
|
+
function deleteAnchorsAt(set, flatIndexes) {
|
|
1831
|
+
const bySub = /* @__PURE__ */ new Map();
|
|
1832
|
+
for (const flat of new Set(flatIndexes)) {
|
|
1833
|
+
const loc = locateAnchor(set, flat);
|
|
1834
|
+
if (!loc) continue;
|
|
1835
|
+
const list = bySub.get(loc.sub);
|
|
1836
|
+
if (list) list.push(loc.idx);
|
|
1837
|
+
else bySub.set(loc.sub, [loc.idx]);
|
|
1838
|
+
}
|
|
1839
|
+
if (bySub.size === 0) return false;
|
|
1840
|
+
let survivors = 0;
|
|
1841
|
+
for (let s = 0; s < set.anchors.length; s++) {
|
|
1842
|
+
const doomed = bySub.get(s)?.length ?? 0;
|
|
1843
|
+
if (set.anchors[s].length - doomed >= 2) survivors++;
|
|
1844
|
+
}
|
|
1845
|
+
if (survivors === 0) return false;
|
|
1846
|
+
for (const [s, indices] of bySub) {
|
|
1847
|
+
const sub3 = set.anchors[s];
|
|
1848
|
+
if (!sub3) continue;
|
|
1849
|
+
indices.sort((a, b) => b - a);
|
|
1850
|
+
for (const i of indices) {
|
|
1851
|
+
const wraps = set.closed[s] && sub3.length > 2;
|
|
1852
|
+
const prev = wraps ? sub3[(i - 1 + sub3.length) % sub3.length] : sub3[i - 1];
|
|
1853
|
+
const next = wraps ? sub3[(i + 1) % sub3.length] : sub3[i + 1];
|
|
1854
|
+
if (prev && next && !(isStraightSegment(prev, sub3[i]) && isStraightSegment(sub3[i], next))) {
|
|
1855
|
+
const { c1, c2 } = fitCubicThroughDeletion(prev, sub3[i], next);
|
|
1856
|
+
prev.outHandle = c1;
|
|
1857
|
+
next.inHandle = c2;
|
|
1858
|
+
}
|
|
1859
|
+
sub3.splice(i, 1);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
for (let s = set.anchors.length - 1; s >= 0; s--) {
|
|
1863
|
+
if (set.anchors[s].length < 2) {
|
|
1864
|
+
set.anchors.splice(s, 1);
|
|
1865
|
+
set.closed.splice(s, 1);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return true;
|
|
1869
|
+
}
|
|
1870
|
+
function openSubpathAt(set, flatIndex) {
|
|
1871
|
+
const loc = locateAnchor(set, flatIndex);
|
|
1872
|
+
if (!loc) return false;
|
|
1873
|
+
if (!set.closed[loc.sub]) return false;
|
|
1874
|
+
const sub3 = set.anchors[loc.sub];
|
|
1875
|
+
if (!sub3) return false;
|
|
1876
|
+
const { inHandle, ...start } = sub3[loc.idx];
|
|
1877
|
+
const end = { x: start.x, y: start.y, ...inHandle ? { inHandle } : {} };
|
|
1878
|
+
set.anchors[loc.sub] = [start, ...sub3.slice(loc.idx + 1), ...sub3.slice(0, loc.idx), end];
|
|
1879
|
+
set.closed[loc.sub] = false;
|
|
1880
|
+
return true;
|
|
1881
|
+
}
|
|
1882
|
+
function anchorsInRect(set, rect) {
|
|
1883
|
+
const x2 = rect.x + rect.width;
|
|
1884
|
+
const y2 = rect.y + rect.height;
|
|
1885
|
+
const hits = [];
|
|
1886
|
+
let flat = 0;
|
|
1887
|
+
for (const sub3 of set.anchors) {
|
|
1888
|
+
for (const a of sub3) {
|
|
1889
|
+
if (a.x >= rect.x && a.x <= x2 && a.y >= rect.y && a.y <= y2) hits.push(flat);
|
|
1890
|
+
flat++;
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
return hits;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// src/paths/joinAnchors.ts
|
|
1897
|
+
var COINCIDENT = 1e-6;
|
|
1898
|
+
function averageAnchorsAt(set, flatIndexes, axis = "both") {
|
|
1899
|
+
const picked = [];
|
|
1900
|
+
for (const flat of new Set(flatIndexes)) {
|
|
1901
|
+
const loc = locateAnchor(set, flat);
|
|
1902
|
+
if (loc) picked.push({ flat, a: set.anchors[loc.sub][loc.idx] });
|
|
1903
|
+
}
|
|
1904
|
+
if (picked.length < 2) return false;
|
|
1905
|
+
const mx = picked.reduce((s, p) => s + p.a.x, 0) / picked.length;
|
|
1906
|
+
const my = picked.reduce((s, p) => s + p.a.y, 0) / picked.length;
|
|
1907
|
+
for (const { flat, a } of picked) {
|
|
1908
|
+
translateAnchorBy(set, flat, axis === "y" ? 0 : mx - a.x, axis === "x" ? 0 : my - a.y);
|
|
1909
|
+
}
|
|
1910
|
+
return true;
|
|
1911
|
+
}
|
|
1912
|
+
function subpathEndAt(set, flatIndex) {
|
|
1913
|
+
const loc = locateAnchor(set, flatIndex);
|
|
1914
|
+
if (!loc || set.closed[loc.sub]) return null;
|
|
1915
|
+
const len = set.anchors[loc.sub].length;
|
|
1916
|
+
if (loc.idx === len - 1) return { sub: loc.sub, end: "last" };
|
|
1917
|
+
if (loc.idx === 0) return { sub: loc.sub, end: "first" };
|
|
1918
|
+
return null;
|
|
1919
|
+
}
|
|
1920
|
+
function joinSubpathEnds(set, a, b) {
|
|
1921
|
+
const subA = set.anchors[a.sub];
|
|
1922
|
+
const subB = set.anchors[b.sub];
|
|
1923
|
+
if (!subA || !subB || set.closed[a.sub] || set.closed[b.sub]) return false;
|
|
1924
|
+
if (a.sub === b.sub) {
|
|
1925
|
+
if (a.end === b.end || subA.length < 2) return false;
|
|
1926
|
+
const first = subA[0];
|
|
1927
|
+
const last = subA[subA.length - 1];
|
|
1928
|
+
if (coincide(first, last) && subA.length > 2) {
|
|
1929
|
+
if (last.inHandle) first.inHandle = last.inHandle;
|
|
1930
|
+
subA.pop();
|
|
1931
|
+
}
|
|
1932
|
+
set.closed[a.sub] = true;
|
|
1933
|
+
return true;
|
|
1934
|
+
}
|
|
1935
|
+
if (a.end === "first") reverseInPlace(subA);
|
|
1936
|
+
if (b.end === "last") reverseInPlace(subB);
|
|
1937
|
+
const tail = subA[subA.length - 1];
|
|
1938
|
+
const head = subB[0];
|
|
1939
|
+
let joined;
|
|
1940
|
+
if (coincide(tail, head)) {
|
|
1941
|
+
if (head.outHandle) tail.outHandle = head.outHandle;
|
|
1942
|
+
joined = [...subA, ...subB.slice(1)];
|
|
1943
|
+
} else {
|
|
1944
|
+
joined = [...subA, ...subB];
|
|
1945
|
+
}
|
|
1946
|
+
const keep = Math.min(a.sub, b.sub);
|
|
1947
|
+
const drop = Math.max(a.sub, b.sub);
|
|
1948
|
+
set.anchors[keep] = joined;
|
|
1949
|
+
set.anchors.splice(drop, 1);
|
|
1950
|
+
set.closed.splice(drop, 1);
|
|
1951
|
+
return true;
|
|
1952
|
+
}
|
|
1953
|
+
function joinAnchorsAt(set, flatA, flatB) {
|
|
1954
|
+
if (flatA === flatB) return false;
|
|
1955
|
+
const a = subpathEndAt(set, flatA);
|
|
1956
|
+
const b = subpathEndAt(set, flatB);
|
|
1957
|
+
if (!a || !b) return false;
|
|
1958
|
+
return joinSubpathEnds(set, a, b);
|
|
1959
|
+
}
|
|
1960
|
+
function closestOpenEnds(set, accept = () => true) {
|
|
1961
|
+
const ends = [];
|
|
1962
|
+
set.anchors.forEach((sub3, s) => {
|
|
1963
|
+
if (set.closed[s] || sub3.length < 2) return;
|
|
1964
|
+
ends.push({ end: { sub: s, end: "first" }, at: sub3[0] });
|
|
1965
|
+
ends.push({ end: { sub: s, end: "last" }, at: sub3[sub3.length - 1] });
|
|
1966
|
+
});
|
|
1967
|
+
let best = null;
|
|
1968
|
+
let bestD = Infinity;
|
|
1969
|
+
for (let i = 0; i < ends.length; i++) {
|
|
1970
|
+
for (let j = i + 1; j < ends.length; j++) {
|
|
1971
|
+
const p = ends[i], q = ends[j];
|
|
1972
|
+
if (p.end.sub === q.end.sub || !accept(p.end, q.end)) continue;
|
|
1973
|
+
const d = Math.hypot(p.at.x - q.at.x, p.at.y - q.at.y);
|
|
1974
|
+
if (d < bestD) {
|
|
1975
|
+
bestD = d;
|
|
1976
|
+
best = [p.end, q.end];
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
return best;
|
|
1981
|
+
}
|
|
1982
|
+
var coincide = (p, q) => Math.hypot(p.x - q.x, p.y - q.y) <= COINCIDENT;
|
|
1983
|
+
function reverseInPlace(sub3) {
|
|
1984
|
+
sub3.reverse();
|
|
1985
|
+
for (const a of sub3) {
|
|
1986
|
+
const { inHandle, outHandle } = a;
|
|
1987
|
+
delete a.inHandle;
|
|
1988
|
+
delete a.outHandle;
|
|
1989
|
+
if (outHandle) a.inHandle = outHandle;
|
|
1990
|
+
if (inHandle) a.outHandle = inHandle;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
// src/pathSubpaths.ts
|
|
1995
|
+
function flatSubpaths(path, tolerance) {
|
|
1996
|
+
const { commands, coords } = path;
|
|
1997
|
+
const closed = [];
|
|
1998
|
+
const open = [];
|
|
1999
|
+
let sub3 = [];
|
|
2000
|
+
forEachSegment(commands, coords, (cmd, ci, curX, curY, _i, opensSubpath) => {
|
|
2001
|
+
if (opensSubpath) sub3 = [curX, curY];
|
|
2002
|
+
switch (cmd) {
|
|
2003
|
+
case PATH_M:
|
|
2004
|
+
if (sub3.length >= 2) open.push(sub3);
|
|
2005
|
+
sub3 = [coords[ci], coords[ci + 1]];
|
|
2006
|
+
break;
|
|
2007
|
+
case PATH_L:
|
|
2008
|
+
sub3.push(coords[ci], coords[ci + 1]);
|
|
2009
|
+
break;
|
|
2010
|
+
case PATH_C:
|
|
2011
|
+
flattenCubic(
|
|
2012
|
+
curX,
|
|
2013
|
+
curY,
|
|
2014
|
+
coords[ci],
|
|
2015
|
+
coords[ci + 1],
|
|
2016
|
+
coords[ci + 2],
|
|
2017
|
+
coords[ci + 3],
|
|
2018
|
+
coords[ci + 4],
|
|
2019
|
+
coords[ci + 5],
|
|
2020
|
+
tolerance,
|
|
2021
|
+
sub3
|
|
2022
|
+
);
|
|
2023
|
+
break;
|
|
2024
|
+
case PATH_Q:
|
|
2025
|
+
flattenQuadratic(
|
|
2026
|
+
curX,
|
|
2027
|
+
curY,
|
|
2028
|
+
coords[ci],
|
|
2029
|
+
coords[ci + 1],
|
|
2030
|
+
coords[ci + 2],
|
|
2031
|
+
coords[ci + 3],
|
|
2032
|
+
tolerance,
|
|
2033
|
+
sub3
|
|
2034
|
+
);
|
|
2035
|
+
break;
|
|
2036
|
+
case PATH_Z:
|
|
2037
|
+
if (sub3.length >= 6) closed.push(sub3);
|
|
2038
|
+
else if (sub3.length >= 2) open.push(sub3);
|
|
2039
|
+
sub3 = [];
|
|
2040
|
+
break;
|
|
2041
|
+
default:
|
|
2042
|
+
throw new Error(`pathHitTest: unknown command ${cmd}`);
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
if (sub3.length >= 2) open.push(sub3);
|
|
2046
|
+
return { closed, open };
|
|
2047
|
+
}
|
|
2048
|
+
function regionSubpaths(path, opts) {
|
|
2049
|
+
const flat = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
|
|
2050
|
+
if (!fillsOpenSubpaths(path)) return flat;
|
|
2051
|
+
return {
|
|
2052
|
+
closed: [...flat.closed, ...flat.open.filter((sub3) => sub3.length >= 6)],
|
|
2053
|
+
open: flat.open.filter((sub3) => sub3.length < 6)
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function closedSubpaths(path, opts) {
|
|
2057
|
+
return regionSubpaths(path, opts).closed;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
// src/screenBand.ts
|
|
2061
|
+
function stretchOf(m) {
|
|
2062
|
+
const e = (m.a + m.d) / 2;
|
|
2063
|
+
const f = (m.a - m.d) / 2;
|
|
2064
|
+
const g = (m.b + m.c) / 2;
|
|
2065
|
+
const h = (m.b - m.c) / 2;
|
|
2066
|
+
const q = Math.hypot(e, h);
|
|
2067
|
+
const r = Math.hypot(f, g);
|
|
2068
|
+
const phi = (Math.atan2(h, e) + Math.atan2(g, f)) / 2;
|
|
2069
|
+
return { s1: q + r, s2: Math.abs(q - r), phi };
|
|
2070
|
+
}
|
|
2071
|
+
function isSimilarity(s) {
|
|
2072
|
+
return s.s1 - s.s2 <= 1e-9 * s.s1;
|
|
2073
|
+
}
|
|
2074
|
+
function capsuleWithinPx(px0, py0, ax, ay, bx, by, r, slop, m, st) {
|
|
2075
|
+
const sax = m.a * ax + m.c * ay, say = m.b * ax + m.d * ay;
|
|
2076
|
+
const sbx = m.a * bx + m.c * by, sby = m.b * bx + m.d * by;
|
|
2077
|
+
const slop2 = slop * slop;
|
|
2078
|
+
const dCenter2 = pointSegmentDist2(px0, py0, sax, say, sbx, sby);
|
|
2079
|
+
if (dCenter2 <= slop2) return true;
|
|
2080
|
+
if (r <= 0) return false;
|
|
2081
|
+
const reach = slop + r * st.s1;
|
|
2082
|
+
if (dCenter2 > reach * reach) return false;
|
|
2083
|
+
const wx = bx - ax, wy = by - ay;
|
|
2084
|
+
const wl = Math.hypot(wx, wy);
|
|
2085
|
+
if (wl > 0) {
|
|
2086
|
+
const nx = -wy / wl * r, ny = wx / wl * r;
|
|
2087
|
+
const ox = m.a * nx + m.c * ny, oy = m.b * nx + m.d * ny;
|
|
2088
|
+
if (quadWithinPx(px0, py0, [
|
|
2089
|
+
sax + ox,
|
|
2090
|
+
say + oy,
|
|
2091
|
+
sbx + ox,
|
|
2092
|
+
sby + oy,
|
|
2093
|
+
sbx - ox,
|
|
2094
|
+
sby - oy,
|
|
2095
|
+
sax - ox,
|
|
2096
|
+
say - oy
|
|
2097
|
+
], slop2)) return true;
|
|
2098
|
+
}
|
|
2099
|
+
return ellipseWithinPx(px0 - sax, py0 - say, r, slop, st) || ellipseWithinPx(px0 - sbx, py0 - sby, r, slop, st);
|
|
2100
|
+
}
|
|
2101
|
+
function quadWithinPx(x, y, q, slop2) {
|
|
2102
|
+
let pos = 0, neg2 = 0;
|
|
2103
|
+
for (let i = 0; i < 8; i += 2) {
|
|
2104
|
+
const j = (i + 2) % 8;
|
|
2105
|
+
const cr = (q[j] - q[i]) * (y - q[i + 1]) - (q[j + 1] - q[i + 1]) * (x - q[i]);
|
|
2106
|
+
if (cr > 0) pos++;
|
|
2107
|
+
else if (cr < 0) neg2++;
|
|
2108
|
+
}
|
|
2109
|
+
if (pos === 0 || neg2 === 0) return true;
|
|
2110
|
+
for (let i = 0; i < 8; i += 2) {
|
|
2111
|
+
const j = (i + 2) % 8;
|
|
2112
|
+
if (pointSegmentDist2(x, y, q[i], q[i + 1], q[j], q[j + 1]) <= slop2) return true;
|
|
2113
|
+
}
|
|
2114
|
+
return false;
|
|
1313
2115
|
}
|
|
1314
2116
|
function ellipseWithinPx(dx, dy, r, slop, st) {
|
|
1315
2117
|
const cos = Math.cos(st.phi), sin = Math.sin(st.phi);
|
|
@@ -1586,218 +2388,61 @@ function circlePath(cx, cy, r, segments = 32) {
|
|
|
1586
2388
|
const coords = new Float32Array(segments * 2);
|
|
1587
2389
|
cmds[0] = PATH_M;
|
|
1588
2390
|
coords[0] = cx + r;
|
|
1589
|
-
coords[1] = cy;
|
|
1590
|
-
for (let i = 1; i < segments; i++) {
|
|
1591
|
-
cmds[i] = PATH_L;
|
|
1592
|
-
const theta = i / segments * Math.PI * 2;
|
|
1593
|
-
coords[i * 2] = cx + r * Math.cos(theta);
|
|
1594
|
-
coords[i * 2 + 1] = cy + r * Math.sin(theta);
|
|
1595
|
-
}
|
|
1596
|
-
cmds[segments] = PATH_Z;
|
|
1597
|
-
return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
|
|
1598
|
-
}
|
|
1599
|
-
function squarePath(cx, cy, size) {
|
|
1600
|
-
const half = size / 2;
|
|
1601
|
-
const x0 = cx - half, y0 = cy - half;
|
|
1602
|
-
const x1 = cx + half, y1 = cy + half;
|
|
1603
|
-
return {
|
|
1604
|
-
kind: "polygon",
|
|
1605
|
-
commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
|
|
1606
|
-
coords: new Float32Array([x0, y0, x1, y0, x1, y1, x0, y1]),
|
|
1607
|
-
fillRule: "nonzero"
|
|
1608
|
-
};
|
|
1609
|
-
}
|
|
1610
|
-
function rectMarkerPath(x, y, width, height) {
|
|
1611
|
-
return {
|
|
1612
|
-
kind: "polygon",
|
|
1613
|
-
commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
|
|
1614
|
-
coords: Float32Array.from(rectToContour(x, y, width, height)),
|
|
1615
|
-
fillRule: "nonzero"
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
function roundRectPath(x, y, width, height, r, cornerSamples = 8) {
|
|
1619
|
-
const radius = Math.max(0, Math.min(r, Math.min(width, height) / 2));
|
|
1620
|
-
if (radius === 0) return rectMarkerPath(x, y, width, height);
|
|
1621
|
-
const HALF_PI = Math.PI / 2;
|
|
1622
|
-
const corners = [
|
|
1623
|
-
[x + radius, y + radius, Math.PI],
|
|
1624
|
-
[x + width - radius, y + radius, -HALF_PI],
|
|
1625
|
-
[x + width - radius, y + height - radius, 0],
|
|
1626
|
-
[x + radius, y + height - radius, HALF_PI]
|
|
1627
|
-
];
|
|
1628
|
-
const perCorner = cornerSamples + 1;
|
|
1629
|
-
const count = corners.length * perCorner;
|
|
1630
|
-
const cmds = new Uint8Array(count + 1);
|
|
1631
|
-
const coords = new Float32Array(count * 2);
|
|
1632
|
-
let i = 0;
|
|
1633
|
-
for (const [cx, cy, start] of corners) {
|
|
1634
|
-
for (let s = 0; s <= cornerSamples; s++) {
|
|
1635
|
-
const theta = start + s / cornerSamples * HALF_PI;
|
|
1636
|
-
cmds[i] = i === 0 ? PATH_M : PATH_L;
|
|
1637
|
-
coords[i * 2] = cx + radius * Math.cos(theta);
|
|
1638
|
-
coords[i * 2 + 1] = cy + radius * Math.sin(theta);
|
|
1639
|
-
i++;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
cmds[count] = PATH_Z;
|
|
1643
|
-
return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
|
-
// src/paths/anchors.ts
|
|
1647
|
-
function pathToAnchors(path) {
|
|
1648
|
-
const { commands, coords } = path;
|
|
1649
|
-
const anchors = [];
|
|
1650
|
-
const closed = [];
|
|
1651
|
-
let current = null;
|
|
1652
|
-
forEachSegment(commands, coords, (cmd, ci) => {
|
|
1653
|
-
switch (cmd) {
|
|
1654
|
-
case PATH_M: {
|
|
1655
|
-
if (current) {
|
|
1656
|
-
anchors.push(current);
|
|
1657
|
-
closed.push(false);
|
|
1658
|
-
}
|
|
1659
|
-
current = [{ x: coords[ci], y: coords[ci + 1] }];
|
|
1660
|
-
break;
|
|
1661
|
-
}
|
|
1662
|
-
case PATH_L: {
|
|
1663
|
-
if (!current) throw new Error("pathToAnchors: L without prior M");
|
|
1664
|
-
current.push({ x: coords[ci], y: coords[ci + 1] });
|
|
1665
|
-
break;
|
|
1666
|
-
}
|
|
1667
|
-
case PATH_C: {
|
|
1668
|
-
if (!current) throw new Error("pathToAnchors: C without prior M");
|
|
1669
|
-
const prev = current[current.length - 1];
|
|
1670
|
-
prev.outHandle = { x: coords[ci], y: coords[ci + 1] };
|
|
1671
|
-
current.push({
|
|
1672
|
-
x: coords[ci + 4],
|
|
1673
|
-
y: coords[ci + 5],
|
|
1674
|
-
inHandle: { x: coords[ci + 2], y: coords[ci + 3] }
|
|
1675
|
-
});
|
|
1676
|
-
break;
|
|
1677
|
-
}
|
|
1678
|
-
case PATH_Q: {
|
|
1679
|
-
if (!current) throw new Error("pathToAnchors: Q without prior M");
|
|
1680
|
-
const handle = { x: coords[ci], y: coords[ci + 1] };
|
|
1681
|
-
const prev = current[current.length - 1];
|
|
1682
|
-
prev.outHandle = handle;
|
|
1683
|
-
current.push({ x: coords[ci + 2], y: coords[ci + 3], inHandle: { ...handle } });
|
|
1684
|
-
break;
|
|
1685
|
-
}
|
|
1686
|
-
case PATH_Z: {
|
|
1687
|
-
if (current) {
|
|
1688
|
-
foldClosingCurve(current);
|
|
1689
|
-
anchors.push(current);
|
|
1690
|
-
closed.push(true);
|
|
1691
|
-
current = null;
|
|
1692
|
-
}
|
|
1693
|
-
break;
|
|
1694
|
-
}
|
|
1695
|
-
default:
|
|
1696
|
-
throw new Error(`pathToAnchors: unknown command ${cmd}`);
|
|
1697
|
-
}
|
|
1698
|
-
});
|
|
1699
|
-
if (current) {
|
|
1700
|
-
anchors.push(current);
|
|
1701
|
-
closed.push(false);
|
|
1702
|
-
}
|
|
1703
|
-
return { anchors, closed };
|
|
1704
|
-
}
|
|
1705
|
-
function foldClosingCurve(sub3) {
|
|
1706
|
-
if (sub3.length < 2) return;
|
|
1707
|
-
const first = sub3[0];
|
|
1708
|
-
const last = sub3[sub3.length - 1];
|
|
1709
|
-
if (!last.inHandle || last.x !== first.x || last.y !== first.y) return;
|
|
1710
|
-
sub3.pop();
|
|
1711
|
-
first.inHandle = last.inHandle;
|
|
1712
|
-
}
|
|
1713
|
-
function anchorsToPath(anchors, closed, like) {
|
|
1714
|
-
const b = new PathBuilder();
|
|
1715
|
-
for (let s = 0; s < anchors.length; s++) {
|
|
1716
|
-
const sub3 = anchors[s];
|
|
1717
|
-
if (sub3.length === 0) continue;
|
|
1718
|
-
b.moveTo(sub3[0].x, sub3[0].y);
|
|
1719
|
-
for (let i = 1; i < sub3.length; i++) {
|
|
1720
|
-
const prev = sub3[i - 1];
|
|
1721
|
-
const cur = sub3[i];
|
|
1722
|
-
const hasHandle = prev.outHandle != null || cur.inHandle != null;
|
|
1723
|
-
if (!hasHandle) {
|
|
1724
|
-
b.lineTo(cur.x, cur.y);
|
|
1725
|
-
} else {
|
|
1726
|
-
const c1 = prev.outHandle ?? { x: prev.x, y: prev.y };
|
|
1727
|
-
const c2 = cur.inHandle ?? { x: cur.x, y: cur.y };
|
|
1728
|
-
b.curveTo(c1.x, c1.y, c2.x, c2.y, cur.x, cur.y);
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
if (closed[s]) {
|
|
1732
|
-
const last = sub3[sub3.length - 1];
|
|
1733
|
-
const first = sub3[0];
|
|
1734
|
-
const hasHandle = last.outHandle != null || first.inHandle != null;
|
|
1735
|
-
if (hasHandle) {
|
|
1736
|
-
const c1 = last.outHandle ?? { x: last.x, y: last.y };
|
|
1737
|
-
const c2 = first.inHandle ?? { x: first.x, y: first.y };
|
|
1738
|
-
b.curveTo(c1.x, c1.y, c2.x, c2.y, first.x, first.y);
|
|
1739
|
-
}
|
|
1740
|
-
b.close();
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
const built = b.build();
|
|
1744
|
-
return like ? { ...like, commands: built.commands, coords: built.coords } : built;
|
|
1745
|
-
}
|
|
1746
|
-
var SMOOTH_THRESHOLD = 1e-3;
|
|
1747
|
-
function isAnchorSmooth(a) {
|
|
1748
|
-
if (!a.inHandle || !a.outHandle) return false;
|
|
1749
|
-
const inDX = a.inHandle.x - a.x;
|
|
1750
|
-
const inDY = a.inHandle.y - a.y;
|
|
1751
|
-
const outDX = a.outHandle.x - a.x;
|
|
1752
|
-
const outDY = a.outHandle.y - a.y;
|
|
1753
|
-
const inLen = Math.hypot(inDX, inDY);
|
|
1754
|
-
const outLen = Math.hypot(outDX, outDY);
|
|
1755
|
-
if (inLen === 0 || outLen === 0) return false;
|
|
1756
|
-
const cross2 = (inDX * outDY - inDY * outDX) / (inLen * outLen);
|
|
1757
|
-
return Math.abs(cross2) < SMOOTH_THRESHOLD;
|
|
1758
|
-
}
|
|
1759
|
-
function countPathAnchors(path) {
|
|
1760
|
-
if (path.kind === "rect") return 4;
|
|
1761
|
-
const cmds = path.commands;
|
|
1762
|
-
let n = 0;
|
|
1763
|
-
for (let i = 0; i < cmds.length; i++) {
|
|
1764
|
-
const c = cmds[i];
|
|
1765
|
-
if (c === PATH_M || c === PATH_L || c === PATH_C || c === PATH_Q) n++;
|
|
2391
|
+
coords[1] = cy;
|
|
2392
|
+
for (let i = 1; i < segments; i++) {
|
|
2393
|
+
cmds[i] = PATH_L;
|
|
2394
|
+
const theta = i / segments * Math.PI * 2;
|
|
2395
|
+
coords[i * 2] = cx + r * Math.cos(theta);
|
|
2396
|
+
coords[i * 2 + 1] = cy + r * Math.sin(theta);
|
|
1766
2397
|
}
|
|
1767
|
-
|
|
1768
|
-
}
|
|
1769
|
-
function segmentEnds(anchors, closed, sub3, segIdx) {
|
|
1770
|
-
const s = anchors[sub3];
|
|
1771
|
-
if (!s || segIdx < 0) return null;
|
|
1772
|
-
if (segIdx + 1 < s.length) return { a: s[segIdx], b: s[segIdx + 1] };
|
|
1773
|
-
if (closed?.[sub3] && s.length > 1 && segIdx === s.length - 1) return { a: s[segIdx], b: s[0] };
|
|
1774
|
-
return null;
|
|
2398
|
+
cmds[segments] = PATH_Z;
|
|
2399
|
+
return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
|
|
1775
2400
|
}
|
|
1776
|
-
function
|
|
1777
|
-
|
|
2401
|
+
function squarePath(cx, cy, size) {
|
|
2402
|
+
const half = size / 2;
|
|
2403
|
+
const x0 = cx - half, y0 = cy - half;
|
|
2404
|
+
const x1 = cx + half, y1 = cy + half;
|
|
2405
|
+
return {
|
|
2406
|
+
kind: "polygon",
|
|
2407
|
+
commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
|
|
2408
|
+
coords: new Float32Array([x0, y0, x1, y0, x1, y1, x0, y1]),
|
|
2409
|
+
fillRule: "nonzero"
|
|
2410
|
+
};
|
|
1778
2411
|
}
|
|
1779
|
-
function
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2412
|
+
function rectMarkerPath(x, y, width, height) {
|
|
2413
|
+
return {
|
|
2414
|
+
kind: "polygon",
|
|
2415
|
+
commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
|
|
2416
|
+
coords: Float32Array.from(rectToContour(x, y, width, height)),
|
|
2417
|
+
fillRule: "nonzero"
|
|
2418
|
+
};
|
|
1784
2419
|
}
|
|
1785
|
-
function
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2420
|
+
function roundRectPath(x, y, width, height, r, cornerSamples = 8) {
|
|
2421
|
+
const radius = Math.max(0, Math.min(r, Math.min(width, height) / 2));
|
|
2422
|
+
if (radius === 0) return rectMarkerPath(x, y, width, height);
|
|
2423
|
+
const HALF_PI = Math.PI / 2;
|
|
2424
|
+
const corners = [
|
|
2425
|
+
[x + radius, y + radius, Math.PI],
|
|
2426
|
+
[x + width - radius, y + radius, -HALF_PI],
|
|
2427
|
+
[x + width - radius, y + height - radius, 0],
|
|
2428
|
+
[x + radius, y + height - radius, HALF_PI]
|
|
2429
|
+
];
|
|
2430
|
+
const perCorner = cornerSamples + 1;
|
|
2431
|
+
const count = corners.length * perCorner;
|
|
2432
|
+
const cmds = new Uint8Array(count + 1);
|
|
2433
|
+
const coords = new Float32Array(count * 2);
|
|
2434
|
+
let i = 0;
|
|
2435
|
+
for (const [cx, cy, start] of corners) {
|
|
2436
|
+
for (let s = 0; s <= cornerSamples; s++) {
|
|
2437
|
+
const theta = start + s / cornerSamples * HALF_PI;
|
|
2438
|
+
cmds[i] = i === 0 ? PATH_M : PATH_L;
|
|
2439
|
+
coords[i * 2] = cx + radius * Math.cos(theta);
|
|
2440
|
+
coords[i * 2 + 1] = cy + radius * Math.sin(theta);
|
|
2441
|
+
i++;
|
|
1798
2442
|
}
|
|
1799
2443
|
}
|
|
1800
|
-
|
|
2444
|
+
cmds[count] = PATH_Z;
|
|
2445
|
+
return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
|
|
1801
2446
|
}
|
|
1802
2447
|
|
|
1803
2448
|
// src/glMat3.ts
|
|
@@ -1920,14 +2565,14 @@ function alignAlong(start, extent, size, align) {
|
|
|
1920
2565
|
if (align === "end") return start + extent - size;
|
|
1921
2566
|
return start + (extent - size) / 2;
|
|
1922
2567
|
}
|
|
1923
|
-
function positionOn(anchor, overlay, placement,
|
|
2568
|
+
function positionOn(anchor, overlay, placement, offset2, crossOffset) {
|
|
1924
2569
|
const { width, height } = overlay;
|
|
1925
2570
|
const { side, align } = placement;
|
|
1926
2571
|
if (side === "top" || side === "bottom") {
|
|
1927
|
-
const y = side === "bottom" ? anchor.y + anchor.height +
|
|
2572
|
+
const y = side === "bottom" ? anchor.y + anchor.height + offset2 : anchor.y - offset2 - height;
|
|
1928
2573
|
return { x: alignAlong(anchor.x, anchor.width, width, align) + crossOffset, y, width, height };
|
|
1929
2574
|
}
|
|
1930
|
-
const x = side === "right" ? anchor.x + anchor.width +
|
|
2575
|
+
const x = side === "right" ? anchor.x + anchor.width + offset2 : anchor.x - offset2 - width;
|
|
1931
2576
|
return { x, y: alignAlong(anchor.y, anchor.height, height, align) + crossOffset, width, height };
|
|
1932
2577
|
}
|
|
1933
2578
|
function clampAxis(start, size, low, extent, padding) {
|
|
@@ -1964,13 +2609,13 @@ function fitsAlongSide(rect, boundary, side, padding) {
|
|
|
1964
2609
|
return start >= low && end <= high;
|
|
1965
2610
|
}
|
|
1966
2611
|
function placeRect(options) {
|
|
1967
|
-
const { anchor, overlay, boundary, placement, offset = 0, crossOffset = 0 } = options;
|
|
2612
|
+
const { anchor, overlay, boundary, placement, offset: offset2 = 0, crossOffset = 0 } = options;
|
|
1968
2613
|
const { padding = 0, flip = true } = options;
|
|
1969
2614
|
let resolved = placement;
|
|
1970
|
-
let rect = positionOn(anchor, overlay, resolved,
|
|
2615
|
+
let rect = positionOn(anchor, overlay, resolved, offset2, crossOffset);
|
|
1971
2616
|
if (flip && !fitsAlongSide(rect, boundary, resolved.side, padding)) {
|
|
1972
2617
|
const opposite = { side: OPPOSITE[resolved.side], align: resolved.align };
|
|
1973
|
-
const flipped = positionOn(anchor, overlay, opposite,
|
|
2618
|
+
const flipped = positionOn(anchor, overlay, opposite, offset2, crossOffset);
|
|
1974
2619
|
if (fitsAlongSide(flipped, boundary, opposite.side, padding)) {
|
|
1975
2620
|
resolved = opposite;
|
|
1976
2621
|
rect = flipped;
|
|
@@ -2166,44 +2811,6 @@ function meanScale(s) {
|
|
|
2166
2811
|
return Math.sqrt(Math.abs(s.x * s.y));
|
|
2167
2812
|
}
|
|
2168
2813
|
|
|
2169
|
-
// src/pxExtent.ts
|
|
2170
|
-
function pxExtent(px, scale2, rotation = 0) {
|
|
2171
|
-
if (!rotation) {
|
|
2172
|
-
return {
|
|
2173
|
-
x: px / Math.abs(scale2.x),
|
|
2174
|
-
y: px / Math.abs(scale2.y)
|
|
2175
|
-
};
|
|
2176
|
-
}
|
|
2177
|
-
const c = Math.cos(rotation), s = Math.sin(rotation);
|
|
2178
|
-
return {
|
|
2179
|
-
x: px * Math.hypot(c / scale2.x, s / scale2.y),
|
|
2180
|
-
y: px * Math.hypot(s / scale2.x, c / scale2.y)
|
|
2181
|
-
};
|
|
2182
|
-
}
|
|
2183
|
-
function scaleDelta(dx, dy, scale2) {
|
|
2184
|
-
return { x: dx * scale2.x, y: dy * scale2.y };
|
|
2185
|
-
}
|
|
2186
|
-
function withinPxBox(dx, dy, px, scale2) {
|
|
2187
|
-
const s = scaleDelta(dx, dy, scale2);
|
|
2188
|
-
return Math.abs(s.x) <= px && Math.abs(s.y) <= px;
|
|
2189
|
-
}
|
|
2190
|
-
function withinPxRadius(dx, dy, px, scale2) {
|
|
2191
|
-
const s = scaleDelta(dx, dy, scale2);
|
|
2192
|
-
return s.x * s.x + s.y * s.y <= px * px;
|
|
2193
|
-
}
|
|
2194
|
-
function standoff(anchor, normal, px, scale2) {
|
|
2195
|
-
const k = Math.sign(scale2.x * scale2.y) || 1;
|
|
2196
|
-
let nx = normal.x * scale2.y * k;
|
|
2197
|
-
let ny = normal.y * scale2.x * k;
|
|
2198
|
-
const l = Math.hypot(nx, ny) || 1;
|
|
2199
|
-
nx /= l;
|
|
2200
|
-
ny /= l;
|
|
2201
|
-
return { x: anchor.x + nx * px / scale2.x, y: anchor.y + ny * px / scale2.y, nx, ny };
|
|
2202
|
-
}
|
|
2203
|
-
function screenAngleOf(rotation, scale2) {
|
|
2204
|
-
return Math.atan2(Math.sin(rotation) * scale2.y, Math.cos(rotation) * scale2.x);
|
|
2205
|
-
}
|
|
2206
|
-
|
|
2207
2814
|
// src/poseRotation.ts
|
|
2208
2815
|
function poseRotationOf(pose) {
|
|
2209
2816
|
const p = pose;
|
|
@@ -2260,12 +2867,12 @@ function poseLinearOf(pose) {
|
|
|
2260
2867
|
function poseFrameOf(pose) {
|
|
2261
2868
|
const p = pose;
|
|
2262
2869
|
if (!p || p.x == null || p.y == null || p.width == null || p.height == null) return null;
|
|
2263
|
-
const
|
|
2264
|
-
if (!p.rotation && !
|
|
2870
|
+
const linear3 = poseLinearOf(p);
|
|
2871
|
+
if (!p.rotation && !linear3) return null;
|
|
2265
2872
|
const cx = p.x + p.width / 2;
|
|
2266
2873
|
const cy = p.y + p.height / 2;
|
|
2267
|
-
if (!
|
|
2268
|
-
const [a, b, c, d] =
|
|
2874
|
+
if (!linear3) return rotateAboutPoint(cx, cy, p.rotation);
|
|
2875
|
+
const [a, b, c, d] = linear3;
|
|
2269
2876
|
const about = [a, b, c, d, cx - (a * cx + c * cy), cy - (b * cx + d * cy)];
|
|
2270
2877
|
return p.rotation ? multiply(rotateAboutPoint(cx, cy, p.rotation), about) : about;
|
|
2271
2878
|
}
|
|
@@ -2286,185 +2893,221 @@ function pathThroughPoseFrame(path, pose) {
|
|
|
2286
2893
|
return r ? rotatePathAround(path, r.cx, r.cy, r.rotation) : path;
|
|
2287
2894
|
}
|
|
2288
2895
|
|
|
2289
|
-
// src/paths/
|
|
2290
|
-
function
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
for (let sub3 = 0; sub3 < set.anchors.length; sub3++) {
|
|
2299
|
-
const len = set.anchors[sub3].length;
|
|
2300
|
-
if (remaining < len) return { sub: sub3, idx: remaining };
|
|
2301
|
-
remaining -= len;
|
|
2302
|
-
}
|
|
2303
|
-
return null;
|
|
2304
|
-
}
|
|
2305
|
-
function flatAnchorIndex(set, sub3, idx) {
|
|
2306
|
-
if (sub3 < 0 || sub3 >= set.anchors.length) return -1;
|
|
2307
|
-
if (idx < 0 || idx >= set.anchors[sub3].length) return -1;
|
|
2308
|
-
let base = 0;
|
|
2309
|
-
for (let s = 0; s < sub3; s++) base += set.anchors[s].length;
|
|
2310
|
-
return base + idx;
|
|
2896
|
+
// src/paths/anchorSymmetry.ts
|
|
2897
|
+
function near(a, b, tol) {
|
|
2898
|
+
if (!a || !b) return a === b;
|
|
2899
|
+
return Math.abs(a.x - b.x) <= tol && Math.abs(a.y - b.y) <= tol;
|
|
2900
|
+
}
|
|
2901
|
+
function image(m, p) {
|
|
2902
|
+
if (!p) return void 0;
|
|
2903
|
+
const [x, y] = applyToPoint(m, p.x, p.y);
|
|
2904
|
+
return { x, y };
|
|
2311
2905
|
}
|
|
2312
|
-
function
|
|
2313
|
-
|
|
2314
|
-
if (!loc) return null;
|
|
2315
|
-
return set.anchors[loc.sub][loc.idx] ?? null;
|
|
2906
|
+
function linear2(m, d) {
|
|
2907
|
+
return { x: m[0] * d.x + m[2] * d.y, y: m[1] * d.x + m[3] * d.y };
|
|
2316
2908
|
}
|
|
2317
|
-
function
|
|
2318
|
-
|
|
2319
|
-
const
|
|
2320
|
-
|
|
2321
|
-
|
|
2909
|
+
function landing(m, a, b, tol) {
|
|
2910
|
+
if (!near(image(m, a), b, tol)) return null;
|
|
2911
|
+
const i = image(m, a.inHandle);
|
|
2912
|
+
const o = image(m, a.outHandle);
|
|
2913
|
+
if (near(i, b.inHandle, tol) && near(o, b.outHandle, tol)) return false;
|
|
2914
|
+
if (near(i, b.outHandle, tol) && near(o, b.inHandle, tol)) return true;
|
|
2915
|
+
return null;
|
|
2322
2916
|
}
|
|
2323
|
-
function
|
|
2324
|
-
const
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
a
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2917
|
+
function anchorSymmetry(set, m, tolerance = 1e-6) {
|
|
2918
|
+
const n = anchorCount(set);
|
|
2919
|
+
const partners = [];
|
|
2920
|
+
const flips = [];
|
|
2921
|
+
const taken = /* @__PURE__ */ new Set();
|
|
2922
|
+
for (let i = 0; i < n; i++) {
|
|
2923
|
+
const a = anchorAt(set, i);
|
|
2924
|
+
let found = -1;
|
|
2925
|
+
let flip = false;
|
|
2926
|
+
for (let j = 0; j < n && found < 0; j++) {
|
|
2927
|
+
if (taken.has(j)) continue;
|
|
2928
|
+
const how = landing(m, a, anchorAt(set, j), tolerance);
|
|
2929
|
+
if (how === null) continue;
|
|
2930
|
+
found = j;
|
|
2931
|
+
flip = how;
|
|
2932
|
+
}
|
|
2933
|
+
if (found < 0) return null;
|
|
2934
|
+
taken.add(found);
|
|
2935
|
+
partners.push(found);
|
|
2936
|
+
flips.push(flip);
|
|
2937
|
+
}
|
|
2938
|
+
return { m, partners, flips };
|
|
2939
|
+
}
|
|
2940
|
+
function anchorSymmetries(set, group, tolerance = 1e-6) {
|
|
2941
|
+
return group.map((m) => anchorSymmetry(set, m, tolerance)).filter((s) => s !== null);
|
|
2942
|
+
}
|
|
2943
|
+
function averaged(d, syms, fixes, apply2) {
|
|
2944
|
+
let x = d.x;
|
|
2945
|
+
let y = d.y;
|
|
2946
|
+
let k = 1;
|
|
2947
|
+
for (const s of syms) {
|
|
2948
|
+
if (!fixes(s)) continue;
|
|
2949
|
+
const p = apply2(s.m, d);
|
|
2950
|
+
x += p.x;
|
|
2951
|
+
y += p.y;
|
|
2952
|
+
k++;
|
|
2953
|
+
}
|
|
2954
|
+
return { x: x / k, y: y / k };
|
|
2955
|
+
}
|
|
2956
|
+
function translateAnchorsSymmetric(set, flats, dx, dy, syms) {
|
|
2957
|
+
const dragged = new Set(flats);
|
|
2958
|
+
const moves = /* @__PURE__ */ new Map();
|
|
2959
|
+
for (const flat of flats) {
|
|
2960
|
+
const d = averaged({ x: dx, y: dy }, syms, (s) => s.partners[flat] === flat, linear2);
|
|
2961
|
+
moves.set(flat, d);
|
|
2962
|
+
for (const s of syms) {
|
|
2963
|
+
const j = s.partners[flat];
|
|
2964
|
+
if (j === void 0 || dragged.has(j) || moves.has(j)) continue;
|
|
2965
|
+
moves.set(j, linear2(s.m, d));
|
|
2966
|
+
}
|
|
2335
2967
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
const
|
|
2343
|
-
if (side === "
|
|
2344
|
-
|
|
2345
|
-
const
|
|
2346
|
-
const
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2968
|
+
let changed = false;
|
|
2969
|
+
for (const [flat, d] of moves) changed = translateAnchorBy(set, flat, d.x, d.y) || changed;
|
|
2970
|
+
return changed;
|
|
2971
|
+
}
|
|
2972
|
+
var other = (side) => side === "in" ? "out" : "in";
|
|
2973
|
+
function moveHandleSymmetric(set, flat, side, toX, toY, breakSmoothness, syms) {
|
|
2974
|
+
const a = anchorAt(set, flat);
|
|
2975
|
+
if (!a || !(side === "in" ? a.inHandle : a.outHandle)) return false;
|
|
2976
|
+
const sideUnder = (s, sd) => s.flips[flat] ? other(sd) : sd;
|
|
2977
|
+
const fixesHandle = (s) => s.partners[flat] === flat && sideUnder(s, side) === side;
|
|
2978
|
+
const to = averaged({ x: toX, y: toY }, syms, fixesHandle, image);
|
|
2979
|
+
const targets = /* @__PURE__ */ new Map();
|
|
2980
|
+
const put = (f, sd, p) => {
|
|
2981
|
+
const key = `${f}:${sd}`;
|
|
2982
|
+
if (!targets.has(key)) targets.set(key, { flat: f, side: sd, to: p });
|
|
2983
|
+
};
|
|
2984
|
+
put(flat, side, to);
|
|
2985
|
+
for (const s of syms) put(s.partners[flat], sideUnder(s, side), image(s.m, to));
|
|
2986
|
+
const opposite = side === "in" ? a.outHandle : a.inHandle;
|
|
2987
|
+
const drivenBySymmetry = targets.has(`${flat}:${other(side)}`);
|
|
2988
|
+
if (!drivenBySymmetry && !breakSmoothness && opposite && isAnchorSmooth(a)) {
|
|
2989
|
+
const opp = { x: 2 * a.x - to.x, y: 2 * a.y - to.y };
|
|
2990
|
+
put(flat, other(side), opp);
|
|
2991
|
+
for (const s of syms) put(s.partners[flat], sideUnder(s, other(side)), image(s.m, opp));
|
|
2992
|
+
}
|
|
2993
|
+
for (const t of targets.values()) {
|
|
2994
|
+
const b = anchorAt(set, t.flat);
|
|
2995
|
+
if (!b) continue;
|
|
2996
|
+
if (t.side === "in") b.inHandle = t.to;
|
|
2997
|
+
else b.outHandle = t.to;
|
|
2351
2998
|
}
|
|
2352
2999
|
return true;
|
|
2353
3000
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
3001
|
+
|
|
3002
|
+
// src/paths/bendSegment.ts
|
|
3003
|
+
var T_MARGIN = 0.05;
|
|
3004
|
+
function bendSegment(set, grip, dx, dy) {
|
|
3005
|
+
const ends = segmentEnds(set.anchors, set.closed, grip.sub, grip.segIdx);
|
|
3006
|
+
if (!ends) return false;
|
|
2357
3007
|
const { a, b } = ends;
|
|
2358
|
-
const
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
a.
|
|
2369
|
-
b.
|
|
2370
|
-
|
|
2371
|
-
x: left[3].x,
|
|
2372
|
-
y: left[3].y,
|
|
2373
|
-
inHandle: { x: left[2].x, y: left[2].y },
|
|
2374
|
-
outHandle: { x: right[1].x, y: right[1].y }
|
|
2375
|
-
});
|
|
2376
|
-
return flatAnchorIndex(set, args.sub, at);
|
|
3008
|
+
const aSmooth = isAnchorSmooth(a);
|
|
3009
|
+
const bSmooth = isAnchorSmooth(b);
|
|
3010
|
+
const straight = isStraightSegment(a, b);
|
|
3011
|
+
const p1 = a.outHandle ?? (straight ? lerp(a, b, 1 / 3) : { x: a.x, y: a.y });
|
|
3012
|
+
const p2 = b.inHandle ?? (straight ? lerp(a, b, 2 / 3) : { x: b.x, y: b.y });
|
|
3013
|
+
const t = Math.min(1 - T_MARGIN, Math.max(T_MARGIN, grip.t));
|
|
3014
|
+
const u = 1 - t;
|
|
3015
|
+
const k = 1 / (3 * t * u * (u * u + t * t));
|
|
3016
|
+
a.outHandle = { x: p1.x + k * u * dx, y: p1.y + k * u * dy };
|
|
3017
|
+
b.inHandle = { x: p2.x + k * t * dx, y: p2.y + k * t * dy };
|
|
3018
|
+
if (aSmooth) a.inHandle = alignedOpposite(a, a.outHandle, a.inHandle);
|
|
3019
|
+
if (bSmooth) b.outHandle = alignedOpposite(b, b.inHandle, b.outHandle);
|
|
3020
|
+
return true;
|
|
2377
3021
|
}
|
|
2378
|
-
function
|
|
2379
|
-
|
|
2380
|
-
const onScreen = (p) => ({ x: p.x * scale2.x, y: p.y * scale2.y });
|
|
2381
|
-
const screenAnchors = set.anchors.map((sub3) => sub3.map((a) => ({
|
|
2382
|
-
...onScreen(a),
|
|
2383
|
-
...a.inHandle ? { inHandle: onScreen(a.inHandle) } : {},
|
|
2384
|
-
...a.outHandle ? { outHandle: onScreen(a.outHandle) } : {}
|
|
2385
|
-
})));
|
|
2386
|
-
const hit = nearestSegmentT(screenAnchors, x * scale2.x, y * scale2.y, set.closed);
|
|
2387
|
-
if (!hit) return null;
|
|
2388
|
-
const ends = segmentEnds(set.anchors, set.closed, hit.sub, hit.segIdx);
|
|
2389
|
-
const point = pointOnSegment(ends.a, ends.b, hit.t);
|
|
2390
|
-
const tol = opts.tolerancePx;
|
|
2391
|
-
if (!withinPxRadius(point.x - x, point.y - y, tol, scale2)) return null;
|
|
2392
|
-
if (withinPxRadius(point.x - ends.a.x, point.y - ends.a.y, tol, scale2)) return null;
|
|
2393
|
-
if (withinPxRadius(point.x - ends.b.x, point.y - ends.b.y, tol, scale2)) return null;
|
|
2394
|
-
return { sub: hit.sub, segIdx: hit.segIdx, t: hit.t, x: point.x, y: point.y };
|
|
3022
|
+
function lerp(a, b, f) {
|
|
3023
|
+
return { x: a.x + (b.x - a.x) * f, y: a.y + (b.y - a.y) * f };
|
|
2395
3024
|
}
|
|
2396
|
-
function
|
|
2397
|
-
|
|
2398
|
-
|
|
3025
|
+
function alignedOpposite(anchor, moved, other2) {
|
|
3026
|
+
const mx = moved.x - anchor.x;
|
|
3027
|
+
const my = moved.y - anchor.y;
|
|
3028
|
+
const len = Math.hypot(mx, my);
|
|
3029
|
+
if (len === 0) return other2;
|
|
3030
|
+
const keep = Math.hypot(other2.x - anchor.x, other2.y - anchor.y);
|
|
3031
|
+
return { x: anchor.x - mx / len * keep, y: anchor.y - my / len * keep };
|
|
2399
3032
|
}
|
|
2400
|
-
|
|
2401
|
-
|
|
3033
|
+
|
|
3034
|
+
// src/paths/handleEdits.ts
|
|
3035
|
+
function retractHandles(set, flatIndexes) {
|
|
3036
|
+
let changed = false;
|
|
2402
3037
|
for (const flat of new Set(flatIndexes)) {
|
|
2403
|
-
const
|
|
2404
|
-
if (!
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
}
|
|
2409
|
-
if (bySub.size === 0) return false;
|
|
2410
|
-
let survivors = 0;
|
|
2411
|
-
for (let s = 0; s < set.anchors.length; s++) {
|
|
2412
|
-
const doomed = bySub.get(s)?.length ?? 0;
|
|
2413
|
-
if (set.anchors[s].length - doomed >= 2) survivors++;
|
|
2414
|
-
}
|
|
2415
|
-
if (survivors === 0) return false;
|
|
2416
|
-
for (const [s, indices] of bySub) {
|
|
2417
|
-
const sub3 = set.anchors[s];
|
|
2418
|
-
if (!sub3) continue;
|
|
2419
|
-
indices.sort((a, b) => b - a);
|
|
2420
|
-
for (const i of indices) {
|
|
2421
|
-
const wraps = set.closed[s] && sub3.length > 2;
|
|
2422
|
-
const prev = wraps ? sub3[(i - 1 + sub3.length) % sub3.length] : sub3[i - 1];
|
|
2423
|
-
const next = wraps ? sub3[(i + 1) % sub3.length] : sub3[i + 1];
|
|
2424
|
-
if (prev && next) {
|
|
2425
|
-
const { c1, c2 } = fitCubicThroughDeletion(prev, next);
|
|
2426
|
-
prev.outHandle = c1;
|
|
2427
|
-
next.inHandle = c2;
|
|
2428
|
-
}
|
|
2429
|
-
sub3.splice(i, 1);
|
|
3038
|
+
const a = anchorAt(set, flat);
|
|
3039
|
+
if (!a) continue;
|
|
3040
|
+
if (a.inHandle) {
|
|
3041
|
+
changed = changed || !same2(a.inHandle, a);
|
|
3042
|
+
delete a.inHandle;
|
|
2430
3043
|
}
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
set.anchors.splice(s, 1);
|
|
2435
|
-
set.closed.splice(s, 1);
|
|
3044
|
+
if (a.outHandle) {
|
|
3045
|
+
changed = changed || !same2(a.outHandle, a);
|
|
3046
|
+
delete a.outHandle;
|
|
2436
3047
|
}
|
|
2437
3048
|
}
|
|
2438
|
-
return
|
|
3049
|
+
return changed;
|
|
2439
3050
|
}
|
|
2440
|
-
function
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
3051
|
+
function makeHandlesSymmetric(set, flatIndexes) {
|
|
3052
|
+
let changed = false;
|
|
3053
|
+
for (const flat of new Set(flatIndexes)) {
|
|
3054
|
+
const loc = locateAnchor(set, flat);
|
|
3055
|
+
if (!loc) continue;
|
|
3056
|
+
const sub3 = set.anchors[loc.sub];
|
|
3057
|
+
const isEnd = !set.closed[loc.sub] && (loc.idx === 0 || loc.idx === sub3.length - 1);
|
|
3058
|
+
if (isEnd) continue;
|
|
3059
|
+
changed = symmetrize(sub3[loc.idx]) || changed;
|
|
3060
|
+
}
|
|
3061
|
+
return changed;
|
|
3062
|
+
}
|
|
3063
|
+
function symmetrize(a) {
|
|
3064
|
+
const out = a.outHandle ? offset(a, a.outHandle) : null;
|
|
3065
|
+
const inFlipped = a.inHandle ? scale2(offset(a, a.inHandle), -1) : null;
|
|
3066
|
+
const outLen = out ? Math.hypot(out.x, out.y) : 0;
|
|
3067
|
+
const inLen = inFlipped ? Math.hypot(inFlipped.x, inFlipped.y) : 0;
|
|
3068
|
+
if (outLen === 0 && inLen === 0) return false;
|
|
3069
|
+
let dir;
|
|
3070
|
+
let len;
|
|
3071
|
+
if (outLen > 0 && inLen > 0) {
|
|
3072
|
+
const sum = { x: out.x / outLen + inFlipped.x / inLen, y: out.y / outLen + inFlipped.y / inLen };
|
|
3073
|
+
const sumLen = Math.hypot(sum.x, sum.y);
|
|
3074
|
+
dir = sumLen > 1e-9 ? scale2(sum, 1 / sumLen) : scale2(out, 1 / outLen);
|
|
3075
|
+
len = (outLen + inLen) / 2;
|
|
3076
|
+
} else if (outLen > 0) {
|
|
3077
|
+
dir = scale2(out, 1 / outLen);
|
|
3078
|
+
len = outLen;
|
|
3079
|
+
} else {
|
|
3080
|
+
dir = scale2(inFlipped, 1 / inLen);
|
|
3081
|
+
len = inLen;
|
|
3082
|
+
}
|
|
3083
|
+
const nextOut = { x: a.x + dir.x * len, y: a.y + dir.y * len };
|
|
3084
|
+
const nextIn = { x: a.x - dir.x * len, y: a.y - dir.y * len };
|
|
3085
|
+
if (same2(a.outHandle, nextOut) && same2(a.inHandle, nextIn)) return false;
|
|
3086
|
+
a.outHandle = nextOut;
|
|
3087
|
+
a.inHandle = nextIn;
|
|
2450
3088
|
return true;
|
|
2451
3089
|
}
|
|
2452
|
-
function
|
|
2453
|
-
const
|
|
2454
|
-
const
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
}
|
|
2463
|
-
|
|
3090
|
+
function handleAlongItsAngle(anchor, handle, to) {
|
|
3091
|
+
const d = offset(anchor, handle);
|
|
3092
|
+
const len = Math.hypot(d.x, d.y);
|
|
3093
|
+
if (len === 0) return { x: to.x, y: to.y };
|
|
3094
|
+
const ux = d.x / len;
|
|
3095
|
+
const uy = d.y / len;
|
|
3096
|
+
const along = Math.max(0, (to.x - anchor.x) * ux + (to.y - anchor.y) * uy);
|
|
3097
|
+
return { x: anchor.x + ux * along, y: anchor.y + uy * along };
|
|
3098
|
+
}
|
|
3099
|
+
function offset(from, to) {
|
|
3100
|
+
return { x: to.x - from.x, y: to.y - from.y };
|
|
3101
|
+
}
|
|
3102
|
+
function scale2(p, k) {
|
|
3103
|
+
return { x: p.x * k, y: p.y * k };
|
|
3104
|
+
}
|
|
3105
|
+
function same2(p, q) {
|
|
3106
|
+
return !!p && Math.abs(p.x - q.x) < 1e-9 && Math.abs(p.y - q.y) < 1e-9;
|
|
2464
3107
|
}
|
|
2465
3108
|
|
|
2466
3109
|
// src/paths/nearestAnchor.ts
|
|
2467
|
-
function nearestPathAnchor(paths, point, px,
|
|
3110
|
+
function nearestPathAnchor(paths, point, px, scale3, accept) {
|
|
2468
3111
|
let best = null;
|
|
2469
3112
|
let bestD2 = px * px;
|
|
2470
3113
|
for (const { id, path } of paths) {
|
|
@@ -2473,7 +3116,7 @@ function nearestPathAnchor(paths, point, px, scale2, accept) {
|
|
|
2473
3116
|
const list = anchors[sub3];
|
|
2474
3117
|
for (let idx = 0; idx < list.length; idx++) {
|
|
2475
3118
|
const a = list[idx];
|
|
2476
|
-
const s = scaleDelta(a.x - point.x, a.y - point.y,
|
|
3119
|
+
const s = scaleDelta(a.x - point.x, a.y - point.y, scale3);
|
|
2477
3120
|
const d2 = s.x * s.x + s.y * s.y;
|
|
2478
3121
|
if (d2 > bestD2 || best !== null && d2 === bestD2) continue;
|
|
2479
3122
|
const end = closed[sub3] ? null : idx === list.length - 1 ? "last" : idx === 0 ? "first" : null;
|
|
@@ -2580,6 +3223,6 @@ function typedArrayReplacer(_key, value) {
|
|
|
2580
3223
|
return tagTypedArray(value) ?? value;
|
|
2581
3224
|
}
|
|
2582
3225
|
|
|
2583
|
-
export { EASINGS, PathBuilder, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, anchorAt, anchorCount, anchorsInRect, anchorsToPath, applyToPoint, boundsOfPath, boxToBox, circlePath, clampRectWithin, composePath, countPathAnchors, cubicBezierEasing, decomposePath, deleteAnchorsAt, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, ellipsePath, flatAnchorIndex, hasOpenSubpath, identity, insertAnchorOnSegment, invert, isAnchorSmooth, isStraightSegment, linePath, linear, locateAnchor, mat3, meanScale, moveHandleTo, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestPathAnchor, nearestSegmentT, normalizeZoom, openSubpathAt, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, pathThroughPoseFrame, pathToAnchors, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, pxExtent, rectMarkerPath, rectPath, regularPolygonPath, resolveEasing, reverseAnchors, reversePath, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, schneiderFit, screenAngleOf, segmentAt, segmentEnds, splitByClosure, splitSubpaths, squarePath, standoff, starPath, strokeHitTest, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translatePath, typedArrayReplacer, unionBoundsPath, untagTypedArray, viewToMat3, withinPxBox, withinPxRadius, worldEditToStorage };
|
|
3226
|
+
export { EASINGS, PathBuilder, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, anchorAt, anchorCount, anchorSymmetries, anchorSymmetry, anchorsInRect, anchorsToPath, applyToPoint, averageAnchorsAt, bendSegment, boundsOfPath, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, countPathAnchors, cubicBezierEasing, decomposePath, deleteAnchorsAt, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, editAnchorSetTracked, ellipsePath, fitCubicThroughDeletion, fitCubicWithTangents, flatAnchorIndex, handleAlongItsAngle, hasOpenSubpath, identity, insertAnchorOnSegment, invert, isAnchorSmooth, isStraightSegment, joinAnchorsAt, joinSubpathEnds, linePath, linear, locateAnchor, makeHandlesSymmetric, mat3, meanScale, moveHandleSymmetric, moveHandleTo, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestPathAnchor, nearestSegmentT, normalizeZoom, openSubpathAt, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, pathThroughPoseFrame, pathToAnchors, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, pxExtent, rectMarkerPath, rectPath, regularPolygonPath, remapPointValues, resolveEasing, retractHandles, reverseAnchors, reversePath, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, schneiderFit, screenAngleOf, segmentAt, segmentEnds, simplifyPath, splitByClosure, splitSubpaths, squarePath, standoff, starPath, strokeHitTest, subpathEndAt, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, typedArrayReplacer, unionBoundsPath, untagTypedArray, viewToMat3, withinPxBox, withinPxRadius, worldEditToStorage };
|
|
2584
3227
|
//# sourceMappingURL=index.js.map
|
|
2585
3228
|
//# sourceMappingURL=index.js.map
|