@pixerate/editor 0.33.0 → 0.35.0
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/THIRD_PARTY_NOTICES.md +22 -0
- package/dist/{bezier-DJPYiVbA.d.ts → bezier-BvqVmWMg.d.ts} +1 -1
- package/dist/{bezier-6KPx3w7Z.d.cts → bezier-D8bsO-L0.d.cts} +1 -1
- package/dist/canvas/index.cjs +179 -622
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +60 -3
- package/dist/canvas/index.d.ts +60 -3
- package/dist/canvas/index.js +37 -480
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-M4XE4UMT.cjs → chunk-BGNPT5PE.cjs} +464 -5
- package/dist/chunk-BGNPT5PE.cjs.map +1 -0
- package/dist/{chunk-GQTXV2EQ.js → chunk-EGPIVUEF.js} +470 -11
- package/dist/chunk-EGPIVUEF.js.map +1 -0
- package/dist/vector/index.cjs +2776 -185
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +638 -10
- package/dist/vector/index.d.ts +638 -10
- package/dist/vector/index.js +2644 -53
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GQTXV2EQ.js.map +0 -1
- package/dist/chunk-M4XE4UMT.cjs.map +0 -1
|
@@ -605,6 +605,10 @@ function fitSingleFrom(pts, u, t0, t1) {
|
|
|
605
605
|
}
|
|
606
606
|
return [best, bestErr, bestSplit];
|
|
607
607
|
}
|
|
608
|
+
function fitCubicWithTangents(points, params, t0, t1) {
|
|
609
|
+
const [curve, error] = fitSingleFrom(points.slice(), params.slice(), [t0[0], t0[1]], [t1[0], t1[1]]);
|
|
610
|
+
return { curve, error };
|
|
611
|
+
}
|
|
608
612
|
function fitRec(pts, t0, t1, tol, out, depth) {
|
|
609
613
|
const n = pts.length;
|
|
610
614
|
if (n === 2) {
|
|
@@ -2651,6 +2655,24 @@ function intersectSubdivided(P, p0, p1, Q, q0, q1, fullP, fullQ, ctx, out, depth
|
|
|
2651
2655
|
intersectSubdivided(P, p0, p1, qb, qm, q1, fullP, fullQ, ctx, out, depth + 1);
|
|
2652
2656
|
}
|
|
2653
2657
|
}
|
|
2658
|
+
function segmentIntersections(a, b, options = {}) {
|
|
2659
|
+
let size = 1;
|
|
2660
|
+
for (const [x, y] of [...a, ...b]) size = Math.max(size, Math.abs(x), Math.abs(y));
|
|
2661
|
+
const eps = options.epsilon ?? size * 1e-9;
|
|
2662
|
+
const found = [];
|
|
2663
|
+
const ctx = { eps, leaves: 0, budget: options.budget ?? 4096 };
|
|
2664
|
+
try {
|
|
2665
|
+
intersectSubdivided(a.slice(), 0, 1, b.slice(), 0, 1, a, b, ctx, found, 0);
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
if (!(error instanceof PathOpsError)) throw error;
|
|
2668
|
+
}
|
|
2669
|
+
const out = [];
|
|
2670
|
+
for (const ev of found.sort((x, y) => x.tp - y.tp)) {
|
|
2671
|
+
if (out.some((o) => dist2(o.point, ev.point) <= eps * 4)) continue;
|
|
2672
|
+
out.push({ ta: ev.tp, tb: ev.tq, point: ev.point });
|
|
2673
|
+
}
|
|
2674
|
+
return out;
|
|
2675
|
+
}
|
|
2654
2676
|
function nearestOn(piece, p, eps) {
|
|
2655
2677
|
if (p[0] < piece.minX - eps || p[0] > piece.maxX + eps || p[1] < piece.minY - eps || p[1] > piece.maxY + eps) return null;
|
|
2656
2678
|
return segmentNearest(piece.pts, p);
|
|
@@ -3248,6 +3270,447 @@ function nestedRingsToPath(rings, keep = () => true) {
|
|
|
3248
3270
|
return contoursToPath(contours);
|
|
3249
3271
|
}
|
|
3250
3272
|
|
|
3273
|
+
// src/canvas/pathops/stroke.ts
|
|
3274
|
+
var DEFAULT_TOLERANCE = 0.01;
|
|
3275
|
+
var normal = (t) => [-t[1], t[0]];
|
|
3276
|
+
function raise(seg) {
|
|
3277
|
+
if (seg.length !== 3) return [...seg];
|
|
3278
|
+
const [p0, p1, p2] = seg;
|
|
3279
|
+
return [p0, [p0[0] + 2 / 3 * (p1[0] - p0[0]), p0[1] + 2 / 3 * (p1[1] - p0[1])], [p2[0] + 2 / 3 * (p1[0] - p2[0]), p2[1] + 2 / 3 * (p1[1] - p2[1])], p2];
|
|
3280
|
+
}
|
|
3281
|
+
function isDegenerate(seg, tol) {
|
|
3282
|
+
return seg.every((p) => dist2(p, seg[0]) <= tol);
|
|
3283
|
+
}
|
|
3284
|
+
function offsetSegment(seg, d, tol, out, depth = 0) {
|
|
3285
|
+
if (seg.length === 2) {
|
|
3286
|
+
const n = normal(segmentTangent(seg, 0));
|
|
3287
|
+
out.push([add2(seg[0], scale(n, d)), add2(seg[1], scale(n, d))]);
|
|
3288
|
+
return;
|
|
3289
|
+
}
|
|
3290
|
+
const c = raise(seg);
|
|
3291
|
+
const t0 = segmentTangent(c, 0);
|
|
3292
|
+
const t1 = segmentTangent(c, 1);
|
|
3293
|
+
const q0 = add2(c[0], scale(normal(t0), d));
|
|
3294
|
+
const q3 = add2(c[3], scale(normal(t1), d));
|
|
3295
|
+
const k0 = segmentCurvature(c, 0);
|
|
3296
|
+
const k1 = segmentCurvature(c, 1);
|
|
3297
|
+
const f0 = Number.isFinite(k0) ? 1 - d * k0 : 1;
|
|
3298
|
+
const f1 = Number.isFinite(k1) ? 1 - d * k1 : 1;
|
|
3299
|
+
const q1 = add2(q0, scale(sub2(c[1], c[0]), f0));
|
|
3300
|
+
const q2 = add2(q3, scale(sub2(c[2], c[3]), f1));
|
|
3301
|
+
const approx = [q0, q1, q2, q3];
|
|
3302
|
+
if (depth < 10) {
|
|
3303
|
+
let err = 0;
|
|
3304
|
+
for (const t of [0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875]) {
|
|
3305
|
+
const target = add2(segmentPoint(c, t), scale(normal(segmentTangent(c, t)), d));
|
|
3306
|
+
err = Math.max(err, segmentNearest(approx, target).distance);
|
|
3307
|
+
if (err > tol) break;
|
|
3308
|
+
}
|
|
3309
|
+
if (err <= tol) {
|
|
3310
|
+
const m = segmentPoint(approx, 0.5);
|
|
3311
|
+
const back = segmentNearest(c, m).distance;
|
|
3312
|
+
err = Math.max(err, Math.abs(back - Math.abs(d)));
|
|
3313
|
+
}
|
|
3314
|
+
if (err > tol) {
|
|
3315
|
+
const [a, b] = splitSegment(c, 0.5);
|
|
3316
|
+
offsetSegment(a, d, tol, out, depth + 1);
|
|
3317
|
+
offsetSegment(b, d, tol, out, depth + 1);
|
|
3318
|
+
return;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
out.push(approx);
|
|
3322
|
+
}
|
|
3323
|
+
function pushArc(out, center, radius, start, sweep, from, to) {
|
|
3324
|
+
const n = Math.max(1, Math.ceil(Math.abs(sweep) / (Math.PI / 2) - 1e-9));
|
|
3325
|
+
const step = sweep / n;
|
|
3326
|
+
const k = 4 / 3 * Math.tan(step / 4);
|
|
3327
|
+
let prev = from;
|
|
3328
|
+
for (let i = 0; i < n; i++) {
|
|
3329
|
+
const a0 = start + step * i;
|
|
3330
|
+
const a1 = a0 + step;
|
|
3331
|
+
const c0 = Math.cos(a0);
|
|
3332
|
+
const s0 = Math.sin(a0);
|
|
3333
|
+
const c1 = Math.cos(a1);
|
|
3334
|
+
const s1 = Math.sin(a1);
|
|
3335
|
+
const end = i === n - 1 ? to : [center[0] + radius * c1, center[1] + radius * s1];
|
|
3336
|
+
out.push([
|
|
3337
|
+
prev,
|
|
3338
|
+
[center[0] + radius * (c0 - k * s0), center[1] + radius * (s0 + k * c0)],
|
|
3339
|
+
[center[0] + radius * (c1 + k * s1), center[1] + radius * (s1 - k * c1)],
|
|
3340
|
+
end
|
|
3341
|
+
]);
|
|
3342
|
+
prev = end;
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
function lineTo(out, from, to) {
|
|
3346
|
+
if (!samePoint(from, to)) out.push([from, to]);
|
|
3347
|
+
}
|
|
3348
|
+
function addJoin(out, p, tin, tout, d, style) {
|
|
3349
|
+
const from = add2(p, scale(normal(tin), d));
|
|
3350
|
+
const to = add2(p, scale(normal(tout), d));
|
|
3351
|
+
const turn = cross(tin, tout);
|
|
3352
|
+
const cos = dot2(tin, tout);
|
|
3353
|
+
if (Math.abs(turn) < 1e-9 && cos > 0) {
|
|
3354
|
+
lineTo(out, from, to);
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
const reversal = Math.abs(turn) < 1e-9 && cos < 0;
|
|
3358
|
+
const inner = !reversal && turn > 0 === d > 0;
|
|
3359
|
+
if (inner) {
|
|
3360
|
+
lineTo(out, from, p);
|
|
3361
|
+
lineTo(out, p, to);
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
const theta = reversal ? d > 0 ? -Math.PI : Math.PI : Math.atan2(turn, cos);
|
|
3365
|
+
if (style.join === "round") {
|
|
3366
|
+
const v = sub2(from, p);
|
|
3367
|
+
pushArc(out, p, Math.abs(d), Math.atan2(v[1], v[0]), theta, from, to);
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
if (style.join === "miter" && !reversal) {
|
|
3371
|
+
const phi = Math.PI - Math.abs(theta);
|
|
3372
|
+
const ratio = 1 / Math.max(Math.sin(phi / 2), 1e-12);
|
|
3373
|
+
if (ratio <= style.miterLimit) {
|
|
3374
|
+
const nin = normal(tin);
|
|
3375
|
+
const nout = normal(tout);
|
|
3376
|
+
const s = d / (1 + dot2(nin, nout));
|
|
3377
|
+
const miter = add2(p, scale(add2(nin, nout), s));
|
|
3378
|
+
lineTo(out, from, miter);
|
|
3379
|
+
lineTo(out, miter, to);
|
|
3380
|
+
return;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
lineTo(out, from, to);
|
|
3384
|
+
}
|
|
3385
|
+
function offsetChain(segs, d, closed, style, tol) {
|
|
3386
|
+
const out = [];
|
|
3387
|
+
const pen = () => out.length > 0 ? out[out.length - 1][out[out.length - 1].length - 1] : null;
|
|
3388
|
+
for (let i = 0; i < segs.length; i++) {
|
|
3389
|
+
if (i > 0) addJoin(out, segs[i][0], segmentTangent(segs[i - 1], 1), segmentTangent(segs[i], 0), d, style);
|
|
3390
|
+
const pieces = [];
|
|
3391
|
+
offsetSegment(segs[i], d, tol, pieces);
|
|
3392
|
+
for (const piece of pieces) {
|
|
3393
|
+
const at = pen();
|
|
3394
|
+
if (at && !samePoint(at, piece[0])) lineTo(out, at, piece[0]);
|
|
3395
|
+
out.push(piece);
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
if (closed && segs.length > 0) {
|
|
3399
|
+
const last = segs[segs.length - 1];
|
|
3400
|
+
addJoin(out, segs[0][0], segmentTangent(last, 1), segmentTangent(segs[0], 0), d, style);
|
|
3401
|
+
const at = pen();
|
|
3402
|
+
if (at && out.length > 0 && !samePoint(at, out[0][0])) lineTo(out, at, out[0][0]);
|
|
3403
|
+
}
|
|
3404
|
+
return out;
|
|
3405
|
+
}
|
|
3406
|
+
function reverseChain(chain) {
|
|
3407
|
+
return chain.map((s) => [...s].reverse()).reverse();
|
|
3408
|
+
}
|
|
3409
|
+
function addCap(out, p, t, h, cap) {
|
|
3410
|
+
const n = normal(t);
|
|
3411
|
+
const from = add2(p, scale(n, h));
|
|
3412
|
+
const to = add2(p, scale(n, -h));
|
|
3413
|
+
if (cap === "round") {
|
|
3414
|
+
pushArc(out, p, h, Math.atan2(n[1], n[0]), -Math.PI, from, to);
|
|
3415
|
+
} else if (cap === "square") {
|
|
3416
|
+
const a = add2(from, scale(t, h));
|
|
3417
|
+
const b = add2(to, scale(t, h));
|
|
3418
|
+
lineTo(out, from, a);
|
|
3419
|
+
lineTo(out, a, b);
|
|
3420
|
+
lineTo(out, b, to);
|
|
3421
|
+
} else {
|
|
3422
|
+
lineTo(out, from, to);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
function dotRings(p, t, h, cap) {
|
|
3426
|
+
if (cap === "butt") return [];
|
|
3427
|
+
const ring = [];
|
|
3428
|
+
addCap(ring, p, t, h, cap);
|
|
3429
|
+
addCap(ring, p, [-t[0], -t[1]], h, cap);
|
|
3430
|
+
return [ring];
|
|
3431
|
+
}
|
|
3432
|
+
function strokeContour(contour, h, style, tol) {
|
|
3433
|
+
const tiny = Math.max(1e-12, tol * 1e-6);
|
|
3434
|
+
const all = contour.closed ? closeContour(contour) : contour.segments;
|
|
3435
|
+
const segs = all.filter((s) => !isDegenerate(s, tiny));
|
|
3436
|
+
if (segs.length === 0) {
|
|
3437
|
+
const p = contour.segments[0]?.[0];
|
|
3438
|
+
return p ? dotRings(p, [1, 0], h, style.cap) : [];
|
|
3439
|
+
}
|
|
3440
|
+
if (contour.closed) {
|
|
3441
|
+
const left2 = offsetChain(segs, h, true, style, tol);
|
|
3442
|
+
const right2 = offsetChain(segs, -h, true, style, tol);
|
|
3443
|
+
return [left2, reverseChain(right2)];
|
|
3444
|
+
}
|
|
3445
|
+
const left = offsetChain(segs, h, false, style, tol);
|
|
3446
|
+
const right = reverseChain(offsetChain(segs, -h, false, style, tol));
|
|
3447
|
+
const ring = [...left];
|
|
3448
|
+
const last = segs[segs.length - 1];
|
|
3449
|
+
addCap(ring, last[last.length - 1], segmentTangent(last, 1), h, style.cap);
|
|
3450
|
+
const joinTo = (p) => {
|
|
3451
|
+
const at = ring[ring.length - 1][ring[ring.length - 1].length - 1];
|
|
3452
|
+
lineTo(ring, at, p);
|
|
3453
|
+
};
|
|
3454
|
+
if (right.length > 0) joinTo(right[0][0]);
|
|
3455
|
+
ring.push(...right);
|
|
3456
|
+
const first = segs[0];
|
|
3457
|
+
const t0 = segmentTangent(first, 0);
|
|
3458
|
+
addCap(ring, first[0], [-t0[0], -t0[1]], h, style.cap);
|
|
3459
|
+
if (ring.length > 0) joinTo(ring[0][0]);
|
|
3460
|
+
return [ring];
|
|
3461
|
+
}
|
|
3462
|
+
function ringsToPath3(rings) {
|
|
3463
|
+
return contoursToPath(rings.filter((r) => r.length > 0).map((segments) => ({ segments, closed: true })));
|
|
3464
|
+
}
|
|
3465
|
+
var MAX_DASHES = 2e5;
|
|
3466
|
+
var MIN_ENTRY = 1e-6;
|
|
3467
|
+
function dashContours(contours, pattern, offset = 0) {
|
|
3468
|
+
if (pattern.length === 0 || pattern.some((v) => !Number.isFinite(v) || v < 0) || !Number.isFinite(offset)) return null;
|
|
3469
|
+
if (!pattern.some((v) => v > MIN_ENTRY)) return null;
|
|
3470
|
+
const pat = pattern.length % 2 === 1 ? [...pattern, ...pattern] : [...pattern];
|
|
3471
|
+
const period = pat.reduce((s, v) => s + v, 0);
|
|
3472
|
+
const chains = contours.map((c) => {
|
|
3473
|
+
const segs = closeContour(c);
|
|
3474
|
+
const lengths = segs.map((s) => segmentLength(s));
|
|
3475
|
+
return { segs, lengths, total: lengths.reduce((s, v) => s + v, 0), closed: c.closed };
|
|
3476
|
+
});
|
|
3477
|
+
const totalLength = chains.reduce((s, c) => s + c.total, 0);
|
|
3478
|
+
if (totalLength / period * pat.length > MAX_DASHES) return null;
|
|
3479
|
+
let off = (offset % period + period) % period;
|
|
3480
|
+
let ix0 = 0;
|
|
3481
|
+
while (off > pat[ix0]) {
|
|
3482
|
+
off -= pat[ix0];
|
|
3483
|
+
ix0 = (ix0 + 1) % pat.length;
|
|
3484
|
+
}
|
|
3485
|
+
const out = { contours: [], dots: [] };
|
|
3486
|
+
for (const chain of chains) {
|
|
3487
|
+
if (chain.segs.length === 0 || !(chain.total > 0)) continue;
|
|
3488
|
+
let ix = ix0;
|
|
3489
|
+
let rem = pat[ix0] - off;
|
|
3490
|
+
let pos = 0;
|
|
3491
|
+
const dashes = [];
|
|
3492
|
+
let guard = 0;
|
|
3493
|
+
while (pos < chain.total && guard++ < MAX_DASHES * 2) {
|
|
3494
|
+
const step = Math.min(rem, chain.total - pos);
|
|
3495
|
+
const on = ix % 2 === 0;
|
|
3496
|
+
if (on) dashes.push({ from: pos, to: pos + step });
|
|
3497
|
+
pos += step;
|
|
3498
|
+
rem -= step;
|
|
3499
|
+
if (rem <= 1e-12) {
|
|
3500
|
+
ix = (ix + 1) % pat.length;
|
|
3501
|
+
rem = pat[ix];
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
if (chain.closed && dashes.length > 1) {
|
|
3505
|
+
const first = dashes[0];
|
|
3506
|
+
const last = dashes[dashes.length - 1];
|
|
3507
|
+
if (first.from <= 1e-9 && last.to >= chain.total - 1e-9 && first.to > first.from && last.to > last.from) {
|
|
3508
|
+
dashes.pop();
|
|
3509
|
+
const tail = trimSegments(chain.segs, last.from, chain.total, chain.lengths);
|
|
3510
|
+
const head = trimSegments(chain.segs, 0, first.to, chain.lengths);
|
|
3511
|
+
dashes.shift();
|
|
3512
|
+
out.contours.push({ segments: [...tail, ...head], closed: false });
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
for (const dash of dashes) {
|
|
3516
|
+
if (dash.to - dash.from <= 1e-12) {
|
|
3517
|
+
const at = locate(chain.segs, chain.lengths, dash.from);
|
|
3518
|
+
out.dots.push(at);
|
|
3519
|
+
continue;
|
|
3520
|
+
}
|
|
3521
|
+
const segments = trimSegments(chain.segs, dash.from, dash.to, chain.lengths);
|
|
3522
|
+
if (segments.length > 0) out.contours.push({ segments, closed: false });
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
return out;
|
|
3526
|
+
}
|
|
3527
|
+
function locate(segs, lengths, at) {
|
|
3528
|
+
let acc = 0;
|
|
3529
|
+
for (let i = 0; i < segs.length; i++) {
|
|
3530
|
+
if (at <= acc + lengths[i] || i === segs.length - 1) {
|
|
3531
|
+
const piece = trimSegments([segs[i]], 0, Math.max(0, at - acc), [lengths[i]]);
|
|
3532
|
+
const t = piece.length > 0 ? 1 : 0;
|
|
3533
|
+
const point = piece.length > 0 ? piece[piece.length - 1][piece[piece.length - 1].length - 1] : segs[i][0];
|
|
3534
|
+
const tangent = segmentTangent(piece.length > 0 ? piece[piece.length - 1] : segs[i], t);
|
|
3535
|
+
return { point, tangent };
|
|
3536
|
+
}
|
|
3537
|
+
acc += lengths[i];
|
|
3538
|
+
}
|
|
3539
|
+
return { point: segs[0][0], tangent: segmentTangent(segs[0], 0) };
|
|
3540
|
+
}
|
|
3541
|
+
function deepPoint(rings) {
|
|
3542
|
+
let minX = Infinity;
|
|
3543
|
+
let minY = Infinity;
|
|
3544
|
+
let maxX = -Infinity;
|
|
3545
|
+
let maxY = -Infinity;
|
|
3546
|
+
for (const p of rings[0].flat()) {
|
|
3547
|
+
minX = Math.min(minX, p[0]);
|
|
3548
|
+
maxX = Math.max(maxX, p[0]);
|
|
3549
|
+
minY = Math.min(minY, p[1]);
|
|
3550
|
+
maxY = Math.max(maxY, p[1]);
|
|
3551
|
+
}
|
|
3552
|
+
const w = maxX - minX;
|
|
3553
|
+
const h = maxY - minY;
|
|
3554
|
+
if (!(w > 0 && h > 0)) return null;
|
|
3555
|
+
const tolerance = Math.max(1e-6, 2e-3 * Math.min(w, h));
|
|
3556
|
+
const polys = rings.map((r) => flattenChain(r, tolerance));
|
|
3557
|
+
let best = null;
|
|
3558
|
+
for (const f of [0.5, 0.3, 0.7, 0.15, 0.85]) {
|
|
3559
|
+
const y = minY + h * f;
|
|
3560
|
+
const xs = [];
|
|
3561
|
+
for (const poly of polys) {
|
|
3562
|
+
for (let i = 0; i < poly.length; i++) {
|
|
3563
|
+
const a = poly[i];
|
|
3564
|
+
const b = poly[(i + 1) % poly.length];
|
|
3565
|
+
if (a[1] <= y !== b[1] <= y) xs.push(a[0] + (y - a[1]) / (b[1] - a[1]) * (b[0] - a[0]));
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
xs.sort((p, q) => p - q);
|
|
3569
|
+
for (let i = 0; i + 1 < xs.length; i += 2) {
|
|
3570
|
+
const span = xs[i + 1] - xs[i];
|
|
3571
|
+
if (!best || span > best.span) best = { span, p: [(xs[i] + xs[i + 1]) / 2, y] };
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
return best?.p ?? null;
|
|
3575
|
+
}
|
|
3576
|
+
function dropSpurious(rings, spurious) {
|
|
3577
|
+
const children = rings.map(() => []);
|
|
3578
|
+
rings.forEach((r, i) => {
|
|
3579
|
+
if (r.parent >= 0) children[r.parent].push(i);
|
|
3580
|
+
});
|
|
3581
|
+
const marked = rings.map((r, i) => spurious([r.segments, ...children[i].map((c) => rings[c].segments)], r));
|
|
3582
|
+
const hasMarkedAncestor = (i) => {
|
|
3583
|
+
for (let k = i; k >= 0; k = rings[k].parent) if (marked[k]) return true;
|
|
3584
|
+
return false;
|
|
3585
|
+
};
|
|
3586
|
+
return nestedRingsToPath(rings, (i) => !hasMarkedAncestor(i));
|
|
3587
|
+
}
|
|
3588
|
+
function mergeSmoothRuns(path, tolerance) {
|
|
3589
|
+
const contours = pathToContours(path).map((contour) => {
|
|
3590
|
+
const segs = closeContour(contour, true).map((s) => s.length === 3 ? raise(s) : [...s]);
|
|
3591
|
+
const n = segs.length;
|
|
3592
|
+
if (n < 2) return { segments: segs, closed: true };
|
|
3593
|
+
const smooth = (a, b) => {
|
|
3594
|
+
if (a.length !== 4 || b.length !== 4) return false;
|
|
3595
|
+
const ta = segmentTangent(a, 1);
|
|
3596
|
+
const tb = segmentTangent(b, 0);
|
|
3597
|
+
return dot2(ta, tb) > 0.9998 && Math.abs(cross(ta, tb)) < 0.02;
|
|
3598
|
+
};
|
|
3599
|
+
let start = 0;
|
|
3600
|
+
for (let k = 0; k < n; k++) {
|
|
3601
|
+
if (!smooth(segs[(k + n - 1) % n], segs[k])) {
|
|
3602
|
+
start = k;
|
|
3603
|
+
break;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
const ordered = [...segs.slice(start), ...segs.slice(0, start)];
|
|
3607
|
+
const out = [];
|
|
3608
|
+
let i = 0;
|
|
3609
|
+
while (i < ordered.length) {
|
|
3610
|
+
let current = ordered[i];
|
|
3611
|
+
let j = i + 1;
|
|
3612
|
+
while (j < ordered.length && smooth(ordered[j - 1], ordered[j])) {
|
|
3613
|
+
const run = ordered.slice(i, j + 1);
|
|
3614
|
+
const pts = [];
|
|
3615
|
+
run.forEach((s, k) => {
|
|
3616
|
+
for (let q = k === 0 ? 0 : 1; q <= 12; q++) pts.push(segmentPoint(s, q / 12));
|
|
3617
|
+
});
|
|
3618
|
+
const fit = fitCubicRun(pts, tolerance, segmentTangent(run[0], 0), segmentTangent(run[run.length - 1], 1));
|
|
3619
|
+
if (fit.length !== 1) break;
|
|
3620
|
+
const c = fit[0];
|
|
3621
|
+
current = [run[0][0], c.p1, c.p2, run[run.length - 1][3]];
|
|
3622
|
+
j++;
|
|
3623
|
+
}
|
|
3624
|
+
out.push(current);
|
|
3625
|
+
i = j;
|
|
3626
|
+
}
|
|
3627
|
+
return { segments: out, closed: true };
|
|
3628
|
+
});
|
|
3629
|
+
return contoursToPath(contours);
|
|
3630
|
+
}
|
|
3631
|
+
function joinStyle(join, miterLimit) {
|
|
3632
|
+
return {
|
|
3633
|
+
join: join ?? "miter",
|
|
3634
|
+
miterLimit: miterLimit !== void 0 && Number.isFinite(miterLimit) ? Math.max(1, miterLimit) : 4
|
|
3635
|
+
};
|
|
3636
|
+
}
|
|
3637
|
+
function strokeOutlineRings(input, options) {
|
|
3638
|
+
const h = options.width / 2;
|
|
3639
|
+
if (!(h > 0) || !Number.isFinite(h)) return [];
|
|
3640
|
+
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
3641
|
+
const style = { ...joinStyle(options.join, options.miterLimit), cap: options.cap ?? "butt" };
|
|
3642
|
+
let contours = pathToContours(input);
|
|
3643
|
+
const rings = [];
|
|
3644
|
+
if (options.dash && options.dash.length > 0) {
|
|
3645
|
+
const dashed = dashContours(contours, options.dash, options.dashOffset ?? 0);
|
|
3646
|
+
if (dashed) {
|
|
3647
|
+
contours = dashed.contours;
|
|
3648
|
+
for (const dot3 of dashed.dots) rings.push(...dotRings(dot3.point, dot3.tangent, h, style.cap));
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
for (const contour of contours) rings.push(...strokeContour(contour, h, style, tol));
|
|
3652
|
+
return ringsToPath3(rings);
|
|
3653
|
+
}
|
|
3654
|
+
function outlineStroke(input, options) {
|
|
3655
|
+
const h = options.width / 2;
|
|
3656
|
+
if (!(h > 0) || !Number.isFinite(h)) return [];
|
|
3657
|
+
let source;
|
|
3658
|
+
try {
|
|
3659
|
+
source = contoursToPath(pathToContours(input));
|
|
3660
|
+
} catch {
|
|
3661
|
+
return [];
|
|
3662
|
+
}
|
|
3663
|
+
if (source.some((c) => c.type !== "Z" && Object.values(c).some((v) => typeof v === "number" && !Number.isFinite(v)))) return [];
|
|
3664
|
+
const raw = strokeOutlineRings(source, options);
|
|
3665
|
+
if (raw.length === 0) return [];
|
|
3666
|
+
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
3667
|
+
const sourceContours = pathToContours(source);
|
|
3668
|
+
const operand = { path: raw, fillRule: "nonzero" };
|
|
3669
|
+
try {
|
|
3670
|
+
const rings = pathBooleanRings("union", [operand], options);
|
|
3671
|
+
const cleaned = dropSpurious(rings, (face, ring) => {
|
|
3672
|
+
if (ring.area >= 0) return false;
|
|
3673
|
+
const p = deepPoint(face);
|
|
3674
|
+
return !!p && distanceToBezierPath(sourceContours, p) < h * (1 - 1e-4) - 1e-6;
|
|
3675
|
+
});
|
|
3676
|
+
return mergeSmoothRuns(cleaned, tol);
|
|
3677
|
+
} catch {
|
|
3678
|
+
return pathBoolean("union", [operand], options).path;
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
function offsetPath(input, distance, options = {}) {
|
|
3682
|
+
if (!Number.isFinite(distance)) return [];
|
|
3683
|
+
const contours = pathToContours(input);
|
|
3684
|
+
if (contours.some((c) => c.segments.some((s) => s.some((p) => !Number.isFinite(p[0]) || !Number.isFinite(p[1]))))) return [];
|
|
3685
|
+
const closed = contours.filter((c) => c.closed && c.segments.length > 0);
|
|
3686
|
+
const open = contours.filter((c) => !c.closed && c.segments.length > 0);
|
|
3687
|
+
const fillRule = options.fillRule ?? "nonzero";
|
|
3688
|
+
const fill = { path: contoursToPath(closed), fillRule };
|
|
3689
|
+
const d = Math.abs(distance);
|
|
3690
|
+
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
3691
|
+
if (d === 0) return pathBoolean("union", [fill], options).path;
|
|
3692
|
+
const strokeOptions = { width: 2 * d, join: options.join ?? "miter", miterLimit: options.miterLimit, cap: "butt", tolerance: tol };
|
|
3693
|
+
const ring = { path: strokeOutlineRings(contoursToPath(closed), strokeOptions), fillRule: "nonzero" };
|
|
3694
|
+
const openRing = {
|
|
3695
|
+
path: distance > 0 ? strokeOutlineRings(contoursToPath(open), strokeOptions) : [],
|
|
3696
|
+
fillRule: "nonzero"
|
|
3697
|
+
};
|
|
3698
|
+
const grow = distance > 0;
|
|
3699
|
+
const operands = [fill, ring, openRing];
|
|
3700
|
+
try {
|
|
3701
|
+
const rings = pathBooleanRings(grow ? (m) => m[0] || m[1] || m[2] : (m) => m[0] && !m[1], operands, options);
|
|
3702
|
+
const sourceContours = contours;
|
|
3703
|
+
const cleaned = dropSpurious(rings, (face, r) => {
|
|
3704
|
+
if (grow ? r.area >= 0 : r.area <= 0) return false;
|
|
3705
|
+
const p = deepPoint(face);
|
|
3706
|
+
return !!p && distanceToBezierPath(sourceContours, p) < d * (1 - 1e-4) - 1e-6;
|
|
3707
|
+
});
|
|
3708
|
+
return mergeSmoothRuns(cleaned, tol);
|
|
3709
|
+
} catch {
|
|
3710
|
+
return grow ? pathBoolean("union", operands, options).path : pathBoolean("difference", [fill, ring], options).path;
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3251
3714
|
export {
|
|
3252
3715
|
ringSignedArea,
|
|
3253
3716
|
polygonArea,
|
|
@@ -3262,6 +3725,7 @@ export {
|
|
|
3262
3725
|
xorPolygons,
|
|
3263
3726
|
dividePolygons,
|
|
3264
3727
|
cubicPointAt,
|
|
3728
|
+
fitCubicWithTangents,
|
|
3265
3729
|
fitCubicRun,
|
|
3266
3730
|
fitCubics,
|
|
3267
3731
|
isStraightCubic,
|
|
@@ -3284,13 +3748,6 @@ export {
|
|
|
3284
3748
|
formatNumber2 as formatNumber,
|
|
3285
3749
|
simplifyRing,
|
|
3286
3750
|
polygonToSvgPath,
|
|
3287
|
-
sub2 as sub,
|
|
3288
|
-
add2 as add,
|
|
3289
|
-
scale,
|
|
3290
|
-
dot2 as dot,
|
|
3291
|
-
cross,
|
|
3292
|
-
dist2 as dist,
|
|
3293
|
-
samePoint,
|
|
3294
3751
|
segmentPoint,
|
|
3295
3752
|
segmentDerivative,
|
|
3296
3753
|
segmentTangent,
|
|
@@ -3319,8 +3776,8 @@ export {
|
|
|
3319
3776
|
windingNumber,
|
|
3320
3777
|
pointInBezierPath,
|
|
3321
3778
|
distanceToBezierPath,
|
|
3322
|
-
flattenChain,
|
|
3323
3779
|
PathOpsError,
|
|
3780
|
+
segmentIntersections,
|
|
3324
3781
|
pathBoolean,
|
|
3325
3782
|
unitePaths,
|
|
3326
3783
|
intersectPaths,
|
|
@@ -3329,7 +3786,9 @@ export {
|
|
|
3329
3786
|
dividePaths,
|
|
3330
3787
|
normalizeBezierPath,
|
|
3331
3788
|
bezierPathArea,
|
|
3332
|
-
|
|
3333
|
-
|
|
3789
|
+
dashContours,
|
|
3790
|
+
strokeOutlineRings,
|
|
3791
|
+
outlineStroke,
|
|
3792
|
+
offsetPath
|
|
3334
3793
|
};
|
|
3335
|
-
//# sourceMappingURL=chunk-
|
|
3794
|
+
//# sourceMappingURL=chunk-EGPIVUEF.js.map
|