@pixerate/editor 0.34.0 → 0.36.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 +14 -0
- package/dist/canvas/index.cjs +178 -623
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +10 -1
- package/dist/canvas/index.d.ts +10 -1
- package/dist/canvas/index.js +35 -480
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-UG5DVXJK.cjs → chunk-BGNPT5PE.cjs} +446 -6
- package/dist/chunk-BGNPT5PE.cjs.map +1 -0
- package/dist/{chunk-RK6HUKDI.js → chunk-EGPIVUEF.js} +451 -11
- package/dist/chunk-EGPIVUEF.js.map +1 -0
- package/dist/vector/index.cjs +2943 -401
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +696 -24
- package/dist/vector/index.d.ts +696 -24
- package/dist/vector/index.js +2880 -338
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-RK6HUKDI.js.map +0 -1
- package/dist/chunk-UG5DVXJK.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) {
|
|
@@ -3266,6 +3270,447 @@ function nestedRingsToPath(rings, keep = () => true) {
|
|
|
3266
3270
|
return contoursToPath(contours);
|
|
3267
3271
|
}
|
|
3268
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
|
+
|
|
3269
3714
|
export {
|
|
3270
3715
|
ringSignedArea,
|
|
3271
3716
|
polygonArea,
|
|
@@ -3280,6 +3725,7 @@ export {
|
|
|
3280
3725
|
xorPolygons,
|
|
3281
3726
|
dividePolygons,
|
|
3282
3727
|
cubicPointAt,
|
|
3728
|
+
fitCubicWithTangents,
|
|
3283
3729
|
fitCubicRun,
|
|
3284
3730
|
fitCubics,
|
|
3285
3731
|
isStraightCubic,
|
|
@@ -3302,13 +3748,6 @@ export {
|
|
|
3302
3748
|
formatNumber2 as formatNumber,
|
|
3303
3749
|
simplifyRing,
|
|
3304
3750
|
polygonToSvgPath,
|
|
3305
|
-
sub2 as sub,
|
|
3306
|
-
add2 as add,
|
|
3307
|
-
scale,
|
|
3308
|
-
dot2 as dot,
|
|
3309
|
-
cross,
|
|
3310
|
-
dist2 as dist,
|
|
3311
|
-
samePoint,
|
|
3312
3751
|
segmentPoint,
|
|
3313
3752
|
segmentDerivative,
|
|
3314
3753
|
segmentTangent,
|
|
@@ -3337,7 +3776,6 @@ export {
|
|
|
3337
3776
|
windingNumber,
|
|
3338
3777
|
pointInBezierPath,
|
|
3339
3778
|
distanceToBezierPath,
|
|
3340
|
-
flattenChain,
|
|
3341
3779
|
PathOpsError,
|
|
3342
3780
|
segmentIntersections,
|
|
3343
3781
|
pathBoolean,
|
|
@@ -3348,7 +3786,9 @@ export {
|
|
|
3348
3786
|
dividePaths,
|
|
3349
3787
|
normalizeBezierPath,
|
|
3350
3788
|
bezierPathArea,
|
|
3351
|
-
|
|
3352
|
-
|
|
3789
|
+
dashContours,
|
|
3790
|
+
strokeOutlineRings,
|
|
3791
|
+
outlineStroke,
|
|
3792
|
+
offsetPath
|
|
3353
3793
|
};
|
|
3354
|
-
//# sourceMappingURL=chunk-
|
|
3794
|
+
//# sourceMappingURL=chunk-EGPIVUEF.js.map
|