@weasel-js/geom 1.10.1 → 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/README.md +9 -1
- package/dist/3d/index.d.ts +29 -2
- package/dist/3d/index.js +49 -1
- package/dist/3d/index.js.map +1 -1
- package/dist/booleans/index.d.ts +18 -11
- package/dist/booleans/index.js +432 -352
- package/dist/booleans/index.js.map +1 -1
- package/dist/chunk-4Y67BZL5.js +573 -0
- package/dist/chunk-4Y67BZL5.js.map +1 -0
- package/dist/chunk-6FGQML7D.js +152 -0
- package/dist/chunk-6FGQML7D.js.map +1 -0
- package/dist/{chunk-7WFFCHRL.js → chunk-7F66PQCJ.js} +6 -37
- package/dist/chunk-7F66PQCJ.js.map +1 -0
- package/dist/chunk-B53BERKG.js +386 -0
- package/dist/chunk-B53BERKG.js.map +1 -0
- package/dist/chunk-CE7IY7TB.js +104 -0
- package/dist/chunk-CE7IY7TB.js.map +1 -0
- package/dist/chunk-EAKE3N7W.js +804 -0
- package/dist/chunk-EAKE3N7W.js.map +1 -0
- package/dist/chunk-LRVPK7HI.js +491 -0
- package/dist/chunk-LRVPK7HI.js.map +1 -0
- package/dist/chunk-Q66NA2FU.js +174 -0
- package/dist/chunk-Q66NA2FU.js.map +1 -0
- package/dist/chunk-UI3FUWXM.js +533 -0
- package/dist/chunk-UI3FUWXM.js.map +1 -0
- package/dist/curvature-PkoLduGc.d.ts +454 -0
- package/dist/curves/index.d.ts +14 -5
- package/dist/curves/index.js +33 -111
- package/dist/curves/index.js.map +1 -1
- package/dist/index.d.ts +1511 -283
- package/dist/index.js +5755 -2674
- package/dist/index.js.map +1 -1
- package/dist/nd/index.d.ts +92 -27
- package/dist/nd/index.js +297 -0
- package/dist/nd/index.js.map +1 -1
- package/dist/path-BW8d_2RY.d.ts +157 -0
- package/dist/portCurve-C5HDWuuV.d.ts +30 -0
- package/dist/tessellate/index.d.ts +15 -4
- package/dist/tessellate/index.js +21 -277
- package/dist/tessellate/index.js.map +1 -1
- package/dist/warp/index.d.ts +254 -0
- package/dist/warp/index.js +1448 -0
- package/dist/warp/index.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-7WFFCHRL.js.map +0 -1
- package/dist/chunk-IDXY2NCA.js +0 -177
- package/dist/chunk-IDXY2NCA.js.map +0 -1
- package/dist/chunk-NJ3IGAKR.js +0 -16
- package/dist/chunk-NJ3IGAKR.js.map +0 -1
- package/dist/chunk-OXH3NOXC.js +0 -62
- package/dist/chunk-OXH3NOXC.js.map +0 -1
- package/dist/chunk-URQMDR6Q.js +0 -80
- package/dist/chunk-URQMDR6Q.js.map +0 -1
- package/dist/cubicMath-BW-HJrCE.d.ts +0 -16
- package/dist/path-ljHxobyu.d.ts +0 -44
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
import { sign, len2, dot } from './chunk-755Y4YZS.js';
|
|
2
|
+
import { PathBuilder, cubicPointAt, forEachSegment, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, hasCorners, withoutCorners, cornerAt, cubicEvalAt, splitCubicAt } from './chunk-B53BERKG.js';
|
|
3
|
+
|
|
4
|
+
// src/flatten.ts
|
|
5
|
+
var DEFAULT_FLATTEN_TOLERANCE = 0.5;
|
|
6
|
+
var MIN_FLATTEN_TOLERANCE = 1e-6;
|
|
7
|
+
var MAX_FLATTEN_DEPTH = 16;
|
|
8
|
+
function usableTolerance(tolerance) {
|
|
9
|
+
return tolerance > 0 ? tolerance : MIN_FLATTEN_TOLERANCE;
|
|
10
|
+
}
|
|
11
|
+
function finite6(a, b, c, d, e, f) {
|
|
12
|
+
return Number.isFinite(a) && Number.isFinite(b) && Number.isFinite(c) && Number.isFinite(d) && Number.isFinite(e) && Number.isFinite(f);
|
|
13
|
+
}
|
|
14
|
+
function finite8(a, b, c, d, e, f, g, h) {
|
|
15
|
+
return finite6(a, b, c, d, e, f) && Number.isFinite(g) && Number.isFinite(h);
|
|
16
|
+
}
|
|
17
|
+
function distPointToSegment(px, py, ax, ay, bx, by) {
|
|
18
|
+
const dx = bx - ax;
|
|
19
|
+
const dy = by - ay;
|
|
20
|
+
const len22 = dx * dx + dy * dy;
|
|
21
|
+
const along = len22 === 0 ? 0 : ((px - ax) * dx + (py - ay) * dy) / len22;
|
|
22
|
+
if (along <= 0) return Math.hypot(px - ax, py - ay);
|
|
23
|
+
if (along >= 1) return Math.hypot(px - bx, py - by);
|
|
24
|
+
return Math.abs((px - ax) * dy - (py - ay) * dx) / Math.sqrt(len22);
|
|
25
|
+
}
|
|
26
|
+
function turnsWithin(x0, y0, x1, y1, x2, y2, x3, y3, maxTurn) {
|
|
27
|
+
let turn = legTurn(x1 - x0, y1 - y0, x2 - x1, y2 - y1);
|
|
28
|
+
if (turn > maxTurn) return false;
|
|
29
|
+
turn += legTurn(x2 - x1, y2 - y1, x3 - x2, y3 - y2);
|
|
30
|
+
if (x2 === x1 && y2 === y1) turn += legTurn(x1 - x0, y1 - y0, x3 - x2, y3 - y2);
|
|
31
|
+
return turn <= maxTurn;
|
|
32
|
+
}
|
|
33
|
+
function legTurn(ax, ay, bx, by) {
|
|
34
|
+
const lens = Math.sqrt((ax * ax + ay * ay) * (bx * bx + by * by));
|
|
35
|
+
if (lens === 0) return 0;
|
|
36
|
+
return Math.acos(Math.max(-1, Math.min(1, (ax * bx + ay * by) / lens)));
|
|
37
|
+
}
|
|
38
|
+
function flattenCubic(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
|
|
39
|
+
if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
|
|
40
|
+
out.push(x3, y3);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), out, 0);
|
|
44
|
+
}
|
|
45
|
+
function flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, depth) {
|
|
46
|
+
const d1 = distPointToSegment(x1, y1, x0, y0, x3, y3);
|
|
47
|
+
const d2 = distPointToSegment(x2, y2, x0, y0, x3, y3);
|
|
48
|
+
if (Math.max(d1, d2) <= tolerance || depth >= MAX_FLATTEN_DEPTH) {
|
|
49
|
+
out.push(x3, y3);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
|
|
53
|
+
const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
|
|
54
|
+
const x23 = (x2 + x3) * 0.5, y23 = (y2 + y3) * 0.5;
|
|
55
|
+
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
56
|
+
const x123 = (x12 + x23) * 0.5, y123 = (y12 + y23) * 0.5;
|
|
57
|
+
const x0123 = (x012 + x123) * 0.5, y0123 = (y012 + y123) * 0.5;
|
|
58
|
+
flattenCubicRec(x0, y0, x01, y01, x012, y012, x0123, y0123, tolerance, out, depth + 1);
|
|
59
|
+
flattenCubicRec(x0123, y0123, x123, y123, x23, y23, x3, y3, tolerance, out, depth + 1);
|
|
60
|
+
}
|
|
61
|
+
function flattenQuadratic(x0, y0, x1, y1, x2, y2, tolerance, out) {
|
|
62
|
+
if (!finite6(x0, y0, x1, y1, x2, y2)) {
|
|
63
|
+
out.push(x2, y2);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
flattenQuadraticRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), out, 0);
|
|
67
|
+
}
|
|
68
|
+
function flattenQuadraticRec(x0, y0, x1, y1, x2, y2, tolerance, out, depth) {
|
|
69
|
+
const d = distPointToSegment(x1, y1, x0, y0, x2, y2);
|
|
70
|
+
if (d <= tolerance || depth >= MAX_FLATTEN_DEPTH) {
|
|
71
|
+
out.push(x2, y2);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
|
|
75
|
+
const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
|
|
76
|
+
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
77
|
+
flattenQuadraticRec(x0, y0, x01, y01, x012, y012, tolerance, out, depth + 1);
|
|
78
|
+
flattenQuadraticRec(x012, y012, x12, y12, x2, y2, tolerance, out, depth + 1);
|
|
79
|
+
}
|
|
80
|
+
function flattenCubicWithArcLen(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcOut, maxTurn = Infinity) {
|
|
81
|
+
if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
|
|
82
|
+
out.push(x3, y3);
|
|
83
|
+
arcOut.push(0);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
return flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), maxTurn, out, arcOut, 0, 0);
|
|
87
|
+
}
|
|
88
|
+
function flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, maxTurn, out, arcOut, accum, depth) {
|
|
89
|
+
const d1 = distPointToSegment(x1, y1, x0, y0, x3, y3);
|
|
90
|
+
const d2 = distPointToSegment(x2, y2, x0, y0, x3, y3);
|
|
91
|
+
const flat = Math.max(d1, d2) <= tolerance && (maxTurn === Infinity || turnsWithin(x0, y0, x1, y1, x2, y2, x3, y3, maxTurn));
|
|
92
|
+
if (flat || depth >= MAX_FLATTEN_DEPTH) {
|
|
93
|
+
const lastX = out.length >= 2 ? out[out.length - 2] : x0;
|
|
94
|
+
const lastY = out.length >= 2 ? out[out.length - 1] : y0;
|
|
95
|
+
const seg = Math.hypot(x3 - lastX, y3 - lastY);
|
|
96
|
+
accum += seg;
|
|
97
|
+
out.push(x3, y3);
|
|
98
|
+
arcOut.push(accum);
|
|
99
|
+
return accum;
|
|
100
|
+
}
|
|
101
|
+
const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
|
|
102
|
+
const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
|
|
103
|
+
const x23 = (x2 + x3) * 0.5, y23 = (y2 + y3) * 0.5;
|
|
104
|
+
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
105
|
+
const x123 = (x12 + x23) * 0.5, y123 = (y12 + y23) * 0.5;
|
|
106
|
+
const x0123 = (x012 + x123) * 0.5, y0123 = (y012 + y123) * 0.5;
|
|
107
|
+
accum = flattenCubicArcRec(x0, y0, x01, y01, x012, y012, x0123, y0123, tolerance, maxTurn, out, arcOut, accum, depth + 1);
|
|
108
|
+
accum = flattenCubicArcRec(x0123, y0123, x123, y123, x23, y23, x3, y3, tolerance, maxTurn, out, arcOut, accum, depth + 1);
|
|
109
|
+
return accum;
|
|
110
|
+
}
|
|
111
|
+
function flattenQuadraticWithArcLen(x0, y0, x1, y1, x2, y2, tolerance, out, arcOut, maxTurn = Infinity) {
|
|
112
|
+
if (!finite6(x0, y0, x1, y1, x2, y2)) {
|
|
113
|
+
out.push(x2, y2);
|
|
114
|
+
arcOut.push(0);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
return flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), maxTurn, out, arcOut, 0, 0);
|
|
118
|
+
}
|
|
119
|
+
function flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, tolerance, maxTurn, out, arcOut, accum, depth) {
|
|
120
|
+
const d = distPointToSegment(x1, y1, x0, y0, x2, y2);
|
|
121
|
+
const flat = d <= tolerance && (maxTurn === Infinity || turnsWithin(x0, y0, x1, y1, x2, y2, x2, y2, maxTurn));
|
|
122
|
+
if (flat || depth >= MAX_FLATTEN_DEPTH) {
|
|
123
|
+
const lastX = out.length >= 2 ? out[out.length - 2] : x0;
|
|
124
|
+
const lastY = out.length >= 2 ? out[out.length - 1] : y0;
|
|
125
|
+
const seg = Math.hypot(x2 - lastX, y2 - lastY);
|
|
126
|
+
accum += seg;
|
|
127
|
+
out.push(x2, y2);
|
|
128
|
+
arcOut.push(accum);
|
|
129
|
+
return accum;
|
|
130
|
+
}
|
|
131
|
+
const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
|
|
132
|
+
const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
|
|
133
|
+
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
134
|
+
accum = flattenQuadraticArcRec(x0, y0, x01, y01, x012, y012, tolerance, maxTurn, out, arcOut, accum, depth + 1);
|
|
135
|
+
accum = flattenQuadraticArcRec(x012, y012, x12, y12, x2, y2, tolerance, maxTurn, out, arcOut, accum, depth + 1);
|
|
136
|
+
return accum;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/polyline.ts
|
|
140
|
+
function pointInPolygon(coords, px, py, start = 0, end = coords.length >> 1) {
|
|
141
|
+
if (end - start < 3) return false;
|
|
142
|
+
let inside = false;
|
|
143
|
+
for (let i = start, j = end - 1; i < end; j = i++) {
|
|
144
|
+
const xi = coords[i * 2], yi = coords[i * 2 + 1];
|
|
145
|
+
const xj = coords[j * 2], yj = coords[j * 2 + 1];
|
|
146
|
+
const crosses = yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi;
|
|
147
|
+
if (crosses) inside = !inside;
|
|
148
|
+
}
|
|
149
|
+
return inside;
|
|
150
|
+
}
|
|
151
|
+
function segmentsCross(ax, ay, bx, by, cx, cy, dx, dy) {
|
|
152
|
+
const d1 = sign((dx - cx) * (ay - cy) - (dy - cy) * (ax - cx));
|
|
153
|
+
const d2 = sign((dx - cx) * (by - cy) - (dy - cy) * (bx - cx));
|
|
154
|
+
const d3 = sign((bx - ax) * (cy - ay) - (by - ay) * (cx - ax));
|
|
155
|
+
const d4 = sign((bx - ax) * (dy - ay) - (by - ay) * (dx - ax));
|
|
156
|
+
return d1 !== d2 && d3 !== d4;
|
|
157
|
+
}
|
|
158
|
+
function pointSegmentDist2(px, py, ax, ay, bx, by) {
|
|
159
|
+
const vx = bx - ax, vy = by - ay;
|
|
160
|
+
const wx = px - ax, wy = py - ay;
|
|
161
|
+
const vv = len2(vx, vy);
|
|
162
|
+
let t = vv === 0 ? 0 : dot(wx, wy, vx, vy) / vv;
|
|
163
|
+
t = t < 0 ? 0 : t > 1 ? 1 : t;
|
|
164
|
+
const dx = px - (ax + t * vx), dy = py - (ay + t * vy);
|
|
165
|
+
return len2(dx, dy);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/openFill.ts
|
|
169
|
+
var fallback = "close";
|
|
170
|
+
function setDefaultOpenFill(rule) {
|
|
171
|
+
fallback = rule;
|
|
172
|
+
}
|
|
173
|
+
function defaultOpenFill() {
|
|
174
|
+
return fallback;
|
|
175
|
+
}
|
|
176
|
+
function fillsOpenSubpaths(path) {
|
|
177
|
+
return (path.openFill ?? fallback) === "close";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/paths/schneiderFit.ts
|
|
181
|
+
function schneiderFit(samples, errorTolerance) {
|
|
182
|
+
if (samples.length === 0) {
|
|
183
|
+
return {
|
|
184
|
+
kind: "polygon",
|
|
185
|
+
commands: new Uint8Array(),
|
|
186
|
+
coords: new Float32Array(),
|
|
187
|
+
fillRule: "nonzero"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const b = new PathBuilder();
|
|
191
|
+
b.moveTo(samples[0].x, samples[0].y);
|
|
192
|
+
if (samples.length === 1) {
|
|
193
|
+
return b.build();
|
|
194
|
+
}
|
|
195
|
+
if (samples.length === 2) {
|
|
196
|
+
emitStraightCubic(b, samples[0], samples[1]);
|
|
197
|
+
return b.build();
|
|
198
|
+
}
|
|
199
|
+
fitRecursive(samples, errorTolerance, b);
|
|
200
|
+
return b.build();
|
|
201
|
+
}
|
|
202
|
+
function fitRecursive(samples, errorTolerance, b) {
|
|
203
|
+
if (samples.length === 2) {
|
|
204
|
+
const fit2 = fitOneCubic(samples);
|
|
205
|
+
b.curveTo(fit2.cp1.x, fit2.cp1.y, fit2.cp2.x, fit2.cp2.y, fit2.end.x, fit2.end.y);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const fit = fitOneCubic(samples);
|
|
209
|
+
const { worstIndex, worstError } = measureError(samples, fit);
|
|
210
|
+
if (worstError <= errorTolerance * errorTolerance) {
|
|
211
|
+
b.curveTo(fit.cp1.x, fit.cp1.y, fit.cp2.x, fit.cp2.y, fit.end.x, fit.end.y);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const left = samples.slice(0, worstIndex + 1);
|
|
215
|
+
const right = samples.slice(worstIndex);
|
|
216
|
+
fitRecursive(left, errorTolerance, b);
|
|
217
|
+
fitRecursive(right, errorTolerance, b);
|
|
218
|
+
}
|
|
219
|
+
function measureError(samples, fit) {
|
|
220
|
+
let worstIndex = 1;
|
|
221
|
+
let worstError = 0;
|
|
222
|
+
const a = samples[0];
|
|
223
|
+
for (let i = 1; i < samples.length - 1; i++) {
|
|
224
|
+
const q = cubicPointAt(a, fit.cp1, fit.cp2, fit.end, fit.ts[i]);
|
|
225
|
+
const dx = samples[i].x - q.x;
|
|
226
|
+
const dy = samples[i].y - q.y;
|
|
227
|
+
const sq = dx * dx + dy * dy;
|
|
228
|
+
if (sq > worstError) {
|
|
229
|
+
worstError = sq;
|
|
230
|
+
worstIndex = i;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return { worstIndex, worstError };
|
|
234
|
+
}
|
|
235
|
+
function fitOneCubic(samples) {
|
|
236
|
+
const n = samples.length;
|
|
237
|
+
return fitWithTangents(
|
|
238
|
+
samples,
|
|
239
|
+
unit(sub(samples[1], samples[0])),
|
|
240
|
+
unit(sub(samples[n - 2], samples[n - 1])),
|
|
241
|
+
4
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
function fitCubicWithTangents(samples, tStart, tEnd, opts = {}) {
|
|
245
|
+
const { cp1, cp2 } = fitWithTangents(samples, tStart, tEnd, opts.passes ?? 4, opts.params);
|
|
246
|
+
return { cp1, cp2 };
|
|
247
|
+
}
|
|
248
|
+
function fitWithTangents(samples, tStart, tEnd, passes, params) {
|
|
249
|
+
const n = samples.length;
|
|
250
|
+
const a = samples[0];
|
|
251
|
+
const e = samples[n - 1];
|
|
252
|
+
const ts = params ? [...params] : chordLengthParam(samples);
|
|
253
|
+
if (ts === null) return { cp1: { ...a }, cp2: { ...e }, end: e, ts: samples.map(() => 0) };
|
|
254
|
+
let fit = solveLS(samples, ts, a, e, tStart, tEnd);
|
|
255
|
+
for (let pass = 0; pass < passes; pass++) {
|
|
256
|
+
reparameterize(samples, ts, a, e, fit);
|
|
257
|
+
fit = solveLS(samples, ts, a, e, tStart, tEnd);
|
|
258
|
+
}
|
|
259
|
+
return fit;
|
|
260
|
+
}
|
|
261
|
+
function chordLengthParam(samples) {
|
|
262
|
+
const n = samples.length;
|
|
263
|
+
const ts = new Array(n);
|
|
264
|
+
ts[0] = 0;
|
|
265
|
+
let total = 0;
|
|
266
|
+
for (let i = 1; i < n; i++) {
|
|
267
|
+
total += dist(samples[i - 1], samples[i]);
|
|
268
|
+
ts[i] = total;
|
|
269
|
+
}
|
|
270
|
+
if (total === 0) return null;
|
|
271
|
+
for (let i = 0; i < n; i++) ts[i] /= total;
|
|
272
|
+
return ts;
|
|
273
|
+
}
|
|
274
|
+
function solveLS(samples, ts, a, e, tStart, tEnd) {
|
|
275
|
+
const n = samples.length;
|
|
276
|
+
let c11 = 0, c12 = 0, c22 = 0, x1 = 0, x2 = 0;
|
|
277
|
+
for (let i = 0; i < n; i++) {
|
|
278
|
+
const t = ts[i];
|
|
279
|
+
const u = 1 - t;
|
|
280
|
+
const b0 = u * u * u;
|
|
281
|
+
const b1 = 3 * u * u * t;
|
|
282
|
+
const b2 = 3 * u * t * t;
|
|
283
|
+
const b3 = t * t * t;
|
|
284
|
+
const A1x = b1 * tStart.x;
|
|
285
|
+
const A1y = b1 * tStart.y;
|
|
286
|
+
const A2x = b2 * tEnd.x;
|
|
287
|
+
const A2y = b2 * tEnd.y;
|
|
288
|
+
c11 += A1x * A1x + A1y * A1y;
|
|
289
|
+
c12 += A1x * A2x + A1y * A2y;
|
|
290
|
+
c22 += A2x * A2x + A2y * A2y;
|
|
291
|
+
const targetX = samples[i].x - (b0 + b1) * a.x - (b2 + b3) * e.x;
|
|
292
|
+
const targetY = samples[i].y - (b0 + b1) * a.y - (b2 + b3) * e.y;
|
|
293
|
+
x1 += A1x * targetX + A1y * targetY;
|
|
294
|
+
x2 += A2x * targetX + A2y * targetY;
|
|
295
|
+
}
|
|
296
|
+
const det = c11 * c22 - c12 * c12;
|
|
297
|
+
let alpha1;
|
|
298
|
+
let alpha2;
|
|
299
|
+
if (Math.abs(det) < 1e-12) {
|
|
300
|
+
const chord = dist(a, e);
|
|
301
|
+
alpha1 = alpha2 = chord / 3;
|
|
302
|
+
} else {
|
|
303
|
+
alpha1 = (c22 * x1 - c12 * x2) / det;
|
|
304
|
+
alpha2 = (c11 * x2 - c12 * x1) / det;
|
|
305
|
+
if (alpha1 < 1e-6 || alpha2 < 1e-6) {
|
|
306
|
+
const chord = dist(a, e);
|
|
307
|
+
alpha1 = alpha2 = chord / 3;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
cp1: { x: a.x + tStart.x * alpha1, y: a.y + tStart.y * alpha1 },
|
|
312
|
+
cp2: { x: e.x + tEnd.x * alpha2, y: e.y + tEnd.y * alpha2 },
|
|
313
|
+
end: e,
|
|
314
|
+
ts
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function reparameterize(samples, ts, a, e, fit) {
|
|
318
|
+
for (let i = 1; i < samples.length - 1; i++) {
|
|
319
|
+
ts[i] = newtonRefineT(samples[i], ts[i], samples[0], fit.cp1, fit.cp2, samples[samples.length - 1]);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function newtonRefineT(p, t, p0, p1, p2, p3) {
|
|
323
|
+
const u = 1 - t;
|
|
324
|
+
const { x: qx, y: qy } = cubicPointAt(p0, p1, p2, p3, t);
|
|
325
|
+
const qpx = 3 * u * u * (p1.x - p0.x) + 6 * u * t * (p2.x - p1.x) + 3 * t * t * (p3.x - p2.x);
|
|
326
|
+
const qpy = 3 * u * u * (p1.y - p0.y) + 6 * u * t * (p2.y - p1.y) + 3 * t * t * (p3.y - p2.y);
|
|
327
|
+
const qppx = 6 * u * (p2.x - 2 * p1.x + p0.x) + 6 * t * (p3.x - 2 * p2.x + p1.x);
|
|
328
|
+
const qppy = 6 * u * (p2.y - 2 * p1.y + p0.y) + 6 * t * (p3.y - 2 * p2.y + p1.y);
|
|
329
|
+
const dx = qx - p.x;
|
|
330
|
+
const dy = qy - p.y;
|
|
331
|
+
const numerator = dx * qpx + dy * qpy;
|
|
332
|
+
const denominator = qpx * qpx + qpy * qpy + dx * qppx + dy * qppy;
|
|
333
|
+
if (Math.abs(denominator) < 1e-12) return t;
|
|
334
|
+
const next = t - numerator / denominator;
|
|
335
|
+
if (next < 0) return 0;
|
|
336
|
+
if (next > 1) return 1;
|
|
337
|
+
return next;
|
|
338
|
+
}
|
|
339
|
+
function sub(a, b) {
|
|
340
|
+
return { x: a.x - b.x, y: a.y - b.y };
|
|
341
|
+
}
|
|
342
|
+
function dist(a, b) {
|
|
343
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
344
|
+
}
|
|
345
|
+
function unit(v) {
|
|
346
|
+
const m = Math.hypot(v.x, v.y);
|
|
347
|
+
if (m === 0) return { x: 0, y: 0 };
|
|
348
|
+
return { x: v.x / m, y: v.y / m };
|
|
349
|
+
}
|
|
350
|
+
function emitStraightCubic(b, a, c) {
|
|
351
|
+
const cp1x = a.x + (c.x - a.x) / 3;
|
|
352
|
+
const cp1y = a.y + (c.y - a.y) / 3;
|
|
353
|
+
const cp2x = a.x + 2 * (c.x - a.x) / 3;
|
|
354
|
+
const cp2y = a.y + 2 * (c.y - a.y) / 3;
|
|
355
|
+
b.curveTo(cp1x, cp1y, cp2x, cp2y, c.x, c.y);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/paths/cornerShape.ts
|
|
359
|
+
var CORNER_KEYWORDS = ["square", "squircle", "round", "bevel", "scoop", "notch"];
|
|
360
|
+
var K_OF = {
|
|
361
|
+
square: Infinity,
|
|
362
|
+
squircle: 2,
|
|
363
|
+
round: 1,
|
|
364
|
+
bevel: 0,
|
|
365
|
+
scoop: -1,
|
|
366
|
+
notch: -Infinity
|
|
367
|
+
};
|
|
368
|
+
function cornerShapeK(shape) {
|
|
369
|
+
return typeof shape === "number" ? shape : K_OF[shape];
|
|
370
|
+
}
|
|
371
|
+
function cornerKeywordOf(k) {
|
|
372
|
+
return CORNER_KEYWORDS.find((w) => K_OF[w] === k) ?? null;
|
|
373
|
+
}
|
|
374
|
+
function isCornerShape(v) {
|
|
375
|
+
return typeof v === "number" && Number.isFinite(v) || CORNER_KEYWORDS.includes(v);
|
|
376
|
+
}
|
|
377
|
+
function nextCornerShape(shape) {
|
|
378
|
+
if (typeof shape !== "number") {
|
|
379
|
+
return CORNER_KEYWORDS[(CORNER_KEYWORDS.indexOf(shape) + 1) % CORNER_KEYWORDS.length];
|
|
380
|
+
}
|
|
381
|
+
return CORNER_KEYWORDS.find((w) => K_OF[w] < shape) ?? CORNER_KEYWORDS[0];
|
|
382
|
+
}
|
|
383
|
+
var CORNER_FIT_TOLERANCE = 1e-3;
|
|
384
|
+
var KAPPA = 4 / 3 * Math.tan(Math.PI / 8);
|
|
385
|
+
function exponentOf(k) {
|
|
386
|
+
const n = 2 ** Math.abs(k);
|
|
387
|
+
return 1 - 0.5 ** (1 / n) < CORNER_FIT_TOLERANCE / 4 ? Infinity : n;
|
|
388
|
+
}
|
|
389
|
+
function unitPoint(n, theta) {
|
|
390
|
+
const p = 2 / n;
|
|
391
|
+
return { x: Math.cos(theta) ** p, y: Math.sin(theta) ** p };
|
|
392
|
+
}
|
|
393
|
+
function unitTangent(n, theta) {
|
|
394
|
+
const q = 2 - 2 / n;
|
|
395
|
+
const x = Math.sin(theta) ** q, y = -(Math.cos(theta) ** q);
|
|
396
|
+
const l = Math.hypot(x, y);
|
|
397
|
+
return { x: x / l, y: y / l };
|
|
398
|
+
}
|
|
399
|
+
var sub2 = (a, b) => ({ x: a.x - b.x, y: a.y - b.y });
|
|
400
|
+
function cubicAt(p0, [c1, c2, p3], t) {
|
|
401
|
+
const u = 1 - t;
|
|
402
|
+
const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
|
|
403
|
+
return { x: a * p0.x + b * c1.x + c * c2.x + d * p3.x, y: a * p0.y + b * c1.y + c * c2.y + d * p3.y };
|
|
404
|
+
}
|
|
405
|
+
function distanceToCubic(q, p0, piece) {
|
|
406
|
+
const d = (t) => {
|
|
407
|
+
const c = cubicAt(p0, piece, t);
|
|
408
|
+
return Math.hypot(c.x - q.x, c.y - q.y);
|
|
409
|
+
};
|
|
410
|
+
let best = 0;
|
|
411
|
+
for (let i = 1; i <= 32; i++) if (d(i / 32) < d(best / 32)) best = i;
|
|
412
|
+
let lo = Math.max(0, (best - 1) / 32), hi = Math.min(1, (best + 1) / 32);
|
|
413
|
+
for (let i = 0; i < 30; i++) {
|
|
414
|
+
const a = lo + (hi - lo) / 3, b = hi - (hi - lo) / 3;
|
|
415
|
+
if (d(a) < d(b)) hi = b;
|
|
416
|
+
else lo = a;
|
|
417
|
+
}
|
|
418
|
+
return d((lo + hi) / 2);
|
|
419
|
+
}
|
|
420
|
+
function fitError(n, a, b, p0, piece) {
|
|
421
|
+
let worst = 0;
|
|
422
|
+
for (let i = 1; i < 16; i++) worst = Math.max(worst, distanceToCubic(unitPoint(n, a + (b - a) * (i / 16)), p0, piece));
|
|
423
|
+
return worst;
|
|
424
|
+
}
|
|
425
|
+
function fitUnit(n, a, b, tol, depth, out) {
|
|
426
|
+
const p0 = unitPoint(n, a), p3 = unitPoint(n, b);
|
|
427
|
+
const samples = [];
|
|
428
|
+
const params = [];
|
|
429
|
+
for (let i = 0; i <= 12; i++) {
|
|
430
|
+
samples.push(unitPoint(n, a + (b - a) * (i / 12)));
|
|
431
|
+
params.push(i / 12);
|
|
432
|
+
}
|
|
433
|
+
const tEnd = unitTangent(n, b);
|
|
434
|
+
const { cp1, cp2 } = fitCubicWithTangents(samples, unitTangent(n, a), { x: -tEnd.x, y: -tEnd.y }, { params });
|
|
435
|
+
const piece = [cp1, cp2, p3];
|
|
436
|
+
if (depth >= 10 || fitError(n, a, b, p0, piece) <= tol) {
|
|
437
|
+
out.push(piece);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const mid = (a + b) / 2;
|
|
441
|
+
fitUnit(n, a, mid, tol, depth + 1, out);
|
|
442
|
+
fitUnit(n, mid, b, tol, depth + 1, out);
|
|
443
|
+
}
|
|
444
|
+
var unitCache = /* @__PURE__ */ new Map();
|
|
445
|
+
function unitCubics(n, tol) {
|
|
446
|
+
if (n === 2) return [[{ x: KAPPA, y: 1 }, { x: 1, y: KAPPA }, { x: 1, y: 0 }]];
|
|
447
|
+
const key = `${n}:${tol}`;
|
|
448
|
+
let hit = unitCache.get(key);
|
|
449
|
+
if (!hit) {
|
|
450
|
+
hit = [];
|
|
451
|
+
fitUnit(n, Math.PI / 2, 0, tol, 0, hit);
|
|
452
|
+
if (unitCache.size > 256) unitCache.clear();
|
|
453
|
+
unitCache.set(key, hit);
|
|
454
|
+
}
|
|
455
|
+
return hit;
|
|
456
|
+
}
|
|
457
|
+
function mapperFor(frame, center) {
|
|
458
|
+
const ex = sub2(frame.end, center), sy = sub2(frame.start, center);
|
|
459
|
+
return (p) => ({ x: center.x + p.x * ex.x + p.y * sy.x, y: center.y + p.x * ex.y + p.y * sy.y });
|
|
460
|
+
}
|
|
461
|
+
function cornerCenter(frame) {
|
|
462
|
+
return { x: frame.start.x + frame.end.x - frame.outer.x, y: frame.start.y + frame.end.y - frame.outer.y };
|
|
463
|
+
}
|
|
464
|
+
function cornerShapePieces(k, frame, tolerance = CORNER_FIT_TOLERANCE) {
|
|
465
|
+
if (k === 0) return [{ kind: "line", to: frame.end }];
|
|
466
|
+
const n = exponentOf(k);
|
|
467
|
+
if (n === Infinity) {
|
|
468
|
+
const via = k > 0 ? frame.outer : cornerCenter(frame);
|
|
469
|
+
return [{ kind: "line", to: via }, { kind: "line", to: frame.end }];
|
|
470
|
+
}
|
|
471
|
+
const map = mapperFor(frame, k > 0 ? cornerCenter(frame) : frame.outer);
|
|
472
|
+
return unitCubics(n, tolerance).map(([c1, c2, to]) => ({ kind: "cubic", c1: map(c1), c2: map(c2), to: map(to) }));
|
|
473
|
+
}
|
|
474
|
+
function cornerShapePoint(k, frame, s) {
|
|
475
|
+
const n = 2 ** Math.abs(k);
|
|
476
|
+
const map = mapperFor(frame, k > 0 ? cornerCenter(frame) : frame.outer);
|
|
477
|
+
return map(unitPoint(n, Math.PI / 2 * (1 - s)));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/paths/cornerSegments.ts
|
|
481
|
+
var lineSeg = (a, b) => ({ line: true, p0: a, c1: a, c2: b, p3: b });
|
|
482
|
+
function decodeContours(path) {
|
|
483
|
+
const { commands, coords } = path;
|
|
484
|
+
const out = [];
|
|
485
|
+
let cur = null;
|
|
486
|
+
let flat = 0;
|
|
487
|
+
let drawn = 0;
|
|
488
|
+
let bad = false;
|
|
489
|
+
const last = () => cur.anchors[cur.anchors.length - 1];
|
|
490
|
+
const push = (p, seg) => {
|
|
491
|
+
cur.segs.push(seg);
|
|
492
|
+
cur.anchors.push(p);
|
|
493
|
+
cur.sources.push(drawn++);
|
|
494
|
+
flat++;
|
|
495
|
+
};
|
|
496
|
+
forEachSegment(commands, coords, (cmd, ci, _px, _py, _i, opens) => {
|
|
497
|
+
if (opens) {
|
|
498
|
+
bad = true;
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
const at = (k) => ({ x: coords[ci + k], y: coords[ci + k + 1] });
|
|
502
|
+
switch (cmd) {
|
|
503
|
+
case PATH_M:
|
|
504
|
+
if (cur) out.push(cur);
|
|
505
|
+
cur = { anchors: [at(0)], segs: [], closed: false, first: flat++, sources: [drawn++] };
|
|
506
|
+
break;
|
|
507
|
+
case PATH_L:
|
|
508
|
+
push(at(0), lineSeg(last(), at(0)));
|
|
509
|
+
break;
|
|
510
|
+
case PATH_C:
|
|
511
|
+
push(at(4), { line: false, p0: last(), c1: at(0), c2: at(2), p3: at(4) });
|
|
512
|
+
break;
|
|
513
|
+
case PATH_Q: {
|
|
514
|
+
const p0 = last(), q = at(0), p3 = at(2);
|
|
515
|
+
const c1 = { x: p0.x + 2 / 3 * (q.x - p0.x), y: p0.y + 2 / 3 * (q.y - p0.y) };
|
|
516
|
+
const c2 = { x: p3.x + 2 / 3 * (q.x - p3.x), y: p3.y + 2 / 3 * (q.y - p3.y) };
|
|
517
|
+
push(p3, { line: false, p0, c1, c2, p3 });
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
case PATH_Z:
|
|
521
|
+
if (cur) closeContour(cur, () => flat--);
|
|
522
|
+
if (cur) out.push(cur);
|
|
523
|
+
cur = null;
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
return void 0;
|
|
527
|
+
});
|
|
528
|
+
if (bad) return null;
|
|
529
|
+
if (cur) out.push(cur);
|
|
530
|
+
return out;
|
|
531
|
+
}
|
|
532
|
+
function closeContour(c, unfold) {
|
|
533
|
+
c.closed = true;
|
|
534
|
+
const n = c.anchors.length;
|
|
535
|
+
const a0 = c.anchors[0];
|
|
536
|
+
const end = c.anchors[n - 1];
|
|
537
|
+
if (n > 1 && !c.segs[n - 2].line && end.x === a0.x && end.y === a0.y) {
|
|
538
|
+
c.anchors.pop();
|
|
539
|
+
c.sources.pop();
|
|
540
|
+
unfold();
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
c.segs.push(lineSeg(end, a0));
|
|
544
|
+
}
|
|
545
|
+
var LUT_STEPS = 32;
|
|
546
|
+
function segLength(seg) {
|
|
547
|
+
if (seg.line) return Math.hypot(seg.p3.x - seg.p0.x, seg.p3.y - seg.p0.y);
|
|
548
|
+
return lut(seg)[LUT_STEPS];
|
|
549
|
+
}
|
|
550
|
+
var lutCache = /* @__PURE__ */ new WeakMap();
|
|
551
|
+
function lut(seg) {
|
|
552
|
+
let table = lutCache.get(seg);
|
|
553
|
+
if (table) return table;
|
|
554
|
+
table = new Float64Array(LUT_STEPS + 1);
|
|
555
|
+
let prev = seg.p0;
|
|
556
|
+
for (let i = 1; i <= LUT_STEPS; i++) {
|
|
557
|
+
const p = pointAt(seg, i / LUT_STEPS);
|
|
558
|
+
table[i] = table[i - 1] + Math.hypot(p.x - prev.x, p.y - prev.y);
|
|
559
|
+
prev = p;
|
|
560
|
+
}
|
|
561
|
+
lutCache.set(seg, table);
|
|
562
|
+
return table;
|
|
563
|
+
}
|
|
564
|
+
function paramAtLength(seg, s) {
|
|
565
|
+
const total = segLength(seg);
|
|
566
|
+
if (total <= 0) return 0;
|
|
567
|
+
if (seg.line) return Math.min(1, Math.max(0, s / total));
|
|
568
|
+
const table = lut(seg);
|
|
569
|
+
if (s <= 0) return 0;
|
|
570
|
+
if (s >= total) return 1;
|
|
571
|
+
let i = 1;
|
|
572
|
+
while (table[i] < s) i++;
|
|
573
|
+
const span = table[i] - table[i - 1];
|
|
574
|
+
const f = span > 0 ? (s - table[i - 1]) / span : 0;
|
|
575
|
+
return (i - 1 + f) / LUT_STEPS;
|
|
576
|
+
}
|
|
577
|
+
function pointAt(seg, t) {
|
|
578
|
+
if (seg.line) {
|
|
579
|
+
return { x: seg.p0.x + (seg.p3.x - seg.p0.x) * t, y: seg.p0.y + (seg.p3.y - seg.p0.y) * t };
|
|
580
|
+
}
|
|
581
|
+
const { p0, c1, c2, p3 } = seg;
|
|
582
|
+
const [x, y] = cubicEvalAt(p0.x, p0.y, c1.x, c1.y, c2.x, c2.y, p3.x, p3.y, t);
|
|
583
|
+
return { x, y };
|
|
584
|
+
}
|
|
585
|
+
function unit2(x, y) {
|
|
586
|
+
const l = Math.hypot(x, y);
|
|
587
|
+
return l > 1e-12 ? { x: x / l, y: y / l } : null;
|
|
588
|
+
}
|
|
589
|
+
function tangentAt(seg, t) {
|
|
590
|
+
const { p0, c1, c2, p3 } = seg;
|
|
591
|
+
if (seg.line) return unit2(p3.x - p0.x, p3.y - p0.y);
|
|
592
|
+
const u = 1 - t;
|
|
593
|
+
const dx = 3 * (u * u * (c1.x - p0.x) + 2 * u * t * (c2.x - c1.x) + t * t * (p3.x - c2.x));
|
|
594
|
+
const dy = 3 * (u * u * (c1.y - p0.y) + 2 * u * t * (c2.y - c1.y) + t * t * (p3.y - c2.y));
|
|
595
|
+
const d = unit2(dx, dy);
|
|
596
|
+
if (d) return d;
|
|
597
|
+
if (t < 0.5) return unit2(c2.x - p0.x, c2.y - p0.y) ?? unit2(p3.x - p0.x, p3.y - p0.y);
|
|
598
|
+
return unit2(p3.x - c1.x, p3.y - c1.y) ?? unit2(p3.x - p0.x, p3.y - p0.y);
|
|
599
|
+
}
|
|
600
|
+
function subCubic(seg, t0, t1) {
|
|
601
|
+
const { p0, c1, c2, p3 } = seg;
|
|
602
|
+
let c = [p0.x, p0.y, c1.x, c1.y, c2.x, c2.y, p3.x, p3.y];
|
|
603
|
+
if (t0 > 0) c = [...splitCubicAt(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], t0)[1]];
|
|
604
|
+
const t = t0 < 1 ? (t1 - t0) / (1 - t0) : 1;
|
|
605
|
+
if (t < 1) c = [...splitCubicAt(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], t)[0]];
|
|
606
|
+
return [{ x: c[2], y: c[3] }, { x: c[4], y: c[5] }, { x: c[6], y: c[7] }];
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// src/paths/corners.ts
|
|
610
|
+
var MIN_TURN = 1e-3;
|
|
611
|
+
function contourCuts(path, c) {
|
|
612
|
+
const n = c.anchors.length;
|
|
613
|
+
const lengths = c.segs.map(segLength);
|
|
614
|
+
const cuts = c.anchors.map((a, i) => {
|
|
615
|
+
const inSeg = i > 0 ? c.segs[i - 1] : c.closed ? c.segs[n - 1] : null;
|
|
616
|
+
const outSeg = i < c.segs.length ? c.segs[i] : null;
|
|
617
|
+
if (!inSeg || !outSeg || inSeg === outSeg) return null;
|
|
618
|
+
const tIn = tangentAt(inSeg, 1);
|
|
619
|
+
const tOut = tangentAt(outSeg, 0);
|
|
620
|
+
if (!tIn || !tOut) return null;
|
|
621
|
+
const turn = Math.acos(Math.max(-1, Math.min(1, tIn.x * tOut.x + tIn.y * tOut.y)));
|
|
622
|
+
if (turn < MIN_TURN || turn > Math.PI - MIN_TURN) return null;
|
|
623
|
+
const bx = tOut.x - tIn.x, by = tOut.y - tIn.y;
|
|
624
|
+
const bl = Math.hypot(bx, by);
|
|
625
|
+
const halfAngle = (Math.PI - turn) / 2;
|
|
626
|
+
const spec = cornerAt(path, c.first + i);
|
|
627
|
+
const want = spec ? spec.radius : 0;
|
|
628
|
+
return {
|
|
629
|
+
frame: { index: c.first + i, x: a.x, y: a.y, bisector: { x: bx / bl, y: by / bl }, halfAngle },
|
|
630
|
+
spec,
|
|
631
|
+
want,
|
|
632
|
+
trim: want
|
|
633
|
+
};
|
|
634
|
+
});
|
|
635
|
+
const scale = cuts.map(() => 1);
|
|
636
|
+
c.segs.forEach((_seg, k) => {
|
|
637
|
+
const a = k, b = (k + 1) % n;
|
|
638
|
+
const sum = (cuts[a]?.want ?? 0) + (cuts[b]?.want ?? 0);
|
|
639
|
+
if (sum <= lengths[k]) return;
|
|
640
|
+
const f = lengths[k] / sum;
|
|
641
|
+
scale[a] = Math.min(scale[a], f);
|
|
642
|
+
scale[b] = Math.min(scale[b], f);
|
|
643
|
+
});
|
|
644
|
+
cuts.forEach((cut, i) => {
|
|
645
|
+
if (cut) cut.trim = cut.want * scale[i];
|
|
646
|
+
});
|
|
647
|
+
return cuts;
|
|
648
|
+
}
|
|
649
|
+
function cornerFrames(path) {
|
|
650
|
+
const contours = decodeContours(path);
|
|
651
|
+
if (!contours) return [];
|
|
652
|
+
const out = [];
|
|
653
|
+
for (const c of contours) {
|
|
654
|
+
const cuts = contourCuts(path, c);
|
|
655
|
+
const n = c.anchors.length;
|
|
656
|
+
cuts.forEach((cut, i) => {
|
|
657
|
+
if (!cut) return;
|
|
658
|
+
const prev = (i - 1 + n) % n;
|
|
659
|
+
const next = (i + 1) % n;
|
|
660
|
+
const inLen = segLength(c.segs[prev]);
|
|
661
|
+
const outLen = segLength(c.segs[i]);
|
|
662
|
+
const room = (len, j) => len - Math.min(len, cuts[j]?.want ?? 0);
|
|
663
|
+
out.push({
|
|
664
|
+
...cut.frame,
|
|
665
|
+
trim: cut.trim,
|
|
666
|
+
maxTrim: Math.max(0, Math.min(room(inLen, prev), room(outLen, next)))
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return out;
|
|
671
|
+
}
|
|
672
|
+
function cornerFrameAt(path, index) {
|
|
673
|
+
return cornerFrames(path).find((f) => f.index === index) ?? null;
|
|
674
|
+
}
|
|
675
|
+
var expanded = /* @__PURE__ */ new WeakMap();
|
|
676
|
+
function resolveCornersWithSources(path) {
|
|
677
|
+
if (path.corners === void 0) return { path, anchorSources: null };
|
|
678
|
+
const hit = expanded.get(path);
|
|
679
|
+
if (hit) return hit;
|
|
680
|
+
const out = hasCorners(path) ? expand(path) : { path: withoutCorners(path), anchorSources: null };
|
|
681
|
+
expanded.set(path, out);
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
function resolveCorners(path) {
|
|
685
|
+
if (path.kind !== "polygon") return path;
|
|
686
|
+
return resolveCornersWithSources(path).path;
|
|
687
|
+
}
|
|
688
|
+
function remapPerAnchor(values, sources, stride) {
|
|
689
|
+
const out = new Array(sources.length * stride);
|
|
690
|
+
for (let i = 0; i < sources.length; i++) {
|
|
691
|
+
for (let k = 0; k < stride; k++) out[i * stride + k] = values[sources[i] * stride + k];
|
|
692
|
+
}
|
|
693
|
+
return out;
|
|
694
|
+
}
|
|
695
|
+
var Emitter = class {
|
|
696
|
+
b = new PathBuilder();
|
|
697
|
+
sources = [];
|
|
698
|
+
src = 0;
|
|
699
|
+
moveTo(x, y) {
|
|
700
|
+
this.b.moveTo(x, y);
|
|
701
|
+
this.sources.push(this.src);
|
|
702
|
+
}
|
|
703
|
+
lineTo(x, y) {
|
|
704
|
+
this.b.lineTo(x, y);
|
|
705
|
+
this.sources.push(this.src);
|
|
706
|
+
}
|
|
707
|
+
curveTo(a, b, c, d, x, y) {
|
|
708
|
+
this.b.curveTo(a, b, c, d, x, y);
|
|
709
|
+
this.sources.push(this.src);
|
|
710
|
+
}
|
|
711
|
+
close() {
|
|
712
|
+
this.b.close();
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
function expand(path) {
|
|
716
|
+
const contours = decodeContours(path);
|
|
717
|
+
if (!contours) return { path: withoutCorners(path), anchorSources: null };
|
|
718
|
+
const e = new Emitter();
|
|
719
|
+
for (const c of contours) emitContour(e, c, contourCuts(path, c));
|
|
720
|
+
const { commands, coords } = e.b.build();
|
|
721
|
+
return {
|
|
722
|
+
path: { ...withoutCorners(path), commands, coords },
|
|
723
|
+
anchorSources: Uint32Array.from(e.sources)
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function segSpan(c, cuts, k) {
|
|
727
|
+
const seg = c.segs[k];
|
|
728
|
+
const len = segLength(seg);
|
|
729
|
+
const t0 = paramAtLength(seg, cuts[k]?.trim ?? 0);
|
|
730
|
+
const t1 = paramAtLength(seg, len - (cuts[(k + 1) % c.anchors.length]?.trim ?? 0));
|
|
731
|
+
return [t0, Math.max(t0, t1)];
|
|
732
|
+
}
|
|
733
|
+
function cutAfter(c, cuts, spans, k) {
|
|
734
|
+
const j = (k + 1) % c.anchors.length;
|
|
735
|
+
const cut = cuts[j];
|
|
736
|
+
const next = c.segs[j];
|
|
737
|
+
if (!cut?.spec || cut.trim <= 0 || !next) return null;
|
|
738
|
+
const seg = c.segs[k];
|
|
739
|
+
const start = pointAt(seg, spans[k][1]);
|
|
740
|
+
const end = pointAt(next, spans[j][0]);
|
|
741
|
+
const frame = shapeFrame({ x: cut.frame.x, y: cut.frame.y }, start, tangentAt(seg, spans[k][1]), end, tangentAt(next, spans[j][0]));
|
|
742
|
+
return { cut, start, end, pieces: cornerShapePieces(cornerShapeK(cut.spec.shape), frame) };
|
|
743
|
+
}
|
|
744
|
+
function cornerCuts(path) {
|
|
745
|
+
if (!hasCorners(path)) return [];
|
|
746
|
+
const out = [];
|
|
747
|
+
for (const c of decodeContours(path) ?? []) {
|
|
748
|
+
const cuts = contourCuts(path, c);
|
|
749
|
+
const spans = c.segs.map((_s, k) => segSpan(c, cuts, k));
|
|
750
|
+
c.segs.forEach((_seg, k) => {
|
|
751
|
+
const at = cutAfter(c, cuts, spans, k);
|
|
752
|
+
if (!at) return;
|
|
753
|
+
const { frame } = at.cut;
|
|
754
|
+
out.push({ index: frame.index, anchor: { x: frame.x, y: frame.y }, spec: at.cut.spec, start: at.start, end: at.end, pieces: at.pieces });
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
return out;
|
|
758
|
+
}
|
|
759
|
+
function emitContour(b, c, cuts) {
|
|
760
|
+
const n = c.anchors.length;
|
|
761
|
+
const spans = c.segs.map((_s, k) => segSpan(c, cuts, k));
|
|
762
|
+
const start = c.closed && c.segs.length > 0 ? pointAt(c.segs[0], spans[0][0]) : c.anchors[0];
|
|
763
|
+
b.src = c.sources[0];
|
|
764
|
+
b.moveTo(start.x, start.y);
|
|
765
|
+
c.segs.forEach((seg, k) => {
|
|
766
|
+
const [t0, t1] = spans[k];
|
|
767
|
+
b.src = c.sources[(k + 1) % n];
|
|
768
|
+
const closing = c.closed && k === n - 1 && !(cuts[0]?.spec && cuts[0].trim > 0);
|
|
769
|
+
if (t1 > t0 && !(closing && seg.line)) {
|
|
770
|
+
if (seg.line) {
|
|
771
|
+
const p = pointAt(seg, t1);
|
|
772
|
+
b.lineTo(p.x, p.y);
|
|
773
|
+
} else {
|
|
774
|
+
const [c1, c2, p3] = subCubic(seg, t0, t1);
|
|
775
|
+
b.curveTo(c1.x, c1.y, c2.x, c2.y, p3.x, p3.y);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
const at = cutAfter(c, cuts, spans, k);
|
|
779
|
+
if (!at) return;
|
|
780
|
+
const pieces = [...at.pieces];
|
|
781
|
+
if ((k + 1) % n === 0 && pieces.at(-1)?.kind === "line") pieces.pop();
|
|
782
|
+
for (const piece of pieces) {
|
|
783
|
+
if (piece.kind === "line") b.lineTo(piece.to.x, piece.to.y);
|
|
784
|
+
else b.curveTo(piece.c1.x, piece.c1.y, piece.c2.x, piece.c2.y, piece.to.x, piece.to.y);
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
if (c.closed) b.close();
|
|
788
|
+
}
|
|
789
|
+
function shapeFrame(v, p1, t1, p2, t2) {
|
|
790
|
+
const outer = t1 && t2 ? tangentMeet(p1, t1, p2, t2) : null;
|
|
791
|
+
const chord = Math.hypot(p2.x - p1.x, p2.y - p1.y);
|
|
792
|
+
const far = !outer || Math.hypot(outer.x - v.x, outer.y - v.y) > 4 * chord;
|
|
793
|
+
return { start: p1, end: p2, outer: far ? v : outer };
|
|
794
|
+
}
|
|
795
|
+
function tangentMeet(a, ta, b, tb) {
|
|
796
|
+
const den = ta.x * tb.y - ta.y * tb.x;
|
|
797
|
+
if (Math.abs(den) < 1e-9) return null;
|
|
798
|
+
const s = ((b.x - a.x) * tb.y - (b.y - a.y) * tb.x) / den;
|
|
799
|
+
return { x: a.x + ta.x * s, y: a.y + ta.y * s };
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, decodeContours, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, pointSegmentDist2, remapPerAnchor, resolveCorners, resolveCornersWithSources, schneiderFit, segmentsCross, setDefaultOpenFill };
|
|
803
|
+
//# sourceMappingURL=chunk-EAKE3N7W.js.map
|
|
804
|
+
//# sourceMappingURL=chunk-EAKE3N7W.js.map
|