@weasel-js/geom 1.11.0 → 1.11.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/dist/booleans/index.d.ts +3 -1
- package/dist/booleans/index.js +138 -11
- package/dist/booleans/index.js.map +1 -1
- package/dist/{chunk-7KLJZFBY.js → chunk-4Y67BZL5.js} +3 -3
- package/dist/{chunk-7KLJZFBY.js.map → chunk-4Y67BZL5.js.map} +1 -1
- package/dist/{chunk-HGF5OVEN.js → chunk-6FGQML7D.js} +29 -6
- package/dist/chunk-6FGQML7D.js.map +1 -0
- package/dist/{chunk-6XSJY3TC.js → chunk-7F66PQCJ.js} +3 -3
- package/dist/{chunk-6XSJY3TC.js.map → chunk-7F66PQCJ.js.map} +1 -1
- package/dist/{chunk-J2O2B54M.js → chunk-EAKE3N7W.js} +13 -9
- package/dist/chunk-EAKE3N7W.js.map +1 -0
- package/dist/{chunk-SASMXDBE.js → chunk-LRVPK7HI.js} +83 -35
- package/dist/chunk-LRVPK7HI.js.map +1 -0
- package/dist/index.d.ts +47 -3
- package/dist/index.js +331 -28
- package/dist/index.js.map +1 -1
- package/dist/nd/index.d.ts +2 -1
- package/dist/nd/index.js +44 -29
- package/dist/nd/index.js.map +1 -1
- package/dist/tessellate/index.js +3 -3
- package/dist/warp/index.d.ts +7 -5
- package/dist/warp/index.js +145 -13
- package/dist/warp/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-HGF5OVEN.js.map +0 -1
- package/dist/chunk-J2O2B54M.js.map +0 -1
- package/dist/chunk-SASMXDBE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { carryCorners, evalSeg, parseSubpaths, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-
|
|
2
|
-
export { CORNER_RESTORE_TOLERANCE, cornerTraces, keepCorners, restoreCorners } from './chunk-
|
|
1
|
+
import { carryCorners, evalSeg, parseSubpaths, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-4Y67BZL5.js';
|
|
2
|
+
export { CORNER_RESTORE_TOLERANCE, cornerTraces, keepCorners, restoreCorners } from './chunk-4Y67BZL5.js';
|
|
3
3
|
import { PORT_REACH, portControls, portCurvePoints } from './chunk-YQADYJJ7.js';
|
|
4
4
|
export { PORT_REACH } from './chunk-YQADYJJ7.js';
|
|
5
5
|
import { cubicDerivativeAt, cubicCurvatureAt } from './chunk-UI3FUWXM.js';
|
|
6
6
|
export { SPIRO_KINDS, combTeeth, cubicCurvatureAt, cubicCurvatureSource, cubicDerivativeAt, curvatureComb, eulerAngleAt, eulerCurvatureAt, eulerCurvatureDerivativesAt, eulerPointAt, fitEulerSegment, isSpiroKind, placeEulerSegment, solveSpiro, spiroContoursFromControl, spiroContoursOf, spiroControlPath, spiroToPath } from './chunk-UI3FUWXM.js';
|
|
7
|
-
import { extractPolylines } from './chunk-
|
|
8
|
-
import { boundsOfPath, fitPointRun, keepCorner } from './chunk-
|
|
9
|
-
export { boundsOfPath } from './chunk-
|
|
7
|
+
import { extractPolylines } from './chunk-7F66PQCJ.js';
|
|
8
|
+
import { boundsOfPath, fitPointRun, keepCorner } from './chunk-6FGQML7D.js';
|
|
9
|
+
export { boundsOfPath } from './chunk-6FGQML7D.js';
|
|
10
10
|
import { countPathAnchors, pathToAnchors, anchorsToPath, isAnchorSmooth, segmentEnds, isStraightSegment, nearestSegmentT } from './chunk-Q66NA2FU.js';
|
|
11
11
|
export { anchorsToPath, countPathAnchors, isAnchorSmooth, isStraightSegment, nearestSegmentT, pathToAnchors, segmentEnds } from './chunk-Q66NA2FU.js';
|
|
12
12
|
import { nearestOnPath, nearestOnLine, nearestOnQuadratic, nearestOnCubic } from './chunk-CE7IY7TB.js';
|
|
13
13
|
export { nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic } from './chunk-CE7IY7TB.js';
|
|
14
|
-
import { pointInPolygon, resolveCorners, cornerCuts, fillsOpenSubpaths, schneiderFit, fitCubicWithTangents, pointSegmentDist2, flattenQuadratic,
|
|
15
|
-
export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, pointSegmentDist2, remapPerAnchor, resolveCorners, resolveCornersWithSources, schneiderFit, segmentsCross, setDefaultOpenFill } from './chunk-
|
|
14
|
+
import { pointInPolygon, resolveCorners, cornerCuts, fillsOpenSubpaths, schneiderFit, fitCubicWithTangents, flattenCubic, pointSegmentDist2, flattenQuadratic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-EAKE3N7W.js';
|
|
15
|
+
export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, pointSegmentDist2, remapPerAnchor, resolveCorners, resolveCornersWithSources, schneiderFit, segmentsCross, setDefaultOpenFill } from './chunk-EAKE3N7W.js';
|
|
16
16
|
import { SINGULAR_RATIO } from './chunk-755Y4YZS.js';
|
|
17
17
|
export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-755Y4YZS.js';
|
|
18
18
|
import { PathBuilder, withCorner, scaleCorners, forEachSegment, pathCommandCoordCount, withoutCorners, PATH_M, PATH_Z, PATH_L, PATH_C, PATH_Q, elevateQuadraticToCubic, cubicEvalAt, cubicPointAt, splitCubicAtT, cubicAxisExtremaTs, rectToContour, splitCubicAt } from './chunk-B53BERKG.js';
|
|
@@ -270,7 +270,7 @@ function pointInPath(path, x, y, opts = {}) {
|
|
|
270
270
|
return x >= path.x && x <= path.x + path.width && y >= path.y && y <= path.y + path.height;
|
|
271
271
|
}
|
|
272
272
|
let crossings = 0;
|
|
273
|
-
let
|
|
273
|
+
let winding2 = 0;
|
|
274
274
|
for (const sub3 of closedSubpaths(path, opts)) {
|
|
275
275
|
const n = sub3.length;
|
|
276
276
|
for (let i = 0; i < n; i += 2) {
|
|
@@ -280,10 +280,10 @@ function pointInPath(path, x, y, opts = {}) {
|
|
|
280
280
|
const ax = sub3[i], bx = sub3[j];
|
|
281
281
|
if (x >= ax + (y - ay) / (by - ay) * (bx - ax)) continue;
|
|
282
282
|
crossings++;
|
|
283
|
-
|
|
283
|
+
winding2 += ay <= y ? 1 : -1;
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
-
return path.fillRule === "evenodd" ? (crossings & 1) === 1 :
|
|
286
|
+
return path.fillRule === "evenodd" ? (crossings & 1) === 1 : winding2 !== 0;
|
|
287
287
|
}
|
|
288
288
|
function strokeHitTest(path, x, y, threshold, opts = {}) {
|
|
289
289
|
const slop = opts.slop;
|
|
@@ -620,7 +620,7 @@ function splitSubpaths(path) {
|
|
|
620
620
|
let coordStart = 0;
|
|
621
621
|
let anchorStart = 0;
|
|
622
622
|
let anchors = 0;
|
|
623
|
-
const
|
|
623
|
+
const emit2 = (end, coordEnd) => {
|
|
624
624
|
const sub3 = { ...bare, commands: commands.slice(cmdStart, end), coords: coords.slice(coordStart, coordEnd) };
|
|
625
625
|
const count = anchors - anchorStart;
|
|
626
626
|
out.push(path.corners ? carryCorners(path, sub3, anchorRange(anchorStart, count)) : sub3);
|
|
@@ -628,13 +628,13 @@ function splitSubpaths(path) {
|
|
|
628
628
|
};
|
|
629
629
|
forEachSegment(commands, coords, (cmd, ci, _px, _py, i) => {
|
|
630
630
|
if (cmd === PATH_M && i > cmdStart) {
|
|
631
|
-
|
|
631
|
+
emit2(i, ci);
|
|
632
632
|
cmdStart = i;
|
|
633
633
|
coordStart = ci;
|
|
634
634
|
}
|
|
635
635
|
if (cmd !== PATH_Z) anchors++;
|
|
636
636
|
});
|
|
637
|
-
|
|
637
|
+
emit2(commands.length, coords.length);
|
|
638
638
|
return out;
|
|
639
639
|
}
|
|
640
640
|
|
|
@@ -812,8 +812,8 @@ function reversePath(path) {
|
|
|
812
812
|
anchor++;
|
|
813
813
|
});
|
|
814
814
|
flush(false);
|
|
815
|
-
const
|
|
816
|
-
return path.corners ? carryCorners(path,
|
|
815
|
+
const reversed3 = { ...path, commands: new Uint8Array(cmds), coords: new Float32Array(out) };
|
|
816
|
+
return path.corners ? carryCorners(path, reversed3, sources) : reversed3;
|
|
817
817
|
}
|
|
818
818
|
|
|
819
819
|
// src/paths/pathFromD.ts
|
|
@@ -1074,9 +1074,9 @@ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep,
|
|
|
1074
1074
|
rys = ryFixed * ryFixed;
|
|
1075
1075
|
}
|
|
1076
1076
|
const sign2 = largeArc === sweep ? -1 : 1;
|
|
1077
|
-
const
|
|
1077
|
+
const num2 = rxs * rys - rxs * y1ps - rys * x1ps;
|
|
1078
1078
|
const den = rxs * y1ps + rys * x1ps;
|
|
1079
|
-
const factor = sign2 * Math.sqrt(Math.max(0,
|
|
1079
|
+
const factor = sign2 * Math.sqrt(Math.max(0, num2 / den));
|
|
1080
1080
|
const cxp = factor * (rxFixed * y1p) / ryFixed;
|
|
1081
1081
|
const cyp = factor * -(ryFixed * x1p) / rxFixed;
|
|
1082
1082
|
const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
|
|
@@ -1124,6 +1124,41 @@ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep,
|
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
1126
1126
|
|
|
1127
|
+
// src/paths/pathToD.ts
|
|
1128
|
+
var num = (n) => Number.isFinite(n) ? String(Math.round(n * 1e6) / 1e6) : "0";
|
|
1129
|
+
function pathToD(given) {
|
|
1130
|
+
const path = resolveCorners(given);
|
|
1131
|
+
if (path.kind === "rect") {
|
|
1132
|
+
const { x, y, width, height } = path;
|
|
1133
|
+
return `M${num(x)} ${num(y)}h${num(width)}v${num(height)}h${num(-width)}Z`;
|
|
1134
|
+
}
|
|
1135
|
+
const cmds = path.commands;
|
|
1136
|
+
const xs = path.coords;
|
|
1137
|
+
const out = [];
|
|
1138
|
+
let ci = 0;
|
|
1139
|
+
for (let i = 0; i < cmds.length; i++) {
|
|
1140
|
+
const c = cmds[i];
|
|
1141
|
+
if (c === PATH_M) {
|
|
1142
|
+
out.push(`M${num(xs[ci])} ${num(xs[ci + 1])}`);
|
|
1143
|
+
ci += 2;
|
|
1144
|
+
} else if (c === PATH_L) {
|
|
1145
|
+
out.push(`L${num(xs[ci])} ${num(xs[ci + 1])}`);
|
|
1146
|
+
ci += 2;
|
|
1147
|
+
} else if (c === PATH_C) {
|
|
1148
|
+
out.push(
|
|
1149
|
+
`C${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])} ${num(xs[ci + 4])} ${num(xs[ci + 5])}`
|
|
1150
|
+
);
|
|
1151
|
+
ci += 6;
|
|
1152
|
+
} else if (c === PATH_Q) {
|
|
1153
|
+
out.push(`Q${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])}`);
|
|
1154
|
+
ci += 4;
|
|
1155
|
+
} else if (c === PATH_Z) {
|
|
1156
|
+
out.push("Z");
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
return out.join("");
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1127
1162
|
// src/paths/pathMeasure.ts
|
|
1128
1163
|
function measurePath(path, opts = {}) {
|
|
1129
1164
|
const polylines = extractPolylines(
|
|
@@ -1162,7 +1197,17 @@ function measurePath(path, opts = {}) {
|
|
|
1162
1197
|
const origin = first;
|
|
1163
1198
|
const closed = contours === 1 && lastClosed;
|
|
1164
1199
|
if (segments.length === 0) {
|
|
1165
|
-
return {
|
|
1200
|
+
return {
|
|
1201
|
+
length: 0,
|
|
1202
|
+
closed,
|
|
1203
|
+
at: () => ({ point: { ...origin }, tangent: { x: 1, y: 0 } }),
|
|
1204
|
+
nearest: (p) => ({
|
|
1205
|
+
s: 0,
|
|
1206
|
+
dist: Math.hypot(p.x - origin.x, p.y - origin.y),
|
|
1207
|
+
point: { ...origin },
|
|
1208
|
+
tangent: { x: 1, y: 0 }
|
|
1209
|
+
})
|
|
1210
|
+
};
|
|
1166
1211
|
}
|
|
1167
1212
|
return {
|
|
1168
1213
|
length: total,
|
|
@@ -1177,6 +1222,26 @@ function measurePath(path, opts = {}) {
|
|
|
1177
1222
|
const y = seg.t0y + (seg.t1y - seg.t0y) * u;
|
|
1178
1223
|
const l = Math.hypot(x, y);
|
|
1179
1224
|
return { point, tangent: l === 0 ? { x: seg.tx, y: seg.ty } : { x: x / l, y: y / l } };
|
|
1225
|
+
},
|
|
1226
|
+
nearest(p) {
|
|
1227
|
+
let best = segments[0];
|
|
1228
|
+
let bestU = 0;
|
|
1229
|
+
let bestDist = Infinity;
|
|
1230
|
+
for (const seg of segments) {
|
|
1231
|
+
const u = Math.min(Math.max(((p.x - seg.ax) * seg.tx + (p.y - seg.ay) * seg.ty) / seg.len, 0), 1);
|
|
1232
|
+
const d = Math.hypot(p.x - (seg.ax + (seg.bx - seg.ax) * u), p.y - (seg.ay + (seg.by - seg.ay) * u));
|
|
1233
|
+
if (d < bestDist) {
|
|
1234
|
+
best = seg;
|
|
1235
|
+
bestU = u;
|
|
1236
|
+
bestDist = d;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
return {
|
|
1240
|
+
s: best.start + best.len * bestU,
|
|
1241
|
+
dist: bestDist,
|
|
1242
|
+
point: { x: best.ax + (best.bx - best.ax) * bestU, y: best.ay + (best.by - best.ay) * bestU },
|
|
1243
|
+
tangent: { x: best.tx, y: best.ty }
|
|
1244
|
+
};
|
|
1180
1245
|
}
|
|
1181
1246
|
};
|
|
1182
1247
|
}
|
|
@@ -1381,13 +1446,13 @@ function matchContours(a, b, opts) {
|
|
|
1381
1446
|
const offset2 = Math.round(opts.startOffset ?? 0);
|
|
1382
1447
|
const directions = opts.reverse !== void 0 ? [opts.reverse] : auto ? [false, true] : [false];
|
|
1383
1448
|
let best = null;
|
|
1384
|
-
for (const
|
|
1385
|
-
const run3 =
|
|
1449
|
+
for (const reversed3 of directions) {
|
|
1450
|
+
const run3 = reversed3 ? reverseContour(y) : y;
|
|
1386
1451
|
const turns = closed && auto ? run3.segs.length : 1;
|
|
1387
1452
|
for (let k = 0; k < turns; k++) {
|
|
1388
1453
|
const [ma, mb] = equalize(x, rotate2(run3, k));
|
|
1389
1454
|
const score = auto ? correspondence(ma, mb) : 0;
|
|
1390
|
-
if (best === null || score < best.score - 1e-9) best = { score, a: ma, b: mb, reversed:
|
|
1455
|
+
if (best === null || score < best.score - 1e-9) best = { score, a: ma, b: mb, reversed: reversed3, turn: k };
|
|
1391
1456
|
}
|
|
1392
1457
|
}
|
|
1393
1458
|
const chosen = best;
|
|
@@ -3110,6 +3175,243 @@ function emitContour(b, grown) {
|
|
|
3110
3175
|
b.close();
|
|
3111
3176
|
}
|
|
3112
3177
|
|
|
3178
|
+
// src/paths/segmentCrossings.ts
|
|
3179
|
+
var STEPS = 16;
|
|
3180
|
+
var END2 = 1e-7;
|
|
3181
|
+
function segmentCrossings(segs) {
|
|
3182
|
+
const flat = segs.map((s) => flatten2(s));
|
|
3183
|
+
const boxes = flat.map(boxOf2);
|
|
3184
|
+
const out = [];
|
|
3185
|
+
for (let a = 0; a < segs.length; a++) {
|
|
3186
|
+
for (let b = a + 1; b < segs.length; b++) {
|
|
3187
|
+
if (!overlaps(boxes[a], boxes[b])) continue;
|
|
3188
|
+
const pa = flat[a], pb = flat[b];
|
|
3189
|
+
for (let i = 0; i + 1 < pa.length; i++) {
|
|
3190
|
+
for (let j = 0; j + 1 < pb.length; j++) {
|
|
3191
|
+
const hit = linesCross(pa[i], pa[i + 1], pb[j], pb[j + 1]);
|
|
3192
|
+
if (hit === null) continue;
|
|
3193
|
+
const guess = [(i + hit[0]) / (pa.length - 1), (j + hit[1]) / (pb.length - 1)];
|
|
3194
|
+
const [s, t] = segs[a].line && segs[b].line ? guess : refine2(segs[a].c, segs[b].c, guess);
|
|
3195
|
+
if (atEnd(s) && atEnd(t)) continue;
|
|
3196
|
+
if (out.some((x) => x.a === a && x.b === b && Math.abs(x.s - s) < 1e-6 && Math.abs(x.t - t) < 1e-6)) continue;
|
|
3197
|
+
out.push({ a, b, s, t });
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
return out;
|
|
3203
|
+
}
|
|
3204
|
+
var atEnd = (t) => t < END2 || t > 1 - END2;
|
|
3205
|
+
function flatten2(seg) {
|
|
3206
|
+
if (seg.line) return [[seg.c[0], seg.c[1]], [seg.c[6], seg.c[7]]];
|
|
3207
|
+
const out = [];
|
|
3208
|
+
for (let i = 0; i <= STEPS; i++) out.push(cubicEvalAt(...seg.c, i / STEPS));
|
|
3209
|
+
return out;
|
|
3210
|
+
}
|
|
3211
|
+
function boxOf2(pts) {
|
|
3212
|
+
const b = [Infinity, Infinity, -Infinity, -Infinity];
|
|
3213
|
+
for (const [x, y] of pts) {
|
|
3214
|
+
b[0] = Math.min(b[0], x);
|
|
3215
|
+
b[1] = Math.min(b[1], y);
|
|
3216
|
+
b[2] = Math.max(b[2], x);
|
|
3217
|
+
b[3] = Math.max(b[3], y);
|
|
3218
|
+
}
|
|
3219
|
+
return b;
|
|
3220
|
+
}
|
|
3221
|
+
var overlaps = (p, q) => p[0] <= q[2] && q[0] <= p[2] && p[1] <= q[3] && q[1] <= p[3];
|
|
3222
|
+
function linesCross(a, b, c, d) {
|
|
3223
|
+
const rx = b[0] - a[0], ry = b[1] - a[1], sx = d[0] - c[0], sy = d[1] - c[1];
|
|
3224
|
+
const den = rx * sy - ry * sx;
|
|
3225
|
+
if (Math.abs(den) < 1e-18) return null;
|
|
3226
|
+
const u = ((c[0] - a[0]) * sy - (c[1] - a[1]) * sx) / den;
|
|
3227
|
+
const w = ((c[0] - a[0]) * ry - (c[1] - a[1]) * rx) / den;
|
|
3228
|
+
return u >= 0 && u <= 1 && w >= 0 && w <= 1 ? [u, w] : null;
|
|
3229
|
+
}
|
|
3230
|
+
function refine2(a, b, guess) {
|
|
3231
|
+
const gap = (s2, t2) => {
|
|
3232
|
+
const p = cubicEvalAt(...a, s2), q = cubicEvalAt(...b, t2);
|
|
3233
|
+
return [p[0] - q[0], p[1] - q[1]];
|
|
3234
|
+
};
|
|
3235
|
+
let [s, t] = guess;
|
|
3236
|
+
let f = gap(s, t);
|
|
3237
|
+
const start = Math.hypot(...f);
|
|
3238
|
+
for (let k = 0; k < 8 && Math.hypot(...f) > 1e-13; k++) {
|
|
3239
|
+
const da = derivative2(a, s), db = derivative2(b, t);
|
|
3240
|
+
const det = -da[0] * db[1] + db[0] * da[1];
|
|
3241
|
+
if (Math.abs(det) < 1e-18) break;
|
|
3242
|
+
s = Math.min(1, Math.max(0, s - (-db[1] * f[0] + db[0] * f[1]) / det));
|
|
3243
|
+
t = Math.min(1, Math.max(0, t - (-da[1] * f[0] + da[0] * f[1]) / det));
|
|
3244
|
+
f = gap(s, t);
|
|
3245
|
+
}
|
|
3246
|
+
return Math.hypot(...f) <= start ? [s, t] : guess;
|
|
3247
|
+
}
|
|
3248
|
+
function derivative2(c, t) {
|
|
3249
|
+
const u = 1 - t;
|
|
3250
|
+
const a = 3 * u * u, b = 6 * u * t, e = 3 * t * t;
|
|
3251
|
+
return [
|
|
3252
|
+
a * (c[2] - c[0]) + b * (c[4] - c[2]) + e * (c[6] - c[4]),
|
|
3253
|
+
a * (c[3] - c[1]) + b * (c[5] - c[3]) + e * (c[7] - c[5])
|
|
3254
|
+
];
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
// src/paths/mergeRegion.ts
|
|
3258
|
+
function mergeRegion(path, opts = {}) {
|
|
3259
|
+
const tol = opts.tolerance ?? 0.01;
|
|
3260
|
+
const contours = pathToCubicContours(path).filter((c) => c.segs.length > 0);
|
|
3261
|
+
const segs = contours.flatMap((c) => closeContour(c.segs, tol * 1e-3));
|
|
3262
|
+
const fillLeft = pathSignedArea(path) < 0;
|
|
3263
|
+
const cuts = segs.map(() => []);
|
|
3264
|
+
for (const x of segmentCrossings(segs)) {
|
|
3265
|
+
const p = crossingPoint(segs[x.a], x.s, segs[x.b], x.t);
|
|
3266
|
+
cuts[x.a].push({ t: x.s, p });
|
|
3267
|
+
cuts[x.b].push({ t: x.t, p });
|
|
3268
|
+
}
|
|
3269
|
+
const rings = flattenAll(segs, tol / 4);
|
|
3270
|
+
const pieces = [];
|
|
3271
|
+
let changed = false;
|
|
3272
|
+
segs.forEach((seg, i) => {
|
|
3273
|
+
const parts = cutSegment(seg, cuts[i]);
|
|
3274
|
+
if (parts.length > 1) changed = true;
|
|
3275
|
+
for (const part of parts) {
|
|
3276
|
+
const side = filledSide(part, rings, tol);
|
|
3277
|
+
if (side === null) changed = true;
|
|
3278
|
+
else if (side === fillLeft) pieces.push(part);
|
|
3279
|
+
else {
|
|
3280
|
+
changed = true;
|
|
3281
|
+
pieces.push(reversed2(part));
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
});
|
|
3285
|
+
const b = new PathBuilder();
|
|
3286
|
+
if (!changed) {
|
|
3287
|
+
for (const c of contours) emit(b, closeContour(c.segs, tol * 1e-3));
|
|
3288
|
+
return b.build();
|
|
3289
|
+
}
|
|
3290
|
+
for (const ring of chain(pieces)) emit(b, ring);
|
|
3291
|
+
return b.build();
|
|
3292
|
+
}
|
|
3293
|
+
function closeContour(given, snap2) {
|
|
3294
|
+
const short = (s) => s.line && Math.hypot(s.c[6] - s.c[0], s.c[7] - s.c[1]) <= snap2;
|
|
3295
|
+
const segs = given.filter((s) => !short(s));
|
|
3296
|
+
if (segs.length === 0) return [];
|
|
3297
|
+
for (let i = 0; i < segs.length; i++) {
|
|
3298
|
+
const prev = segs[(i + segs.length - 1) % segs.length].c, s = segs[i];
|
|
3299
|
+
if (prev[6] !== s.c[0] || prev[7] !== s.c[1]) {
|
|
3300
|
+
if (Math.hypot(prev[6] - s.c[0], prev[7] - s.c[1]) <= snap2) segs[i] = moveEnds(s, [prev[6], prev[7]], [s.c[6], s.c[7]]);
|
|
3301
|
+
else if (i === 0) segs.push(lineSegment(prev[6], prev[7], s.c[0], s.c[1]));
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
return segs;
|
|
3305
|
+
}
|
|
3306
|
+
function crossingPoint(a, s, b, t) {
|
|
3307
|
+
const end = (seg, u) => u <= 1e-7 ? [seg.c[0], seg.c[1]] : u >= 1 - 1e-7 ? [seg.c[6], seg.c[7]] : null;
|
|
3308
|
+
const fixed = end(a, s) ?? end(b, t);
|
|
3309
|
+
if (fixed) return fixed;
|
|
3310
|
+
const p = cubicEvalAt(...a.c, s), q = cubicEvalAt(...b.c, t);
|
|
3311
|
+
return [(p[0] + q[0]) / 2, (p[1] + q[1]) / 2];
|
|
3312
|
+
}
|
|
3313
|
+
function cutSegment(seg, cuts) {
|
|
3314
|
+
const inner = cuts.filter((c) => c.t > 1e-7 && c.t < 1 - 1e-7).sort((x, y) => x.t - y.t);
|
|
3315
|
+
const out = [];
|
|
3316
|
+
let rest = seg, from = 0;
|
|
3317
|
+
let start = [seg.c[0], seg.c[1]];
|
|
3318
|
+
for (const cut of inner) {
|
|
3319
|
+
if (cut.t - from < 1e-9) continue;
|
|
3320
|
+
const [l, r] = splitSegment(rest, (cut.t - from) / (1 - from));
|
|
3321
|
+
out.push(moveEnds(l, start, cut.p));
|
|
3322
|
+
rest = r;
|
|
3323
|
+
from = cut.t;
|
|
3324
|
+
start = cut.p;
|
|
3325
|
+
}
|
|
3326
|
+
out.push(moveEnds(rest, start, [seg.c[6], seg.c[7]]));
|
|
3327
|
+
return out;
|
|
3328
|
+
}
|
|
3329
|
+
function moveEnds(s, a, b) {
|
|
3330
|
+
const c = s.c;
|
|
3331
|
+
return {
|
|
3332
|
+
c: [a[0], a[1], c[2] + a[0] - c[0], c[3] + a[1] - c[1], c[4] + b[0] - c[6], c[5] + b[1] - c[7], b[0], b[1]],
|
|
3333
|
+
line: s.line
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
3336
|
+
function reversed2(s) {
|
|
3337
|
+
const c = s.c;
|
|
3338
|
+
return { c: [c[6], c[7], c[4], c[5], c[2], c[3], c[0], c[1]], line: s.line };
|
|
3339
|
+
}
|
|
3340
|
+
function flattenAll(segs, tol) {
|
|
3341
|
+
const rings = [];
|
|
3342
|
+
let ring = [];
|
|
3343
|
+
for (const { c, line } of segs) {
|
|
3344
|
+
if (ring.length === 0) ring.push(c[0], c[1]);
|
|
3345
|
+
else if (ring[ring.length - 2] !== c[0] || ring[ring.length - 1] !== c[1]) {
|
|
3346
|
+
rings.push(ring);
|
|
3347
|
+
ring = [c[0], c[1]];
|
|
3348
|
+
}
|
|
3349
|
+
if (line) ring.push(c[6], c[7]);
|
|
3350
|
+
else flattenCubic(...c, tol, ring);
|
|
3351
|
+
}
|
|
3352
|
+
if (ring.length > 0) rings.push(ring);
|
|
3353
|
+
return rings;
|
|
3354
|
+
}
|
|
3355
|
+
function winding(rings, x, y) {
|
|
3356
|
+
let w = 0;
|
|
3357
|
+
for (const r of rings) {
|
|
3358
|
+
for (let i = 0; i + 3 < r.length; i += 2) {
|
|
3359
|
+
const ay = r[i + 1], by = r[i + 3];
|
|
3360
|
+
if (ay > y === by > y) continue;
|
|
3361
|
+
const ax = r[i], bx = r[i + 2];
|
|
3362
|
+
if (x >= ax + (y - ay) / (by - ay) * (bx - ax)) continue;
|
|
3363
|
+
w += ay <= y ? 1 : -1;
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
return w;
|
|
3367
|
+
}
|
|
3368
|
+
function filledSide(seg, rings, tol) {
|
|
3369
|
+
const c = seg.c;
|
|
3370
|
+
const [x, y] = cubicEvalAt(...c, 0.5);
|
|
3371
|
+
const dx2 = c[6] + c[4] - c[2] - c[0], dy2 = c[7] + c[5] - c[3] - c[1];
|
|
3372
|
+
const len = Math.hypot(dx2, dy2);
|
|
3373
|
+
if (len < 1e-12) return null;
|
|
3374
|
+
const nx = dy2 / len * tol, ny = -dx2 / len * tol;
|
|
3375
|
+
const left = winding(rings, x + nx, y + ny) !== 0, right = winding(rings, x - nx, y - ny) !== 0;
|
|
3376
|
+
return left === right ? null : left;
|
|
3377
|
+
}
|
|
3378
|
+
function chain(pieces) {
|
|
3379
|
+
const key = (x, y) => `${x},${y}`;
|
|
3380
|
+
const from = /* @__PURE__ */ new Map();
|
|
3381
|
+
pieces.forEach((p, i) => {
|
|
3382
|
+
const k = key(p.c[0], p.c[1]);
|
|
3383
|
+
const list = from.get(k);
|
|
3384
|
+
if (list) list.push(i);
|
|
3385
|
+
else from.set(k, [i]);
|
|
3386
|
+
});
|
|
3387
|
+
const used = new Uint8Array(pieces.length);
|
|
3388
|
+
const rings = [];
|
|
3389
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
3390
|
+
if (used[i]) continue;
|
|
3391
|
+
const ring = [];
|
|
3392
|
+
let at2 = i;
|
|
3393
|
+
while (at2 !== void 0 && !used[at2]) {
|
|
3394
|
+
used[at2] = 1;
|
|
3395
|
+
const p = pieces[at2];
|
|
3396
|
+
ring.push(p);
|
|
3397
|
+
at2 = from.get(key(p.c[6], p.c[7]))?.find((j) => !used[j]);
|
|
3398
|
+
}
|
|
3399
|
+
rings.push(ring);
|
|
3400
|
+
}
|
|
3401
|
+
return rings;
|
|
3402
|
+
}
|
|
3403
|
+
function emit(b, ring) {
|
|
3404
|
+
if (ring.length === 0) return;
|
|
3405
|
+
const [x0, y0] = ring[0].c;
|
|
3406
|
+
b.moveTo(x0, y0);
|
|
3407
|
+
for (const [i, { c, line }] of ring.entries()) {
|
|
3408
|
+
if (line && i === ring.length - 1 && c[6] === x0 && c[7] === y0) break;
|
|
3409
|
+
if (line) b.lineTo(c[6], c[7]);
|
|
3410
|
+
else b.curveTo(c[2], c[3], c[4], c[5], c[6], c[7]);
|
|
3411
|
+
}
|
|
3412
|
+
b.close();
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3113
3415
|
// src/paths/simplifyAnchors.ts
|
|
3114
3416
|
function simplifyAnchorsAt(set, flatIndexes, tolerance, opts = {}) {
|
|
3115
3417
|
const bySub = /* @__PURE__ */ new Map();
|
|
@@ -3164,7 +3466,7 @@ var unit3 = (x, y) => {
|
|
|
3164
3466
|
const len = Math.hypot(x, y);
|
|
3165
3467
|
return len === 0 ? { x: 0, y: 0 } : { x: x / len, y: y / len };
|
|
3166
3468
|
};
|
|
3167
|
-
function
|
|
3469
|
+
function derivative3(seg, t) {
|
|
3168
3470
|
const u = 1 - t;
|
|
3169
3471
|
const { a, c1, c2, b } = seg;
|
|
3170
3472
|
return {
|
|
@@ -3174,8 +3476,8 @@ function derivative2(seg, t) {
|
|
|
3174
3476
|
}
|
|
3175
3477
|
function headingOn(seg, t) {
|
|
3176
3478
|
if (seg.straight) return unit3(seg.b.x - seg.a.x, seg.b.y - seg.a.y);
|
|
3177
|
-
let d =
|
|
3178
|
-
if (Math.hypot(d.x, d.y) < 1e-9) d =
|
|
3479
|
+
let d = derivative3(seg, t);
|
|
3480
|
+
if (Math.hypot(d.x, d.y) < 1e-9) d = derivative3(seg, t < 0.5 ? t + 1e-3 : t - 1e-3);
|
|
3179
3481
|
const h = unit3(d.x, d.y);
|
|
3180
3482
|
return h.x === 0 && h.y === 0 ? unit3(seg.b.x - seg.a.x, seg.b.y - seg.a.y) : h;
|
|
3181
3483
|
}
|
|
@@ -4338,7 +4640,7 @@ function smudgePath(path, opts) {
|
|
|
4338
4640
|
if (!(radius > 0) || strength === 0 || delta.x === 0 && delta.y === 0) return path;
|
|
4339
4641
|
const detail = opts.detail ?? radius / 3;
|
|
4340
4642
|
return editAnchorSet(path, (set) => {
|
|
4341
|
-
|
|
4643
|
+
refine3(set, center, radius, detail);
|
|
4342
4644
|
let touched = false;
|
|
4343
4645
|
let flat = 0;
|
|
4344
4646
|
for (const sub3 of set.anchors) {
|
|
@@ -4358,7 +4660,7 @@ function weight(p, c, radius) {
|
|
|
4358
4660
|
const u2 = ((p.x - c.x) ** 2 + (p.y - c.y) ** 2) / (radius * radius);
|
|
4359
4661
|
return u2 >= 1 ? 0 : (1 - u2) ** 2;
|
|
4360
4662
|
}
|
|
4361
|
-
function
|
|
4663
|
+
function refine3(set, c, radius, detail) {
|
|
4362
4664
|
if (!Number.isFinite(detail) || detail <= 0) return;
|
|
4363
4665
|
let added = 0;
|
|
4364
4666
|
for (let sub3 = 0; sub3 < set.anchors.length; sub3++) {
|
|
@@ -5579,7 +5881,8 @@ function constrainPathsEdit(items, links = []) {
|
|
|
5579
5881
|
const sliding = new Set(kept.flatMap((c) => c.kind === "onPath" ? [c.anchor] : []));
|
|
5580
5882
|
const still = (i) => {
|
|
5581
5883
|
const { item } = itemOf(i, nowStart);
|
|
5582
|
-
|
|
5884
|
+
const it = items[item];
|
|
5885
|
+
return items.length > 1 && it.before === it.after && !it.yields && !sliding.has(i);
|
|
5583
5886
|
};
|
|
5584
5887
|
const held = nowAll.flatMap((p, i) => {
|
|
5585
5888
|
const r = reference[i];
|
|
@@ -6001,6 +6304,6 @@ function typedArrayReplacer(_key, value) {
|
|
|
6001
6304
|
return tagTypedArray(value) ?? value;
|
|
6002
6305
|
}
|
|
6003
6306
|
|
|
6004
|
-
export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, blendPaths, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, 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, equalizeSegmentHandles, everyNthAnchor, extendToMeet, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, intersectSegments, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, pxExtent, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField };
|
|
6307
|
+
export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, blendPaths, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, 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, equalizeSegmentHandles, everyNthAnchor, extendToMeet, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, intersectSegments, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, mergeRegion, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, pathToD, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, pxExtent, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField };
|
|
6005
6308
|
//# sourceMappingURL=index.js.map
|
|
6006
6309
|
//# sourceMappingURL=index.js.map
|