lineadraw 0.10.0 → 0.11.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.
Files changed (35) hide show
  1. package/README.md +18 -7
  2. package/bin/lineadraw.mjs +60 -10
  3. package/dist/bridge.d.ts +1 -0
  4. package/dist/bridge.js +1 -1
  5. package/dist/{chunk-YYJAXJOY.js → chunk-7UFXC7OI.js} +1680 -141
  6. package/dist/chunk-7UFXC7OI.js.map +1 -0
  7. package/dist/chunk-FDLANLIC.js +1161 -0
  8. package/dist/chunk-FDLANLIC.js.map +1 -0
  9. package/dist/chunk-M3EDRSHW.js +81 -0
  10. package/dist/chunk-M3EDRSHW.js.map +1 -0
  11. package/dist/chunk-MYP7RUYK.js +9 -0
  12. package/dist/chunk-MYP7RUYK.js.map +1 -0
  13. package/dist/{chunk-L2CWZAKW.js → chunk-RNA2RDGL.js} +13 -6
  14. package/dist/chunk-RNA2RDGL.js.map +1 -0
  15. package/dist/dist-56K6CNML.js +188 -0
  16. package/dist/dist-56K6CNML.js.map +1 -0
  17. package/dist/dist-IEN64QSV.js +10 -0
  18. package/dist/dist-IEN64QSV.js.map +1 -0
  19. package/dist/emscripten-module-Q67P5WYC-ITCU5LXL.js +2424 -0
  20. package/dist/emscripten-module-Q67P5WYC-ITCU5LXL.js.map +1 -0
  21. package/dist/{exportDxf-C4CLQCC3.js → exportDxf-6XTXQ4XN.js} +2 -2
  22. package/dist/ffi-SHMEF5YV.js +82 -0
  23. package/dist/ffi-SHMEF5YV.js.map +1 -0
  24. package/dist/module-ES6BEMUI-BJFWC656.js +14 -0
  25. package/dist/module-ES6BEMUI-BJFWC656.js.map +1 -0
  26. package/dist/module-asyncify-2EFITU5U-7F5WZXRA.js +9 -0
  27. package/dist/module-asyncify-2EFITU5U-7F5WZXRA.js.map +1 -0
  28. package/dist/sdk.d.ts +868 -95
  29. package/dist/sdk.js +619 -558
  30. package/dist/sdk.js.map +1 -1
  31. package/lineadraw.d.ts +162 -8
  32. package/package.json +2 -2
  33. package/dist/chunk-L2CWZAKW.js.map +0 -1
  34. package/dist/chunk-YYJAXJOY.js.map +0 -1
  35. /package/dist/{exportDxf-C4CLQCC3.js.map → exportDxf-6XTXQ4XN.js.map} +0 -0
@@ -2,6 +2,811 @@ import {
2
2
  __export
3
3
  } from "./chunk-PZ5AY32C.js";
4
4
 
5
+ // ../core/src/geometry/vec2.ts
6
+ var add = (a2, b) => ({ x: a2.x + b.x, y: a2.y + b.y });
7
+ var sub = (a2, b) => ({ x: a2.x - b.x, y: a2.y - b.y });
8
+ var scale = (a2, s) => ({ x: a2.x * s, y: a2.y * s });
9
+ var dot = (a2, b) => a2.x * b.x + a2.y * b.y;
10
+ var lenSq = (a2) => a2.x * a2.x + a2.y * a2.y;
11
+ var len = (a2) => Math.hypot(a2.x, a2.y);
12
+ var dist = (a2, b) => Math.hypot(b.x - a2.x, b.y - a2.y);
13
+ var norm = (a2) => {
14
+ const l = len(a2);
15
+ return l === 0 ? a2 : { x: a2.x / l, y: a2.y / l };
16
+ };
17
+ var lerp = (a2, b, t) => ({
18
+ x: a2.x + (b.x - a2.x) * t,
19
+ y: a2.y + (b.y - a2.y) * t
20
+ });
21
+ var mid = (a2, b) => lerp(a2, b, 0.5);
22
+ var angle = (a2) => Math.atan2(a2.y, a2.x);
23
+ var rot = (a2, angle2) => {
24
+ const c2 = Math.cos(angle2);
25
+ const s = Math.sin(angle2);
26
+ return { x: a2.x * c2 - a2.y * s, y: a2.x * s + a2.y * c2 };
27
+ };
28
+ var rotAround = (p2, center, angle2) => add(center, rot(sub(p2, center), angle2));
29
+ var perp = (a2) => ({ x: -a2.y, y: a2.x });
30
+ var fromAngle = (angle2) => ({
31
+ x: Math.cos(angle2),
32
+ y: Math.sin(angle2)
33
+ });
34
+ var normAngle = (angle2) => {
35
+ const t = angle2 % (Math.PI * 2);
36
+ return t < 0 ? t + Math.PI * 2 : t;
37
+ };
38
+
39
+ // ../core/src/paint/painters/arrows.ts
40
+ var arrowLineStart = (tip, toward, size, type = "filled") => type === "filled" ? add(tip, scale(norm(sub(toward, tip)), Math.min(size, dist(tip, toward)))) : tip;
41
+ var paintArrowhead = (sink, tip, toward, size, color, type = "filled", opacity) => {
42
+ if (type === "none") return;
43
+ const dir = norm(sub(toward, tip));
44
+ if (dir.x === 0 && dir.y === 0) return;
45
+ switch (type) {
46
+ case "filled": {
47
+ const base = add(tip, scale(dir, size));
48
+ const half = scale(perp(dir), size / 3);
49
+ sink.beginPath();
50
+ sink.moveTo(tip);
51
+ sink.lineTo(add(base, half));
52
+ sink.lineTo(sub(base, half));
53
+ sink.closePath();
54
+ sink.fill({ color, opacity });
55
+ break;
56
+ }
57
+ case "open": {
58
+ const base = add(tip, scale(dir, size));
59
+ const half = scale(perp(dir), size / 3);
60
+ sink.beginPath();
61
+ sink.moveTo(add(base, half));
62
+ sink.lineTo(tip);
63
+ sink.lineTo(sub(base, half));
64
+ sink.stroke({ color, widthMm: Math.min(size / 10, 0.25), opacity });
65
+ break;
66
+ }
67
+ case "tick": {
68
+ const diag = scale(norm(add(dir, perp(dir))), size / 2);
69
+ sink.beginPath();
70
+ sink.moveTo(sub(tip, diag));
71
+ sink.lineTo(add(tip, diag));
72
+ sink.stroke({ color, widthMm: Math.min(size / 8, 0.35), opacity });
73
+ break;
74
+ }
75
+ case "dot": {
76
+ sink.beginPath();
77
+ sink.arc(tip, size / 4, 0, Math.PI * 2, true);
78
+ sink.fill({ color, opacity });
79
+ break;
80
+ }
81
+ }
82
+ };
83
+
84
+ // ../core/src/geometry/nurbs.ts
85
+ var nurbsDomain = (c2) => {
86
+ const n = c2.controlPoints.length;
87
+ return [c2.knots[c2.degree], c2.knots[n]];
88
+ };
89
+ var findSpan = (c2, u5) => {
90
+ const n = c2.controlPoints.length;
91
+ const p2 = c2.degree;
92
+ if (u5 >= c2.knots[n]) return n - 1;
93
+ if (u5 <= c2.knots[p2]) return p2;
94
+ let lo = p2;
95
+ let hi = n;
96
+ let mid2 = lo + hi >> 1;
97
+ while (u5 < c2.knots[mid2] || u5 >= c2.knots[mid2 + 1]) {
98
+ if (u5 < c2.knots[mid2]) hi = mid2;
99
+ else lo = mid2;
100
+ mid2 = lo + hi >> 1;
101
+ }
102
+ return mid2;
103
+ };
104
+ var evaluateNurbs = (c2, u5) => {
105
+ const p2 = c2.degree;
106
+ const k2 = findSpan(c2, u5);
107
+ const d2 = [];
108
+ for (let j = 0; j <= p2; j++) {
109
+ const i = k2 - p2 + j;
110
+ const cp = c2.controlPoints[i];
111
+ const w3 = c2.weights?.[i] ?? 1;
112
+ d2.push([cp.x * w3, cp.y * w3, w3]);
113
+ }
114
+ for (let r = 1; r <= p2; r++)
115
+ for (let j = p2; j >= r; j--) {
116
+ const i = k2 - p2 + j;
117
+ const den = c2.knots[i + p2 - r + 1] - c2.knots[i];
118
+ const a2 = den === 0 ? 0 : (u5 - c2.knots[i]) / den;
119
+ d2[j] = [
120
+ (1 - a2) * d2[j - 1][0] + a2 * d2[j][0],
121
+ (1 - a2) * d2[j - 1][1] + a2 * d2[j][1],
122
+ (1 - a2) * d2[j - 1][2] + a2 * d2[j][2]
123
+ ];
124
+ }
125
+ const [x2, y2, w2] = d2[p2];
126
+ return w2 === 0 ? { x: x2, y: y2 } : { x: x2 / w2, y: y2 / w2 };
127
+ };
128
+ var isValidNurbs = (c2) => c2.degree >= 1 && c2.controlPoints.length > c2.degree && c2.knots.length === c2.controlPoints.length + c2.degree + 1 && (c2.weights === void 0 || c2.weights.length === c2.controlPoints.length) && c2.knots.every((v2, i) => i === 0 || v2 >= c2.knots[i - 1]);
129
+ var sampleNurbs = (c2, tolerance, maxDepth = 10) => {
130
+ const [u0, u1] = nurbsDomain(c2);
131
+ const out = [evaluateNurbs(c2, u0)];
132
+ const push = (q) => {
133
+ const last = out[out.length - 1];
134
+ if (Math.hypot(q.x - last.x, q.y - last.y) > 1e-9) out.push(q);
135
+ };
136
+ const refine = (a2, pa, b, pb, depth) => {
137
+ const m2 = (a2 + b) / 2;
138
+ const pm = evaluateNurbs(c2, m2);
139
+ const chord = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };
140
+ const dev = Math.hypot(pm.x - chord.x, pm.y - chord.y);
141
+ if (depth >= maxDepth || dev <= tolerance) {
142
+ if (dev > tolerance / 4) push(pm);
143
+ push(pb);
144
+ return;
145
+ }
146
+ refine(a2, pa, m2, pm, depth + 1);
147
+ refine(m2, pm, b, pb, depth + 1);
148
+ };
149
+ const spans = [];
150
+ for (let i = c2.degree; i < c2.controlPoints.length; i++) {
151
+ const a2 = Math.max(c2.knots[i], u0);
152
+ const b = Math.min(c2.knots[i + 1], u1);
153
+ if (b > a2) spans.push(a2, b);
154
+ }
155
+ for (let i = 0; i < spans.length; i += 2) {
156
+ const a2 = spans[i];
157
+ const b = spans[i + 1];
158
+ const pa = evaluateNurbs(c2, a2);
159
+ const pb = evaluateNurbs(c2, b);
160
+ const m2 = (a2 + b) / 2;
161
+ const pm = evaluateNurbs(c2, m2);
162
+ refine(a2, pa, m2, pm, 1);
163
+ refine(m2, pm, b, pb, 1);
164
+ }
165
+ return dropCollinear(out, tolerance / 10);
166
+ };
167
+ var dropCollinear = (pts, eps) => {
168
+ if (pts.length < 3) return pts;
169
+ const out = [pts[0]];
170
+ for (let i = 1; i < pts.length - 1; i++) {
171
+ const a2 = out[out.length - 1];
172
+ const b = pts[i + 1];
173
+ const q = pts[i];
174
+ const abx = b.x - a2.x;
175
+ const aby = b.y - a2.y;
176
+ const len22 = abx * abx + aby * aby;
177
+ const t = len22 === 0 ? 0 : Math.max(
178
+ 0,
179
+ Math.min(1, ((q.x - a2.x) * abx + (q.y - a2.y) * aby) / len22)
180
+ );
181
+ const dist3 = Math.hypot(q.x - (a2.x + t * abx), q.y - (a2.y + t * aby));
182
+ if (dist3 > eps) out.push(q);
183
+ }
184
+ out.push(pts[pts.length - 1]);
185
+ return out;
186
+ };
187
+ var interpolateFitPoints = (input, degree = 3, tangents) => {
188
+ const points = input.filter(
189
+ (q, i) => i === 0 || Math.hypot(q.x - input[i - 1].x, q.y - input[i - 1].y) > 1e-9
190
+ );
191
+ const n = points.length;
192
+ if (n < 2) return null;
193
+ const p2 = Math.min(degree, n - 1);
194
+ const u5 = [0];
195
+ let total = 0;
196
+ for (let i = 1; i < n; i++) {
197
+ total += Math.hypot(
198
+ points[i].x - points[i - 1].x,
199
+ points[i].y - points[i - 1].y
200
+ );
201
+ u5.push(total);
202
+ }
203
+ if (total === 0) return null;
204
+ for (let i = 0; i < n; i++) u5[i] /= total;
205
+ if (degree >= 3 && (tangents?.start || tangents?.end))
206
+ return throughWithTangents(points, u5, total, tangents);
207
+ const knots = new Array(p2 + 1).fill(0);
208
+ for (let j = 1; j <= n - p2 - 1; j++) {
209
+ let s = 0;
210
+ for (let i = j; i <= j + p2 - 1; i++) s += u5[i];
211
+ knots.push(s / p2);
212
+ }
213
+ knots.push(...new Array(p2 + 1).fill(1));
214
+ return solveThrough(points, u5, knots, p2);
215
+ };
216
+ var solveThrough = (points, params, knots, p2) => {
217
+ const n = points.length;
218
+ if (params.length !== n || knots.length !== n + p2 + 1) return null;
219
+ const A = params.map((ui) => basisRow(knots, p2, n, ui));
220
+ const controlPoints = solveLinear(A, points);
221
+ return controlPoints ? { degree: p2, controlPoints, knots } : null;
222
+ };
223
+ var basisRow = (knots, p2, m2, u5) => {
224
+ const row = new Array(m2).fill(0);
225
+ for (let j = 0; j < m2; j++)
226
+ row[j] = evaluateNurbs(
227
+ {
228
+ degree: p2,
229
+ controlPoints: Array.from({ length: m2 }, (_2, k2) => ({
230
+ x: k2 === j ? 1 : 0,
231
+ y: 0
232
+ })),
233
+ knots
234
+ },
235
+ u5
236
+ ).x;
237
+ return row;
238
+ };
239
+ var solveLinear = (A0, B2) => {
240
+ const n = B2.length;
241
+ const A = A0.map((r) => [...r]);
242
+ const bx = B2.map((q) => q.x);
243
+ const by = B2.map((q) => q.y);
244
+ for (let col = 0; col < n; col++) {
245
+ let pivot = col;
246
+ for (let r = col + 1; r < n; r++)
247
+ if (Math.abs(A[r][col]) > Math.abs(A[pivot][col])) pivot = r;
248
+ if (Math.abs(A[pivot][col]) < 1e-12) return null;
249
+ [A[col], A[pivot]] = [A[pivot], A[col]];
250
+ [bx[col], bx[pivot]] = [bx[pivot], bx[col]];
251
+ [by[col], by[pivot]] = [by[pivot], by[col]];
252
+ for (let r = 0; r < n; r++) {
253
+ if (r === col) continue;
254
+ const k2 = A[r][col] / A[col][col];
255
+ if (k2 === 0) continue;
256
+ for (let c2 = col; c2 < n; c2++) A[r][c2] -= k2 * A[col][c2];
257
+ bx[r] -= k2 * bx[col];
258
+ by[r] -= k2 * by[col];
259
+ }
260
+ }
261
+ return bx.map((x2, i) => ({ x: x2 / A[i][i], y: by[i] / A[i][i] }));
262
+ };
263
+ var unit = (v2) => {
264
+ const l = Math.hypot(v2.x, v2.y);
265
+ return l === 0 ? { x: 1, y: 0 } : { x: v2.x / l, y: v2.y / l };
266
+ };
267
+ var throughWithTangents = (points, u5, total, tangents) => {
268
+ const n = points.length;
269
+ const p2 = 3;
270
+ const m2 = n + 2;
271
+ const knots = [0, 0, 0, 0, ...u5.slice(1, n - 1), 1, 1, 1, 1];
272
+ const free = interpolateFitPoints(points);
273
+ const dir = (given, at) => unit(
274
+ given ?? (free ? nurbsTangent(free, at) : { x: points[1].x - points[0].x, y: points[1].y - points[0].y })
275
+ );
276
+ const d0 = dir(tangents.start, 0);
277
+ const d1 = dir(tangents.end, 1);
278
+ const derivRow = (a2, b, k2) => {
279
+ const r = new Array(m2).fill(0);
280
+ r[a2] = -k2;
281
+ r[b] = k2;
282
+ return r;
283
+ };
284
+ const rows = [
285
+ basisRow(knots, p2, m2, 0),
286
+ derivRow(0, 1, p2 / knots[p2 + 1])
287
+ ];
288
+ const rhs = [points[0], { x: d0.x * total, y: d0.y * total }];
289
+ for (let i = 1; i < n - 1; i++) {
290
+ rows.push(basisRow(knots, p2, m2, u5[i]));
291
+ rhs.push(points[i]);
292
+ }
293
+ rows.push(
294
+ derivRow(m2 - 2, m2 - 1, p2 / (1 - knots[m2 - 1])),
295
+ basisRow(knots, p2, m2, 1)
296
+ );
297
+ rhs.push({ x: d1.x * total, y: d1.y * total }, points[n - 1]);
298
+ const controlPoints = solveLinear(rows, rhs);
299
+ return controlPoints ? { degree: p2, controlPoints, knots } : null;
300
+ };
301
+ var interpolateClosed = (input, degree = 3) => {
302
+ const near = (a2, b) => Math.hypot(a2.x - b.x, a2.y - b.y) <= 1e-9;
303
+ let points = input.filter((q, i) => i === 0 || !near(q, input[i - 1]));
304
+ if (points.length > 1 && near(points[0], points[points.length - 1]))
305
+ points = points.slice(0, -1);
306
+ const n = points.length;
307
+ if (n < 3) return null;
308
+ const p2 = Math.min(degree, n - 1);
309
+ const u5 = [0];
310
+ let total = 0;
311
+ for (let i = 1; i <= n; i++) {
312
+ total += Math.hypot(
313
+ points[i % n].x - points[i - 1].x,
314
+ points[i % n].y - points[i - 1].y
315
+ );
316
+ u5.push(total);
317
+ }
318
+ for (let i = 0; i <= n; i++) u5[i] /= total;
319
+ const knots = periodicKnots(u5, p2);
320
+ const m2 = n + p2;
321
+ const A = u5.slice(0, n).map((ui) => {
322
+ const full = basisRow(knots, p2, m2, ui);
323
+ const row = new Array(n).fill(0);
324
+ full.forEach((v2, j) => row[j % n] += v2);
325
+ return row;
326
+ });
327
+ const P = solveLinear(A, points);
328
+ if (!P) return null;
329
+ return { degree: p2, controlPoints: [...P, ...P.slice(0, p2)], knots };
330
+ };
331
+ var periodicKnots = (u5, p2) => {
332
+ const n = u5.length - 1;
333
+ const period = u5[n] - u5[0];
334
+ const t = new Array(n + 2 * p2 + 1);
335
+ for (let k2 = 0; k2 <= n; k2++) t[p2 + k2] = u5[k2];
336
+ for (let i = p2 - 1; i >= 0; i--) t[i] = t[i + n] - period;
337
+ for (let i = n + p2 + 1; i < t.length; i++) t[i] = t[i - n] + period;
338
+ return t;
339
+ };
340
+ var insertKnot = (c2, u5) => {
341
+ const p2 = c2.degree;
342
+ const n = c2.controlPoints.length;
343
+ let k2 = p2;
344
+ while (k2 < n - 1 && c2.knots[k2 + 1] <= u5) k2++;
345
+ const w2 = (i) => c2.weights?.[i] ?? 1;
346
+ const cps = [];
347
+ const ws = [];
348
+ for (let i = 0; i <= n; i++) {
349
+ if (i <= k2 - p2) {
350
+ cps.push(c2.controlPoints[i]);
351
+ ws.push(w2(i));
352
+ } else if (i > k2) {
353
+ cps.push(c2.controlPoints[i - 1]);
354
+ ws.push(w2(i - 1));
355
+ } else {
356
+ const den = c2.knots[i + p2] - c2.knots[i];
357
+ const a2 = den === 0 ? 0 : (u5 - c2.knots[i]) / den;
358
+ const w0 = w2(i - 1);
359
+ const w1 = w2(i);
360
+ const wn = (1 - a2) * w0 + a2 * w1;
361
+ const P0 = c2.controlPoints[i - 1];
362
+ const P1 = c2.controlPoints[i];
363
+ cps.push({
364
+ x: ((1 - a2) * P0.x * w0 + a2 * P1.x * w1) / wn,
365
+ y: ((1 - a2) * P0.y * w0 + a2 * P1.y * w1) / wn
366
+ });
367
+ ws.push(wn);
368
+ }
369
+ }
370
+ const knots = [...c2.knots.slice(0, k2 + 1), u5, ...c2.knots.slice(k2 + 1)];
371
+ return {
372
+ degree: p2,
373
+ controlPoints: cps,
374
+ knots,
375
+ ...c2.weights ? { weights: ws } : {}
376
+ };
377
+ };
378
+ var nurbsClamped = (c2) => {
379
+ const p2 = c2.degree;
380
+ const k2 = c2.knots;
381
+ for (let i = 1; i <= p2; i++)
382
+ if (k2[i] !== k2[0] || k2[k2.length - 1 - i] !== k2[k2.length - 1]) return false;
383
+ return true;
384
+ };
385
+ var nurbsToBeziers = (c0) => {
386
+ const p2 = c0.degree;
387
+ if (p2 < 1 || p2 > 3 || !isValidNurbs(c0)) return null;
388
+ const c2 = nurbsClamped(c0) ? c0 : nurbsSegment(c0, ...nurbsDomain(c0));
389
+ if (c2.weights?.some((w2) => w2 !== c2.weights[0])) return null;
390
+ let cur = { ...c2, weights: void 0 };
391
+ const [u0, u1] = nurbsDomain(c2);
392
+ const interior = [...new Set(c2.knots)].filter((v2) => v2 > u0 && v2 < u1);
393
+ for (const v2 of interior) {
394
+ let m2 = cur.knots.filter((k2) => k2 === v2).length;
395
+ if (m2 > p2) return null;
396
+ while (m2 < p2) {
397
+ cur = insertKnot(cur, v2);
398
+ m2++;
399
+ }
400
+ }
401
+ const P = cur.controlPoints;
402
+ const lerp2 = (a2, b, t) => ({
403
+ x: a2.x + (b.x - a2.x) * t,
404
+ y: a2.y + (b.y - a2.y) * t
405
+ });
406
+ const out = [];
407
+ for (let i = 0; i + p2 < P.length; i += p2) {
408
+ const q = P.slice(i, i + p2 + 1);
409
+ if (p2 === 3) out.push({ start: q[0], c1: q[1], c2: q[2], end: q[3] });
410
+ else if (p2 === 2)
411
+ out.push({
412
+ start: q[0],
413
+ c1: lerp2(q[0], q[1], 2 / 3),
414
+ c2: lerp2(q[2], q[1], 2 / 3),
415
+ end: q[2]
416
+ });
417
+ else
418
+ out.push({
419
+ start: q[0],
420
+ c1: lerp2(q[0], q[1], 1 / 3),
421
+ c2: lerp2(q[0], q[1], 2 / 3),
422
+ end: q[1]
423
+ });
424
+ }
425
+ return out;
426
+ };
427
+ var nurbsBounds = (c2) => {
428
+ let minX = Infinity;
429
+ let minY = Infinity;
430
+ let maxX = -Infinity;
431
+ let maxY = -Infinity;
432
+ for (const q of c2.controlPoints) {
433
+ minX = Math.min(minX, q.x);
434
+ minY = Math.min(minY, q.y);
435
+ maxX = Math.max(maxX, q.x);
436
+ maxY = Math.max(maxY, q.y);
437
+ }
438
+ return { minX, minY, maxX, maxY };
439
+ };
440
+ var curveTolerance = (c2) => {
441
+ const b = nurbsBounds(c2);
442
+ return Math.max(1e-3, Math.hypot(b.maxX - b.minX, b.maxY - b.minY) / 2e3);
443
+ };
444
+ var multiplicity = (c2, u5) => c2.knots.filter((k2) => k2 === u5).length;
445
+ var raiseKnot = (c2, u5, m2) => {
446
+ let cur = c2;
447
+ for (let k2 = multiplicity(cur, u5); k2 < Math.min(m2, c2.degree + 1); k2++)
448
+ cur = insertKnot(cur, u5);
449
+ return cur;
450
+ };
451
+ var nurbsSegment = (c2, a2, b) => {
452
+ const p2 = c2.degree;
453
+ const cur = raiseKnot(raiseKnot(c2, a2, p2), b, p2);
454
+ const k2 = cur.knots;
455
+ const sA = k2.indexOf(a2);
456
+ const j0 = sA + multiplicity(cur, a2) - p2 - 1;
457
+ const j1 = k2.indexOf(b) - 1;
458
+ const inner = k2.filter((v2) => v2 > a2 && v2 < b);
459
+ return {
460
+ degree: p2,
461
+ controlPoints: cur.controlPoints.slice(j0, j1 + 1),
462
+ knots: [...new Array(p2 + 1).fill(a2), ...inner, ...new Array(p2 + 1).fill(b)],
463
+ ...cur.weights ? { weights: cur.weights.slice(j0, j1 + 1) } : {}
464
+ };
465
+ };
466
+ var nurbsTangent = (c2, u5) => {
467
+ const [u0, u1] = nurbsDomain(c2);
468
+ const h = (u1 - u0) * 1e-6;
469
+ const a2 = evaluateNurbs(c2, Math.max(u0, u5 - h));
470
+ const b = evaluateNurbs(c2, Math.min(u1, u5 + h));
471
+ const l = Math.hypot(b.x - a2.x, b.y - a2.y);
472
+ return l === 0 ? { x: 1, y: 0 } : { x: (b.x - a2.x) / l, y: (b.y - a2.y) / l };
473
+ };
474
+
475
+ // ../core/src/geometry/arcs.ts
476
+ var arcSweep = (a2) => {
477
+ const s = normAngle(a2.endAngle - a2.startAngle);
478
+ return s === 0 ? Math.PI * 2 : s;
479
+ };
480
+ var pointOnArc = (a2, angle2) => ({
481
+ x: a2.center.x + Math.cos(angle2) * a2.radius,
482
+ y: a2.center.y + Math.sin(angle2) * a2.radius
483
+ });
484
+ var arcStartPoint = (a2) => pointOnArc(a2, a2.startAngle);
485
+ var arcEndPoint = (a2) => pointOnArc(a2, a2.endAngle);
486
+ var arcMidPoint = (a2) => pointOnArc(a2, a2.startAngle + arcSweep(a2) / 2);
487
+ var angleInArc = (a2, angle2) => normAngle(angle2 - a2.startAngle) <= arcSweep(a2) + 1e-12;
488
+ var bulgeToArc = (a2, b, bulge) => {
489
+ if (Math.abs(bulge) < 1e-12) return null;
490
+ const chord = dist(a2, b);
491
+ if (chord < 1e-12) return null;
492
+ const sweep = 4 * Math.atan(bulge);
493
+ const radius = Math.abs(chord / (2 * Math.sin(sweep / 2)));
494
+ const m2 = mid(a2, b);
495
+ const dir = scale(sub(b, a2), 1 / chord);
496
+ const h = chord / 2 / Math.tan(sweep / 2);
497
+ const center = add(m2, scale(perp(dir), h));
498
+ const angA = angle(sub(a2, center));
499
+ const angB = angle(sub(b, center));
500
+ return bulge > 0 ? { center, radius, startAngle: angA, endAngle: angB } : { center, radius, startAngle: angB, endAngle: angA };
501
+ };
502
+ var bulgeFrom3Points = (a2, m2, b) => {
503
+ let turn = angle(sub(b, m2)) - angle(sub(m2, a2));
504
+ while (turn > Math.PI) turn -= 2 * Math.PI;
505
+ while (turn < -Math.PI) turn += 2 * Math.PI;
506
+ return Math.tan(turn / 2);
507
+ };
508
+ var circleFrom3Points = (p1, p2, p3) => {
509
+ const ax = p1.x;
510
+ const ay = p1.y;
511
+ const bx = p2.x;
512
+ const by = p2.y;
513
+ const cx = p3.x;
514
+ const cy = p3.y;
515
+ const d2 = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
516
+ if (Math.abs(d2) < 1e-12) return null;
517
+ const a2 = ax * ax + ay * ay;
518
+ const b2 = bx * bx + by * by;
519
+ const c2 = cx * cx + cy * cy;
520
+ const center = {
521
+ x: (a2 * (by - cy) + b2 * (cy - ay) + c2 * (ay - by)) / d2,
522
+ y: (a2 * (cx - bx) + b2 * (ax - cx) + c2 * (bx - ax)) / d2
523
+ };
524
+ return { center, radius: dist(center, p1) };
525
+ };
526
+ var arcFrom3Points = (start, on, end) => {
527
+ const c2 = circleFrom3Points(start, on, end);
528
+ if (!c2) return null;
529
+ const angS = angle(sub(start, c2.center));
530
+ const angO = angle(sub(on, c2.center));
531
+ const angE = angle(sub(end, c2.center));
532
+ const ccw = {
533
+ center: c2.center,
534
+ radius: c2.radius,
535
+ startAngle: angS,
536
+ endAngle: angE
537
+ };
538
+ if (angleInArc(ccw, angO)) return ccw;
539
+ return {
540
+ center: c2.center,
541
+ radius: c2.radius,
542
+ startAngle: angE,
543
+ endAngle: angS
544
+ };
545
+ };
546
+ var closestPointOnArc = (a2, p2) => {
547
+ const v2 = sub(p2, a2.center);
548
+ const ang = angle(v2);
549
+ if (angleInArc(a2, ang)) return pointOnArc(a2, ang);
550
+ const s = arcStartPoint(a2);
551
+ const e = arcEndPoint(a2);
552
+ return dist(p2, s) <= dist(p2, e) ? s : e;
553
+ };
554
+ var distToArc = (a2, p2) => dist(p2, closestPointOnArc(a2, p2));
555
+ var tessellateArc = (a2, chordTolerance = 0.1) => {
556
+ const sweep = arcSweep(a2);
557
+ const maxStep = a2.radius <= chordTolerance ? sweep : 2 * Math.acos(Math.max(-1, 1 - chordTolerance / a2.radius));
558
+ const n = Math.max(2, Math.ceil(sweep / Math.max(maxStep, 1e-3)));
559
+ const pts = [];
560
+ for (let i = 0; i <= n; i++) {
561
+ pts.push(pointOnArc(a2, a2.startAngle + sweep * i / n));
562
+ }
563
+ return pts;
564
+ };
565
+
566
+ // ../core/src/geometry/hatchLoop.ts
567
+ var TAU = Math.PI * 2;
568
+ var sweepOf = (start, end) => {
569
+ const s = ((end - start) % TAU + TAU) % TAU;
570
+ return s < 1e-12 ? TAU : s;
571
+ };
572
+ var ellipsePoint = (e, t) => {
573
+ const minor = { x: -e.majorAxis.y * e.ratio, y: e.majorAxis.x * e.ratio };
574
+ return {
575
+ x: e.center.x + e.majorAxis.x * Math.cos(t) + minor.x * Math.sin(t),
576
+ y: e.center.y + e.majorAxis.y * Math.cos(t) + minor.y * Math.sin(t)
577
+ };
578
+ };
579
+ var stepsFor = (r, sweep, tolerance) => {
580
+ if (r <= tolerance) return Math.max(2, Math.ceil(sweep / (Math.PI / 4)));
581
+ const step = 2 * Math.acos(Math.max(-1, 1 - tolerance / r));
582
+ return Math.max(2, Math.ceil(sweep / Math.max(step, 1e-3)));
583
+ };
584
+ var edgePoints = (edge, tolerance = 0.1) => {
585
+ switch (edge.kind) {
586
+ case "line":
587
+ return [edge.a, edge.b];
588
+ case "arc": {
589
+ const sweep = sweepOf(edge.startAngle, edge.endAngle);
590
+ const n = stepsFor(edge.radius, sweep, tolerance);
591
+ return Array.from({ length: n + 1 }, (_2, i) => {
592
+ const t = edge.startAngle + sweep * i / n;
593
+ return {
594
+ x: edge.center.x + edge.radius * Math.cos(t),
595
+ y: edge.center.y + edge.radius * Math.sin(t)
596
+ };
597
+ });
598
+ }
599
+ case "ellipse": {
600
+ const sweep = sweepOf(edge.startAngle, edge.endAngle);
601
+ const r = Math.hypot(edge.majorAxis.x, edge.majorAxis.y);
602
+ const n = stepsFor(r, sweep, tolerance);
603
+ return Array.from(
604
+ { length: n + 1 },
605
+ (_2, i) => ellipsePoint(edge, edge.startAngle + sweep * i / n)
606
+ );
607
+ }
608
+ case "spline":
609
+ return sampleNurbs(edge, Math.min(tolerance, curveTolerance(edge)));
610
+ }
611
+ };
612
+ var edgeEnds = (edge) => {
613
+ switch (edge.kind) {
614
+ case "line":
615
+ return { start: edge.a, end: edge.b };
616
+ case "arc": {
617
+ const at = (t) => ({
618
+ x: edge.center.x + edge.radius * Math.cos(t),
619
+ y: edge.center.y + edge.radius * Math.sin(t)
620
+ });
621
+ return { start: at(edge.startAngle), end: at(edge.endAngle) };
622
+ }
623
+ case "ellipse":
624
+ return {
625
+ start: ellipsePoint(edge, edge.startAngle),
626
+ end: ellipsePoint(edge, edge.endAngle)
627
+ };
628
+ case "spline": {
629
+ const [u0, u1] = nurbsDomain(edge);
630
+ return { start: evaluateNurbs(edge, u0), end: evaluateNurbs(edge, u1) };
631
+ }
632
+ }
633
+ };
634
+ var chainEdges = (loop) => {
635
+ const out = [];
636
+ const edges = loop.edges;
637
+ if (edges.length === 0) return out;
638
+ let reversed = false;
639
+ if (edges.length > 1) {
640
+ const e0 = edgeEnds(edges[0]);
641
+ const e1 = edgeEnds(edges[1]);
642
+ const toNext = (p2) => Math.min(dist(p2, e1.start), dist(p2, e1.end));
643
+ reversed = toNext(e0.start) < toNext(e0.end);
644
+ }
645
+ out.push({ edge: edges[0], reversed });
646
+ let at = reversed ? edgeEnds(edges[0]).start : edgeEnds(edges[0]).end;
647
+ for (let i = 1; i < edges.length; i++) {
648
+ const { start, end } = edgeEnds(edges[i]);
649
+ const rev = dist(at, end) < dist(at, start);
650
+ out.push({ edge: edges[i], reversed: rev });
651
+ at = rev ? start : end;
652
+ }
653
+ return out;
654
+ };
655
+ var loopPolygon = (loop, tolerance = 0.1) => {
656
+ const ring = [];
657
+ for (const { edge, reversed } of chainEdges(loop)) {
658
+ const pts = edgePoints(edge, tolerance);
659
+ if (reversed) pts.reverse();
660
+ ring.push(...pts.slice(0, -1));
661
+ }
662
+ return ring;
663
+ };
664
+ var emitLoopPath = (sink, loop) => {
665
+ const chain = chainEdges(loop);
666
+ if (chain.length === 0) return;
667
+ const first = edgeEnds(chain[0].edge);
668
+ sink.moveTo(chain[0].reversed ? first.end : first.start);
669
+ for (const { edge, reversed } of chain) {
670
+ if (edge.kind === "line") {
671
+ sink.lineTo(reversed ? edge.a : edge.b);
672
+ continue;
673
+ }
674
+ if (edge.kind === "arc") {
675
+ const sweep = sweepOf(edge.startAngle, edge.endAngle);
676
+ if (reversed)
677
+ sink.arc(
678
+ edge.center,
679
+ edge.radius,
680
+ edge.startAngle + sweep,
681
+ edge.startAngle,
682
+ false
683
+ );
684
+ else
685
+ sink.arc(
686
+ edge.center,
687
+ edge.radius,
688
+ edge.startAngle,
689
+ edge.startAngle + sweep,
690
+ true
691
+ );
692
+ continue;
693
+ }
694
+ if (edge.kind === "spline") {
695
+ const pieces = nurbsToBeziers(edge);
696
+ if (pieces) {
697
+ if (reversed)
698
+ for (let i = pieces.length - 1; i >= 0; i--)
699
+ sink.bezierTo(pieces[i].c2, pieces[i].c1, pieces[i].start);
700
+ else for (const p2 of pieces) sink.bezierTo(p2.c1, p2.c2, p2.end);
701
+ continue;
702
+ }
703
+ }
704
+ const pts = edgePoints(edge, curveToleranceOf(edge));
705
+ if (reversed) pts.reverse();
706
+ for (const p2 of pts.slice(1)) sink.lineTo(p2);
707
+ }
708
+ sink.closePath();
709
+ };
710
+ var curveToleranceOf = (edge) => {
711
+ if (edge.kind === "spline") return curveTolerance(edge);
712
+ if (edge.kind === "ellipse")
713
+ return Math.max(
714
+ 1e-3,
715
+ Math.hypot(edge.majorAxis.x, edge.majorAxis.y) / 2e3
716
+ );
717
+ return 0.05;
718
+ };
719
+ var loopCurves = (loop) => {
720
+ const segments = [];
721
+ const arcs = [];
722
+ for (const edge of loop.edges) {
723
+ if (edge.kind === "line") segments.push({ a: edge.a, b: edge.b });
724
+ else if (edge.kind === "arc")
725
+ arcs.push({
726
+ center: edge.center,
727
+ radius: edge.radius,
728
+ startAngle: edge.startAngle,
729
+ endAngle: edge.startAngle + sweepOf(edge.startAngle, edge.endAngle) - 1e-9
730
+ });
731
+ else {
732
+ const pts = edgePoints(edge, 0.1);
733
+ for (let i = 1; i < pts.length; i++)
734
+ segments.push({ a: pts[i - 1], b: pts[i] });
735
+ }
736
+ }
737
+ return { segments, arcs };
738
+ };
739
+ var loopCorners = (loop) => chainEdges(loop).map(({ edge, reversed }) => {
740
+ const e = edgeEnds(edge);
741
+ return reversed ? e.end : e.start;
742
+ });
743
+ var ringArea = (ring) => {
744
+ let s = 0;
745
+ for (let i = 0; i < ring.length; i++) {
746
+ const p2 = ring[i];
747
+ const q = ring[(i + 1) % ring.length];
748
+ s += p2.x * q.y - q.x * p2.y;
749
+ }
750
+ return Math.abs(s) / 2;
751
+ };
752
+ var hatchArea = (loops) => {
753
+ const areas = loops.map((l) => ringArea(loopPolygon(l, 0.01)));
754
+ if (areas.length === 0) return 0;
755
+ const holes = areas.slice(1).reduce((a2, b) => a2 + b, 0);
756
+ return Math.max(areas[0] - holes, 0);
757
+ };
758
+ var verticesToLoop = (vertices) => {
759
+ const edges = [];
760
+ const n = vertices.length;
761
+ for (let i = 0; i < n; i++) {
762
+ const va = vertices[i];
763
+ const vb = vertices[(i + 1) % n];
764
+ const a2 = { x: va.x, y: va.y };
765
+ const b = { x: vb.x, y: vb.y };
766
+ if (dist(a2, b) < 1e-9) continue;
767
+ const arc = bulgeToArc(a2, b, va.bulge);
768
+ if (!arc) {
769
+ edges.push({ kind: "line", a: a2, b });
770
+ continue;
771
+ }
772
+ edges.push({
773
+ kind: "arc",
774
+ center: arc.center,
775
+ radius: arc.radius,
776
+ // CCW: a → b for a positive bulge, b → a for a negative one.
777
+ startAngle: va.bulge > 0 ? angle(sub(a2, arc.center)) : angle(sub(b, arc.center)),
778
+ endAngle: va.bulge > 0 ? angle(sub(b, arc.center)) : angle(sub(a2, arc.center))
779
+ });
780
+ }
781
+ return { edges };
782
+ };
783
+ var loopToVertices = (loop) => {
784
+ if (loop.edges.some((e) => e.kind === "ellipse" || e.kind === "spline"))
785
+ return null;
786
+ const out = [];
787
+ for (const { edge, reversed } of chainEdges(loop)) {
788
+ if (edge.kind === "line") {
789
+ const s = reversed ? edge.b : edge.a;
790
+ out.push({ x: s.x, y: s.y, bulge: 0 });
791
+ continue;
792
+ }
793
+ if (edge.kind !== "arc") return null;
794
+ const sweep = sweepOf(edge.startAngle, edge.endAngle);
795
+ const pieces = sweep > Math.PI + 1e-9 ? 2 : 1;
796
+ const step = sweep / pieces;
797
+ const bulge = Math.tan(step / 4) * (reversed ? -1 : 1);
798
+ for (let k2 = 0; k2 < pieces; k2++) {
799
+ const t = reversed ? edge.startAngle + sweep - step * k2 : edge.startAngle + step * k2;
800
+ out.push({
801
+ x: edge.center.x + edge.radius * Math.cos(t),
802
+ y: edge.center.y + edge.radius * Math.sin(t),
803
+ bulge
804
+ });
805
+ }
806
+ }
807
+ return out;
808
+ };
809
+
5
810
  // ../core/src/model/hatchPatterns.ts
6
811
  import { z as z2 } from "zod";
7
812
 
@@ -41,9 +846,9 @@ var matApply = (m2, p2) => ({
41
846
  y: m2[1] * p2.x + m2[3] * p2.y + m2[5]
42
847
  });
43
848
  var signedArcSweep = (startAngle, endAngle, ccw) => {
44
- const TAU = Math.PI * 2;
45
- let sweep = ccw ? ((endAngle - startAngle) % TAU + TAU) % TAU : -(((startAngle - endAngle) % TAU + TAU) % TAU);
46
- if (sweep === 0) sweep = ccw ? TAU : -TAU;
849
+ const TAU2 = Math.PI * 2;
850
+ let sweep = ccw ? ((endAngle - startAngle) % TAU2 + TAU2) % TAU2 : -(((startAngle - endAngle) % TAU2 + TAU2) % TAU2);
851
+ if (sweep === 0) sweep = ccw ? TAU2 : -TAU2;
47
852
  return sweep;
48
853
  };
49
854
  var arcToBeziers = (center, r, startAngle, sweep) => {
@@ -727,7 +1532,6 @@ import {
727
1532
  LWPolylineFlags,
728
1533
  TextHorizontalAlignment,
729
1534
  TextVerticalAlignment,
730
- HatchBoundaryPaths,
731
1535
  HatchPolylineBoundary,
732
1536
  HatchPredefinedPatterns,
733
1537
  pattern
@@ -954,12 +1758,7 @@ var StoredInputsSchema = z3.union([
954
1758
  z3.array(ValueSchema),
955
1759
  z3.record(
956
1760
  z3.string(),
957
- z3.union([
958
- Vec2Schema,
959
- z3.string(),
960
- z3.array(Vec2Schema),
961
- z3.array(z3.string())
962
- ])
1761
+ z3.union([Vec2Schema, z3.string(), z3.array(Vec2Schema), z3.array(z3.string())])
963
1762
  )
964
1763
  ]);
965
1764
  var isNamedInputs = (inputs) => !Array.isArray(inputs);
@@ -975,8 +1774,7 @@ var inputPoints = (inputs) => inputValues(inputs).filter((v2) => typeof v2 !== "
975
1774
  var inputRefs = (inputs) => inputValues(inputs).filter((v2) => typeof v2 === "string");
976
1775
  var mapInputValues = (inputs, fn2) => {
977
1776
  let i = 0;
978
- if (!isNamedInputs(inputs))
979
- return inputs.map((v2) => fn2(v2, i++));
1777
+ if (!isNamedInputs(inputs)) return inputs.map((v2) => fn2(v2, i++));
980
1778
  const out = {};
981
1779
  for (const [name, v2] of Object.entries(inputs))
982
1780
  out[name] = Array.isArray(v2) ? v2.map((x2) => fn2(x2, i++)) : fn2(v2, i++);
@@ -1023,8 +1821,73 @@ var EllipseSchema = ObjectBaseSchema.extend({
1023
1821
  startAngle: z4.number().default(0),
1024
1822
  endAngle: z4.number().default(Math.PI * 2)
1025
1823
  });
1824
+ var nurbsFields = {
1825
+ degree: z4.number().int().min(1).max(11),
1826
+ controlPoints: z4.array(Vec2Schema).min(2),
1827
+ knots: z4.array(z4.number()),
1828
+ weights: z4.array(z4.number().positive()).optional()
1829
+ };
1830
+ var refineNurbs = (s, ctx) => {
1831
+ const n = s.controlPoints.length;
1832
+ if (n <= s.degree)
1833
+ ctx.addIssue({
1834
+ code: "custom",
1835
+ path: ["controlPoints"],
1836
+ message: `a degree-${s.degree} spline needs more than ${s.degree} control points`
1837
+ });
1838
+ if (s.knots.length !== n + s.degree + 1)
1839
+ ctx.addIssue({
1840
+ code: "custom",
1841
+ path: ["knots"],
1842
+ message: `expected ${n + s.degree + 1} knots (control points + degree + 1)`
1843
+ });
1844
+ if (s.knots.some((k2, i) => i > 0 && k2 < s.knots[i - 1]))
1845
+ ctx.addIssue({
1846
+ code: "custom",
1847
+ path: ["knots"],
1848
+ message: "knots must be non-decreasing"
1849
+ });
1850
+ if (s.weights && s.weights.length !== n)
1851
+ ctx.addIssue({
1852
+ code: "custom",
1853
+ path: ["weights"],
1854
+ message: "one weight per control point"
1855
+ });
1856
+ };
1857
+ var SplineSchema = ObjectBaseSchema.extend({
1858
+ type: z4.literal("spline"),
1859
+ ...nurbsFields,
1860
+ fitPoints: z4.array(Vec2Schema).min(2).optional(),
1861
+ startTangent: Vec2Schema.optional(),
1862
+ endTangent: Vec2Schema.optional(),
1863
+ closed: z4.boolean().default(false)
1864
+ }).superRefine(refineNurbs);
1865
+ var HatchEdgeSchema = z4.discriminatedUnion("kind", [
1866
+ z4.object({ kind: z4.literal("line"), a: Vec2Schema, b: Vec2Schema }),
1867
+ z4.object({
1868
+ kind: z4.literal("arc"),
1869
+ center: Vec2Schema,
1870
+ radius: z4.number().positive(),
1871
+ startAngle: z4.number(),
1872
+ endAngle: z4.number()
1873
+ }),
1874
+ z4.object({
1875
+ kind: z4.literal("ellipse"),
1876
+ center: Vec2Schema,
1877
+ majorAxis: Vec2Schema,
1878
+ ratio: z4.number().gt(0).max(1),
1879
+ startAngle: z4.number().default(0),
1880
+ endAngle: z4.number().default(Math.PI * 2)
1881
+ }),
1882
+ z4.object({
1883
+ kind: z4.literal("spline"),
1884
+ ...nurbsFields,
1885
+ /** Drawn through points: those points (its grips), as on a spline. */
1886
+ fitPoints: z4.array(Vec2Schema).min(2).optional()
1887
+ }).superRefine(refineNurbs)
1888
+ ]);
1026
1889
  var HatchLoopSchema = z4.object({
1027
- points: z4.array(PolylineVertexSchema).min(3)
1890
+ edges: z4.array(HatchEdgeSchema).min(1)
1028
1891
  });
1029
1892
  var HatchFillSchema = z4.discriminatedUnion("kind", [
1030
1893
  z4.object({ kind: z4.literal("solid") }),
@@ -1409,11 +2272,7 @@ var TableShapeSchema = ObjectBaseSchema.extend({
1409
2272
  ),
1410
2273
  /** Row-major: `cells[row][column]`, exactly rows × columns. Input may
1411
2274
  * give a cell as a plain string (= `{ text }`). */
1412
- cells: z4.array(
1413
- z4.array(
1414
- z4.preprocess(cellInput, TableCellSchema)
1415
- )
1416
- ),
2275
+ cells: z4.array(z4.array(z4.preprocess(cellInput, TableCellSchema))),
1417
2276
  /** Rows above the heavier header rule. */
1418
2277
  headerRows: z4.number().int().min(0).default(0),
1419
2278
  /** Text inset from the cell edges (mm). */
@@ -1530,6 +2389,7 @@ var ModelObjectSchema = z4.discriminatedUnion("type", [
1530
2389
  CircleSchema,
1531
2390
  ArcSchema,
1532
2391
  EllipseSchema,
2392
+ SplineSchema,
1533
2393
  HatchSchema,
1534
2394
  TextSchema,
1535
2395
  DimensionSchema,
@@ -1702,11 +2562,11 @@ var normalizeName2 = (name) => name.trim().toUpperCase().replace(/[\s.-]+/g, "_"
1702
2562
  var asciiPreview = (dashesMm) => {
1703
2563
  const WIDTH = 15;
1704
2564
  if (!dashesMm.length) return "_".repeat(WIDTH * 0.8);
1705
- const unit = Math.max(1.5875, Math.max(...dashesMm.map(Math.abs)) / 5);
2565
+ const unit2 = Math.max(1.5875, Math.max(...dashesMm.map(Math.abs)) / 5);
1706
2566
  let out = "";
1707
2567
  while (out.length < WIDTH) {
1708
2568
  for (const d2 of dashesMm) {
1709
- const n = Math.max(1, Math.min(10, Math.round(Math.abs(d2) / unit)));
2569
+ const n = Math.max(1, Math.min(10, Math.round(Math.abs(d2) / unit2)));
1710
2570
  out += d2 > 0 ? "_".repeat(n) : d2 < 0 ? " ".repeat(n) : ".";
1711
2571
  if (out.length >= WIDTH) break;
1712
2572
  }
@@ -1774,40 +2634,6 @@ var resolveLineType = (name, lineTypes) => {
1774
2634
  return getLineType(name);
1775
2635
  };
1776
2636
 
1777
- // ../core/src/geometry/vec2.ts
1778
- var add = (a2, b) => ({ x: a2.x + b.x, y: a2.y + b.y });
1779
- var sub = (a2, b) => ({ x: a2.x - b.x, y: a2.y - b.y });
1780
- var scale = (a2, s) => ({ x: a2.x * s, y: a2.y * s });
1781
- var dot = (a2, b) => a2.x * b.x + a2.y * b.y;
1782
- var lenSq = (a2) => a2.x * a2.x + a2.y * a2.y;
1783
- var len = (a2) => Math.hypot(a2.x, a2.y);
1784
- var dist = (a2, b) => Math.hypot(b.x - a2.x, b.y - a2.y);
1785
- var norm = (a2) => {
1786
- const l = len(a2);
1787
- return l === 0 ? a2 : { x: a2.x / l, y: a2.y / l };
1788
- };
1789
- var lerp = (a2, b, t) => ({
1790
- x: a2.x + (b.x - a2.x) * t,
1791
- y: a2.y + (b.y - a2.y) * t
1792
- });
1793
- var mid = (a2, b) => lerp(a2, b, 0.5);
1794
- var angle = (a2) => Math.atan2(a2.y, a2.x);
1795
- var rot = (a2, angle2) => {
1796
- const c2 = Math.cos(angle2);
1797
- const s = Math.sin(angle2);
1798
- return { x: a2.x * c2 - a2.y * s, y: a2.x * s + a2.y * c2 };
1799
- };
1800
- var rotAround = (p2, center, angle2) => add(center, rot(sub(p2, center), angle2));
1801
- var perp = (a2) => ({ x: -a2.y, y: a2.x });
1802
- var fromAngle = (angle2) => ({
1803
- x: Math.cos(angle2),
1804
- y: Math.sin(angle2)
1805
- });
1806
- var normAngle = (angle2) => {
1807
- const t = angle2 % (Math.PI * 2);
1808
- return t < 0 ? t + Math.PI * 2 : t;
1809
- };
1810
-
1811
2637
  // ../core/src/extensions/paramLists.ts
1812
2638
  var NUMBER = /^[+-]?(\d+([.,]\d*)?|[.,]\d+)(e[+-]?\d+)?$/i;
1813
2639
  var REPEAT = /^(\d+)\*(.+)$/;
@@ -2059,6 +2885,7 @@ var OBJECT_TYPE_NAMES = [
2059
2885
  "circle",
2060
2886
  "arc",
2061
2887
  "ellipse",
2888
+ "spline",
2062
2889
  "hatch",
2063
2890
  "text",
2064
2891
  "dimension",
@@ -2193,16 +3020,21 @@ var mapObjectPoints = (obj, fn2) => {
2193
3020
  case "arc":
2194
3021
  case "ellipse":
2195
3022
  return { ...obj, center: fn2(obj.center) };
3023
+ case "spline":
3024
+ return {
3025
+ ...obj,
3026
+ controlPoints: obj.controlPoints.map(fn2),
3027
+ ...obj.fitPoints ? { fitPoints: obj.fitPoints.map(fn2) } : {}
3028
+ };
2196
3029
  case "hatch":
2197
3030
  return {
2198
3031
  ...obj,
2199
3032
  // The pattern frame moves with its region, as in AutoCAD — an
2200
3033
  // unanchored fill's frame is the drawing origin, which moves along
2201
3034
  // too (else the pattern would swim inside a moved hatch).
2202
- fill: obj.fill.kind === "pattern" ? { ...obj.fill, origin: fn2(obj.fill.origin ?? { x: 0, y: 0 }) } : obj.fill,
2203
- loops: obj.loops.map((loop) => ({
2204
- points: loop.points.map((v2) => ({ ...v2, ...fn2(v2) }))
2205
- }))
3035
+ // (Its boundary edges are transformed by each caller, as the
3036
+ // objects they are — see hatchEdgesVia.)
3037
+ fill: obj.fill.kind === "pattern" ? { ...obj.fill, origin: fn2(obj.fill.origin ?? { x: 0, y: 0 }) } : obj.fill
2206
3038
  };
2207
3039
  case "text":
2208
3040
  return {
@@ -2224,8 +3056,45 @@ var mapObjectPoints = (obj, fn2) => {
2224
3056
  return { ...obj, position: fn2(obj.position) };
2225
3057
  }
2226
3058
  };
3059
+ var EDGE_FIELDS = {
3060
+ line: ["a", "b"],
3061
+ arc: ["center", "radius", "startAngle", "endAngle"],
3062
+ ellipse: ["center", "majorAxis", "ratio", "startAngle", "endAngle"],
3063
+ spline: ["degree", "controlPoints", "knots", "weights", "fitPoints"]
3064
+ };
3065
+ var hatchEdgeAsObject = (edge) => {
3066
+ const { kind, ...geometry } = edge;
3067
+ const closed = kind === "spline" ? (() => {
3068
+ const { start, end } = edgeEnds(edge);
3069
+ return Math.hypot(start.x - end.x, start.y - end.y) < 1e-9;
3070
+ })() : void 0;
3071
+ return {
3072
+ ...geometry,
3073
+ type: kind,
3074
+ id: "",
3075
+ layerId: "",
3076
+ ...closed !== void 0 ? { closed } : {}
3077
+ };
3078
+ };
3079
+ var objectAsHatchEdge = (obj, kind) => {
3080
+ const source = obj;
3081
+ const out = { kind };
3082
+ for (const key of EDGE_FIELDS[kind])
3083
+ if (source[key] !== void 0) out[key] = source[key];
3084
+ return out;
3085
+ };
3086
+ var hatchEdgesVia = (hatch, transform) => ({
3087
+ ...hatch,
3088
+ loops: hatch.loops.map((loop) => ({
3089
+ edges: loop.edges.map(
3090
+ (edge) => objectAsHatchEdge(transform(hatchEdgeAsObject(edge)), edge.kind)
3091
+ )
3092
+ }))
3093
+ });
2227
3094
  var translateObject = (obj, delta) => {
2228
3095
  const mapped = mapObjectPoints(obj, (p2) => add(p2, delta));
3096
+ if (mapped.type === "hatch")
3097
+ return hatchEdgesVia(mapped, (o) => translateObject(o, delta));
2229
3098
  return mapped.type === "viewport" ? {
2230
3099
  ...mapped,
2231
3100
  rect: {
@@ -2268,11 +3137,15 @@ var rotateObject = (obj, center, ang) => {
2268
3137
  case "reference":
2269
3138
  return { ...mapped, rotation: normAngle(mapped.rotation + ang) };
2270
3139
  case "hatch":
2271
- return { ...mapped, fill: turnFill(mapped.fill, (a2) => a2 + ang) };
3140
+ return {
3141
+ ...hatchEdgesVia(mapped, (o) => rotateObject(o, center, ang)),
3142
+ fill: turnFill(mapped.fill, (a2) => a2 + ang)
3143
+ };
2272
3144
  case "line":
2273
3145
  case "point":
2274
3146
  case "polyline":
2275
3147
  case "circle":
3148
+ case "spline":
2276
3149
  case "comment":
2277
3150
  return mapped;
2278
3151
  default:
@@ -2290,7 +3163,7 @@ var scaleObjectUniform = (obj, s) => {
2290
3163
  return { ...mapped, majorAxis: m2(mapped.majorAxis) };
2291
3164
  case "hatch":
2292
3165
  return {
2293
- ...mapped,
3166
+ ...hatchEdgesVia(mapped, (o) => scaleObjectUniform(o, s)),
2294
3167
  fill: mapped.fill.kind === "lines" ? { ...mapped.fill, spacing: mapped.fill.spacing * s } : mapped.fill.kind === "pattern" ? { ...mapped.fill, scale: mapped.fill.scale * s } : mapped.fill
2295
3168
  };
2296
3169
  case "text":
@@ -2328,6 +3201,7 @@ var scaleObjectUniform = (obj, s) => {
2328
3201
  return mapped;
2329
3202
  case "line":
2330
3203
  case "polyline":
3204
+ case "spline":
2331
3205
  case "comment":
2332
3206
  return mapped;
2333
3207
  default:
@@ -2383,11 +3257,8 @@ var mirrorObject = (obj, a2, b) => {
2383
3257
  };
2384
3258
  case "hatch":
2385
3259
  return {
2386
- ...mapped,
2387
- fill: turnFill(mapped.fill, mirrorAngle),
2388
- loops: mapped.loops.map((loop) => ({
2389
- points: loop.points.map((v2) => ({ ...v2, bulge: -v2.bulge }))
2390
- }))
3260
+ ...hatchEdgesVia(mapped, (o) => mirrorObject(o, a2, b)),
3261
+ fill: turnFill(mapped.fill, mirrorAngle)
2391
3262
  };
2392
3263
  case "text": {
2393
3264
  const reflected = normAngle(mirrorAngle(mapped.rotation));
@@ -2417,6 +3288,7 @@ var mirrorObject = (obj, a2, b) => {
2417
3288
  case "line":
2418
3289
  case "point":
2419
3290
  case "circle":
3291
+ case "spline":
2420
3292
  case "comment":
2421
3293
  return mapped;
2422
3294
  // Mirrored above, before the point map.
@@ -2470,7 +3342,9 @@ var acquireInputTable = async (table, pickers, extras = {}) => {
2470
3342
  break;
2471
3343
  case "host": {
2472
3344
  if (!pickers.host)
2473
- throw new Error(`"${def.name}" needs a host block \u2014 pick it in the editor`);
3345
+ throw new Error(
3346
+ `"${def.name}" needs a host block \u2014 pick it in the editor`
3347
+ );
2474
3348
  const picked = await pickers.host(def);
2475
3349
  out[def.name] = picked.id;
2476
3350
  extras.hostPoint = picked.point;
@@ -2534,7 +3408,9 @@ var checkNamedInputs = (who, table, given, lookup) => {
2534
3408
  throw new Error(`${who}: input "${def.name}" \u2014 expected a block id`);
2535
3409
  const host = lookup?.(v2);
2536
3410
  if (lookup && host?.type !== "block")
2537
- throw new Error(`${who}: input "${def.name}" \u2014 no block with id ${v2}`);
3411
+ throw new Error(
3412
+ `${who}: input "${def.name}" \u2014 no block with id ${v2}`
3413
+ );
2538
3414
  if (host?.type === "block" && def.types.length > 0 && !def.types.includes(host.definitionId))
2539
3415
  throw new Error(
2540
3416
  `${who}: input "${def.name}" \u2014 a "${host.definitionId}" can't host this (takes ${def.types.join(", ")})`
@@ -2621,7 +3497,9 @@ var resolveNamedInputs = (table, stored, pivot, resolve) => {
2621
3497
  case "host":
2622
3498
  break;
2623
3499
  case "objects": {
2624
- const ids = Array.isArray(v2) ? v2.filter((id) => typeof id === "string") : [];
3500
+ const ids = Array.isArray(v2) ? v2.filter(
3501
+ (id) => typeof id === "string"
3502
+ ) : [];
2625
3503
  out[def.name] = ids.map(obj).filter((o) => o !== null);
2626
3504
  break;
2627
3505
  }
@@ -2743,7 +3621,7 @@ var PX_TO_MM = 25.4 / 96;
2743
3621
  var embeddedAssetId = (o) => o.type === "reference" && o.source?.kind === "asset" ? o.source.assetId : void 0;
2744
3622
 
2745
3623
  // ../core/src/model/migrations.ts
2746
- var CURRENT_DOCUMENT_VERSION = 24;
3624
+ var CURRENT_DOCUMENT_VERSION = 25;
2747
3625
  var leaderRawToText = (raw) => {
2748
3626
  const points = Array.isArray(raw.points) ? raw.points : [];
2749
3627
  const extraLines = Array.isArray(raw.extraLines) ? raw.extraLines : [];
@@ -3374,6 +4252,31 @@ var migrateV22toV23 = (doc) => {
3374
4252
  return { ...doc, objects: mapObjects(doc.objects), layouts, version: 23 };
3375
4253
  };
3376
4254
  var migrateV23toV24 = (doc) => ({ ...doc, version: 24 });
4255
+ var hatchRawPointsToEdges = (raw) => {
4256
+ if (!Array.isArray(raw.loops)) return raw;
4257
+ const vertex = (v2) => Array.isArray(v2) ? { x: Number(v2[0]), y: Number(v2[1]), bulge: Number(v2[2] ?? 0) } : {
4258
+ x: Number(v2.x),
4259
+ y: Number(v2.y),
4260
+ bulge: Number(v2.bulge ?? 0)
4261
+ };
4262
+ return {
4263
+ ...raw,
4264
+ loops: raw.loops.map(
4265
+ (loop) => loop !== null && typeof loop === "object" && Array.isArray(loop.points) ? verticesToLoop(loop.points.map(vertex)) : loop
4266
+ )
4267
+ };
4268
+ };
4269
+ var migrateV24toV25 = (doc) => {
4270
+ const mapObjects = (list) => Array.isArray(list) ? list.map(
4271
+ (raw) => raw !== null && typeof raw === "object" && raw.type === "hatch" ? hatchRawPointsToEdges(raw) : raw
4272
+ ) : list;
4273
+ const layouts = Array.isArray(doc.layouts) ? doc.layouts.map((raw) => {
4274
+ if (raw === null || typeof raw !== "object") return raw;
4275
+ const layout = raw;
4276
+ return { ...layout, objects: mapObjects(layout.objects) };
4277
+ }) : doc.layouts;
4278
+ return { ...doc, objects: mapObjects(doc.objects), layouts, version: 25 };
4279
+ };
3377
4280
  var MIGRATION_STEPS = [
3378
4281
  migrateV1toV2,
3379
4282
  migrateV2toV3,
@@ -3397,7 +4300,8 @@ var MIGRATION_STEPS = [
3397
4300
  migrateV20toV21,
3398
4301
  migrateV21toV22,
3399
4302
  migrateV22toV23,
3400
- migrateV23toV24
4303
+ migrateV23toV24,
4304
+ migrateV24toV25
3401
4305
  ];
3402
4306
  function migrateDocument(raw) {
3403
4307
  if (raw === null || typeof raw !== "object") return raw;
@@ -3437,6 +4341,7 @@ var BlockChildSchema = z7.preprocess(
3437
4341
  dimRawScaleToField(dimensionRawToOffset(obj))
3438
4342
  );
3439
4343
  if (obj.type === "text") return textRawStyleToOverride(obj);
4344
+ if (obj.type === "hatch") return hatchRawPointsToEdges(obj);
3440
4345
  return obj;
3441
4346
  },
3442
4347
  z7.discriminatedUnion("type", [
@@ -3545,10 +4450,12 @@ var RawHandleSchema = z8.strictObject({
3545
4450
  if (h.along && !h.along.origin) issue("`along` needs an `origin`");
3546
4451
  } else {
3547
4452
  if (!h.from || !h.to) issue("a line handle needs `from` and `to`");
3548
- if (h.around) issue("a line handle drags along a direction, not `around`");
4453
+ if (h.around)
4454
+ issue("a line handle drags along a direction, not `around`");
3549
4455
  if (h.input !== void 0) issue("a line handle can't move an `input`");
3550
4456
  }
3551
- if (behaviours > 1) issue("give a handle ONE of `param`, `input` or `drag`");
4457
+ if (behaviours > 1)
4458
+ issue("give a handle ONE of `param`, `input` or `drag`");
3552
4459
  if (h.along && h.around)
3553
4460
  issue("`along` and `around` are alternative constraints \u2014 pick one");
3554
4461
  if (!h.fixed && behaviours === 0 && !h.click && !h.menu?.length && !h.actions?.length)
@@ -3556,7 +4463,9 @@ var RawHandleSchema = z8.strictObject({
3556
4463
  "the handle does nothing \u2014 add `param`, `input`, `drag`, `click`, `menu` or `actions`, or mark it `fixed`"
3557
4464
  );
3558
4465
  if (h.kind === "point" && h.param !== void 0 && !h.along && !h.around)
3559
- issue("a `param` handle needs `along` or `around` (what value it measures)");
4466
+ issue(
4467
+ "a `param` handle needs `along` or `around` (what value it measures)"
4468
+ );
3560
4469
  if (h.along && Math.hypot(h.along.direction.x, h.along.direction.y) === 0)
3561
4470
  issue("`along.direction` is zero");
3562
4471
  });
@@ -5630,8 +6539,7 @@ var fromGeom = (multi) => multi.flatMap(
5630
6539
  (polygon) => polygon.map((ring) => {
5631
6540
  const pts = ring.map(([x2, y2]) => ({ x: x2, y: y2 }));
5632
6541
  const [first, last] = [pts[0], pts[pts.length - 1]];
5633
- if (pts.length > 1 && first.x === last.x && first.y === last.y)
5634
- pts.pop();
6542
+ if (pts.length > 1 && first.x === last.x && first.y === last.y) pts.pop();
5635
6543
  return pts;
5636
6544
  })
5637
6545
  );
@@ -5652,50 +6560,489 @@ var intersection2 = (...polygons) => {
5652
6560
  return fromGeom(index.intersection(gs[0], ...gs.slice(1)));
5653
6561
  };
5654
6562
 
6563
+ // ../core/src/extensions/scriptCurves.ts
6564
+ var scriptCurves_exports = {};
6565
+ __export(scriptCurves_exports, {
6566
+ hatchLoop: () => hatchLoop,
6567
+ splineThrough: () => splineThrough
6568
+ });
6569
+ var splineThrough = (points, degree = 3) => {
6570
+ const pts = points.map(
6571
+ (p2) => Array.isArray(p2) ? { x: p2[0], y: p2[1] } : { x: p2.x, y: p2.y }
6572
+ );
6573
+ const curve = interpolateFitPoints(pts, degree);
6574
+ if (!curve)
6575
+ throw new Error("splineThrough: needs at least two distinct points");
6576
+ return {
6577
+ type: "spline",
6578
+ degree: curve.degree,
6579
+ controlPoints: curve.controlPoints,
6580
+ knots: curve.knots,
6581
+ fitPoints: pts
6582
+ };
6583
+ };
6584
+ var hatchLoop = (points) => verticesToLoop(
6585
+ points.map(
6586
+ (p2) => Array.isArray(p2) ? {
6587
+ x: p2[0],
6588
+ y: p2[1],
6589
+ bulge: p2[2] ?? 0
6590
+ } : {
6591
+ x: p2.x,
6592
+ y: p2.y,
6593
+ bulge: p2.bulge ?? 0
6594
+ }
6595
+ )
6596
+ );
6597
+
6598
+ // ../core/src/extensions/sandbox.ts
6599
+ var COMMAND_BUDGET_MS = 5e3;
6600
+ var BLOCK_BUDGET_MS = 200;
6601
+ var MEMORY_LIMIT = 256 * 1024 * 1024;
6602
+ var STACK_LIMIT = 1024 * 1024;
6603
+ var HOST_FN = "\0fn";
6604
+ var HOST_OBJ = "\0obj";
6605
+ var VM_FN = "fn";
6606
+ var FROZEN = "\0frozen";
6607
+ var PRELUDE = String.raw`(() => {
6608
+ const host = globalThis.__host;
6609
+ delete globalThis.__host;
6610
+ const fns = new Map();
6611
+ let next = 0;
6612
+ const encode = (v) =>
6613
+ JSON.stringify([v], (k, x) => {
6614
+ if (typeof x !== "function") return x;
6615
+ fns.set(next, x);
6616
+ return { "\u0001fn": next++ };
6617
+ });
6618
+ const settle = (r) => (typeof r === "string" ? revive(r) : r.then(revive));
6619
+ const revive = (s) =>
6620
+ JSON.parse(s, (k, x) => {
6621
+ if (x !== null && typeof x === "object") {
6622
+ if ("\u0000frozen" in x) return Object.freeze(x["\u0000frozen"]);
6623
+ if ("\u0000fn" in x) {
6624
+ const id = x["\u0000fn"];
6625
+ return (...a) => settle(host.call(id, encode(a)));
6626
+ }
6627
+ if ("\u0000obj" in x) {
6628
+ const id = x["\u0000obj"];
6629
+ return new Proxy({}, {
6630
+ get: (_, p) => (typeof p === "string" ? revive(host.get(id, p)) : undefined),
6631
+ });
6632
+ }
6633
+ }
6634
+ return x;
6635
+ })[0];
6636
+ const out = (r) =>
6637
+ r !== null && typeof r === "object" && typeof r.then === "function"
6638
+ ? Promise.resolve(r).then(encode)
6639
+ : encode(r);
6640
+ return {
6641
+ call: (id, args, freed) => {
6642
+ for (const f of JSON.parse(freed)) fns.delete(f);
6643
+ return out(fns.get(id)(...revive(args)));
6644
+ },
6645
+ load: (code, helpersJson, localHelpers) => {
6646
+ // Pure helpers run here (a host call per vector op costs ~20 µs);
6647
+ // the heavy ones (booleans, curves) stay host calls.
6648
+ const helpers = Object.freeze({
6649
+ ...revive(helpersJson),
6650
+ ...new Function("return (" + localHelpers + ")")(),
6651
+ });
6652
+ const lineadraw = { helpers, defineBlock: (s) => s, defineCommand: (s) => s };
6653
+ const require = (spec) => {
6654
+ if (spec === "lineadraw/helpers" || spec === "linea/helpers") return helpers;
6655
+ if (spec === "lineadraw" || spec === "linea") return lineadraw;
6656
+ throw new Error('Cannot import "' + spec + '" — scripts may only import from "lineadraw" and "lineadraw/helpers"');
6657
+ };
6658
+ const module = { exports: {} };
6659
+ new Function("exports", "require", "module", code)(module.exports, require, module);
6660
+ return encode(module.exports);
6661
+ },
6662
+ };
6663
+ })()`;
6664
+ var wasm = null;
6665
+ var wasmLoading = null;
6666
+ var ensureSandbox = () => {
6667
+ if (wasm) return Promise.resolve(wasm);
6668
+ wasmLoading ??= Promise.all([
6669
+ import("./dist-56K6CNML.js"),
6670
+ import("./dist-IEN64QSV.js")
6671
+ ]).then(
6672
+ ([{ newQuickJSWASMModuleFromVariant }, variant]) => newQuickJSWASMModuleFromVariant(variant.default)
6673
+ ).then((m2) => {
6674
+ wasm = m2;
6675
+ return m2;
6676
+ });
6677
+ return wasmLoading;
6678
+ };
6679
+ var ScriptTimeoutError = class extends Error {
6680
+ code = "scriptTimeout";
6681
+ };
6682
+ var BUILTIN_ERRORS = {
6683
+ TypeError,
6684
+ RangeError,
6685
+ SyntaxError,
6686
+ ReferenceError
6687
+ };
6688
+ var isPlain = (x2) => {
6689
+ if (Array.isArray(x2)) return true;
6690
+ const p2 = Object.getPrototypeOf(x2);
6691
+ return p2 === Object.prototype || p2 === null;
6692
+ };
6693
+ var runtime = null;
6694
+ var live = /* @__PURE__ */ new Set();
6695
+ var resetListeners = /* @__PURE__ */ new Set();
6696
+ var stack = [];
6697
+ var deadline = 0;
6698
+ var entryBudget = 0;
6699
+ var interrupted = null;
6700
+ var resetPending = false;
6701
+ var getRuntime = () => {
6702
+ if (runtime) return runtime;
6703
+ if (!wasm) throw new Error("Script sandbox is still loading");
6704
+ const rt = wasm.newRuntime();
6705
+ rt.setMemoryLimit(MEMORY_LIMIT);
6706
+ rt.setMaxStackSize(STACK_LIMIT);
6707
+ rt.setInterruptHandler(() => {
6708
+ if (Date.now() <= deadline) return false;
6709
+ interrupted ??= stack[stack.length - 1] ?? null;
6710
+ return true;
6711
+ });
6712
+ runtime = rt;
6713
+ return rt;
6714
+ };
6715
+ var onSandboxReset = (cb) => {
6716
+ resetListeners.add(cb);
6717
+ return () => resetListeners.delete(cb);
6718
+ };
6719
+ var resetRuntime = () => {
6720
+ resetPending = false;
6721
+ for (const s of live) s.kill();
6722
+ live.clear();
6723
+ runtime?.dispose();
6724
+ runtime = null;
6725
+ for (const cb of resetListeners) cb();
6726
+ };
6727
+ var ModuleSandbox = class {
6728
+ ctx;
6729
+ bridge;
6730
+ hostFns = [];
6731
+ hostObjs = [];
6732
+ bound = /* @__PURE__ */ new Map();
6733
+ baseFns = 0;
6734
+ baseObjs = 0;
6735
+ loaded = false;
6736
+ /** VM function refs whose host callables were collected; sent along with
6737
+ * the next call so the VM drops them too. */
6738
+ vmFreed = [];
6739
+ vmFinalizer = new FinalizationRegistry(
6740
+ (id) => this.vmFreed.push(id)
6741
+ );
6742
+ depth = 0;
6743
+ pendingAsync = 0;
6744
+ poisoned = null;
6745
+ dead = false;
6746
+ disposeOnIdle = false;
6747
+ lastHostError = null;
6748
+ opts;
6749
+ constructor(opts) {
6750
+ this.opts = opts;
6751
+ this.ctx = getRuntime().newContext();
6752
+ live.add(this);
6753
+ const ctx = this.ctx;
6754
+ const host = ctx.newObject();
6755
+ const call = ctx.newFunction("call", (idH, argsH) => {
6756
+ const fn2 = this.hostFns[ctx.getNumber(idH)];
6757
+ let r;
6758
+ try {
6759
+ if (!fn2)
6760
+ throw new Error(
6761
+ "A host function was called after the call that handed it over ended"
6762
+ );
6763
+ r = fn2(...this.decode(ctx.getString(argsH))[0]);
6764
+ } catch (e) {
6765
+ this.lastHostError = e;
6766
+ throw e;
6767
+ }
6768
+ if (!(r instanceof Promise)) return ctx.newString(this.encode(r));
6769
+ const d2 = ctx.newPromise();
6770
+ r.then(
6771
+ (v2) => {
6772
+ if (this.dead) return;
6773
+ const s = ctx.newString(this.encode(v2));
6774
+ d2.resolve(s);
6775
+ s.dispose();
6776
+ },
6777
+ (e) => {
6778
+ if (this.dead) return;
6779
+ this.lastHostError = e;
6780
+ const eh = ctx.newError(e instanceof Error ? e.message : String(e));
6781
+ d2.reject(eh);
6782
+ eh.dispose();
6783
+ }
6784
+ ).finally(() => {
6785
+ if (this.dead) return;
6786
+ d2.dispose();
6787
+ this.drain();
6788
+ });
6789
+ return d2.handle.dup();
6790
+ });
6791
+ const get = ctx.newFunction("get", (idH, keyH) => {
6792
+ const id = ctx.getNumber(idH);
6793
+ const key = ctx.getString(keyH);
6794
+ const obj = this.hostObjs[id];
6795
+ if (!obj)
6796
+ throw new Error(
6797
+ "A host object was used after the call that handed it over ended"
6798
+ );
6799
+ const v2 = obj[key];
6800
+ if (typeof v2 !== "function") return ctx.newString(this.encode(v2));
6801
+ const k2 = `${id}:${key}`;
6802
+ let fnId = this.bound.get(k2);
6803
+ if (fnId === void 0) {
6804
+ fnId = this.hostFns.push(v2.bind(obj)) - 1;
6805
+ this.bound.set(k2, fnId);
6806
+ }
6807
+ return ctx.newString(JSON.stringify([{ [HOST_FN]: fnId }]));
6808
+ });
6809
+ ctx.setProp(host, "call", call);
6810
+ ctx.setProp(host, "get", get);
6811
+ ctx.setProp(ctx.global, "__host", host);
6812
+ call.dispose();
6813
+ get.dispose();
6814
+ host.dispose();
6815
+ this.bridge = this.enter(
6816
+ () => this.unwrap(ctx.evalCode(PRELUDE, "prelude.js"))
6817
+ );
6818
+ }
6819
+ /** Host value → JSON for the VM (functions/instances become refs). */
6820
+ encode(v2) {
6821
+ return JSON.stringify([v2], (_k, x2) => {
6822
+ if (typeof x2 === "function")
6823
+ return { [HOST_FN]: this.hostFns.push(x2) - 1 };
6824
+ if (x2 === null || typeof x2 !== "object") return x2;
6825
+ if (!isPlain(x2)) return { [HOST_OBJ]: this.hostObjs.push(x2) - 1 };
6826
+ if (Object.isFrozen(x2) && !(FROZEN in x2))
6827
+ return { [FROZEN]: Array.isArray(x2) ? [...x2] : { ...x2 } };
6828
+ return x2;
6829
+ });
6830
+ }
6831
+ /** VM JSON → host value (VM function refs become host callables). */
6832
+ decode(s) {
6833
+ return JSON.parse(
6834
+ s,
6835
+ (_k, x2) => x2 !== null && typeof x2 === "object" && VM_FN in x2 ? this.vmFunction(x2[VM_FN]) : x2
6836
+ );
6837
+ }
6838
+ /** Run `fn` as VM work. The outermost entry on the shared stack starts the
6839
+ * budget; nested entries (a script calling the host calling a script)
6840
+ * spend the same one. */
6841
+ enter(fn2) {
6842
+ if (this.dead)
6843
+ throw new Error(
6844
+ "This script's sandbox was reset; it re-compiles on next use"
6845
+ );
6846
+ if (this.poisoned) throw this.poisoned;
6847
+ if (stack.length === 0) {
6848
+ getRuntime();
6849
+ deadline = Date.now() + this.opts.budgetMs;
6850
+ entryBudget = this.opts.budgetMs;
6851
+ interrupted = null;
6852
+ }
6853
+ if (this.depth === 0) this.lastHostError = null;
6854
+ stack.push(this);
6855
+ this.depth++;
6856
+ try {
6857
+ return fn2();
6858
+ } finally {
6859
+ stack.pop();
6860
+ this.depth--;
6861
+ this.idle();
6862
+ if (stack.length === 0 && resetPending) resetRuntime();
6863
+ }
6864
+ }
6865
+ /** Nothing of this module running or awaited: drop the host refs its
6866
+ * calls handed over (a script that keeps one past its call gets a clear
6867
+ * error using it). VM refs live until the host collects their callables. */
6868
+ idle() {
6869
+ if (this.depth > 0 || this.pendingAsync > 0) return;
6870
+ if (this.disposeOnIdle) return this.dispose();
6871
+ if (!this.loaded) return;
6872
+ this.hostFns.length = this.baseFns;
6873
+ this.hostObjs.length = this.baseObjs;
6874
+ for (const [k2, id] of this.bound)
6875
+ if (id >= this.baseFns) this.bound.delete(k2);
6876
+ }
6877
+ drain() {
6878
+ this.enter(() => {
6879
+ const r = getRuntime().executePendingJobs();
6880
+ if (r.error) r.error.dispose();
6881
+ });
6882
+ }
6883
+ unwrap(r) {
6884
+ if (!r.error) return r.value;
6885
+ const dumped = this.ctx.dump(r.error);
6886
+ r.error.dispose();
6887
+ throw this.toHostError(dumped);
6888
+ }
6889
+ toHostError(dumped) {
6890
+ if (interrupted) {
6891
+ const e = new ScriptTimeoutError(
6892
+ `Script exceeded its ${entryBudget} ms time budget and was stopped.`
6893
+ );
6894
+ if (interrupted === this && this.opts.poisonOnTimeout)
6895
+ this.poisoned = new ScriptTimeoutError(
6896
+ `${e.message} It stays off until its source changes.`
6897
+ );
6898
+ return e;
6899
+ }
6900
+ const field = (k2) => dumped !== null && typeof dumped === "object" && k2 in dumped ? String(dumped[k2]) : "";
6901
+ const message = field("message") || String(dumped);
6902
+ if (/out of memory/i.test(message)) {
6903
+ resetPending = true;
6904
+ return new Error(
6905
+ `Script ran out of memory (${MEMORY_LIMIT / 1024 / 1024} MB for all scripts) and was stopped.`
6906
+ );
6907
+ }
6908
+ const host = this.lastHostError;
6909
+ if (host instanceof Error && host.message === message) return host;
6910
+ return new (BUILTIN_ERRORS[field("name")] ?? Error)(message);
6911
+ }
6912
+ /** The VM's answer: a JSON string, or a promise of one. */
6913
+ result(h) {
6914
+ if (this.ctx.typeof(h) === "string") {
6915
+ const s = this.ctx.getString(h);
6916
+ h.dispose();
6917
+ return this.decode(s)[0];
6918
+ }
6919
+ const p2 = this.ctx.resolvePromise(h);
6920
+ h.dispose();
6921
+ this.pendingAsync++;
6922
+ this.drain();
6923
+ return p2.then((r) => {
6924
+ const v2 = this.unwrap(r);
6925
+ const s = this.ctx.getString(v2);
6926
+ v2.dispose();
6927
+ return this.decode(s)[0];
6928
+ }).finally(() => {
6929
+ this.pendingAsync--;
6930
+ this.idle();
6931
+ });
6932
+ }
6933
+ callBridge(method, args) {
6934
+ return this.enter(() => {
6935
+ const fnH = this.ctx.getProp(this.bridge, method);
6936
+ const argHs = args.map(
6937
+ (a2) => typeof a2 === "number" ? this.ctx.newNumber(a2) : this.ctx.newString(a2)
6938
+ );
6939
+ const r = this.ctx.callFunction(fnH, this.ctx.undefined, argHs);
6940
+ fnH.dispose();
6941
+ for (const a2 of argHs) a2.dispose();
6942
+ return this.result(this.unwrap(r));
6943
+ });
6944
+ }
6945
+ vmFunction(id) {
6946
+ const f2 = (...args) => {
6947
+ const freed = JSON.stringify(this.vmFreed);
6948
+ this.vmFreed = [];
6949
+ return this.callBridge("call", [id, this.encode(args), freed]);
6950
+ };
6951
+ this.vmFinalizer.register(f2, id);
6952
+ return f2;
6953
+ }
6954
+ load(code, helpers2, localHelpers) {
6955
+ const exported = this.callBridge("load", [
6956
+ code,
6957
+ this.encode(helpers2),
6958
+ localHelpers
6959
+ ]);
6960
+ this.baseFns = this.hostFns.length;
6961
+ this.baseObjs = this.hostObjs.length;
6962
+ this.loaded = true;
6963
+ return exported;
6964
+ }
6965
+ /** The compile cache dropped the module: free its context (once idle). */
6966
+ dispose() {
6967
+ if (this.dead) return;
6968
+ if (this.depth > 0 || this.pendingAsync > 0) {
6969
+ this.disposeOnIdle = true;
6970
+ return;
6971
+ }
6972
+ this.kill();
6973
+ live.delete(this);
6974
+ }
6975
+ /** Free the context now (runtime reset, or an idle dispose). */
6976
+ kill() {
6977
+ if (this.dead) return;
6978
+ this.dead = true;
6979
+ this.hostFns.length = 0;
6980
+ this.hostObjs.length = 0;
6981
+ this.bound.clear();
6982
+ if (this.bridge?.alive) this.bridge.dispose();
6983
+ if (this.ctx.alive) this.ctx.dispose();
6984
+ }
6985
+ };
6986
+ var executeInSandbox = (code, helpers2, localHelpers, opts = { budgetMs: COMMAND_BUDGET_MS }) => {
6987
+ localSource ??= `{${Object.entries(localHelpers).map(([k2, f2]) => `${JSON.stringify(k2)}: ${f2.toString()}`).join(",")}}`;
6988
+ const box = new ModuleSandbox(opts);
6989
+ try {
6990
+ return {
6991
+ exports: box.load(code, helpers2, localSource),
6992
+ release: () => box.dispose()
6993
+ };
6994
+ } catch (e) {
6995
+ box.dispose();
6996
+ throw e;
6997
+ }
6998
+ };
6999
+ var localSource = null;
7000
+
5655
7001
  // ../core/src/extensions/scriptRuntime.ts
5656
- var scriptHelpers = Object.freeze({ ...scriptHelpers_exports, ...scriptBooleans_exports });
7002
+ var releases = /* @__PURE__ */ new WeakMap();
7003
+ var releaseScriptModule = (mod) => {
7004
+ releases.get(mod)?.();
7005
+ releases.delete(mod);
7006
+ };
7007
+ var scriptHelpers = Object.freeze({
7008
+ ...scriptHelpers_exports,
7009
+ ...scriptBooleans_exports,
7010
+ ...scriptCurves_exports
7011
+ });
5657
7012
  var helpers = Object.freeze({ ...scriptHelpers });
5658
7013
  var onTranspilerReady = null;
5659
7014
  var transpiler = null;
5660
7015
  var transpilerLoading = null;
5661
7016
  var ensureScriptTranspiler = () => {
5662
7017
  if (transpiler) return Promise.resolve(transpiler);
5663
- transpilerLoading ??= import("sucrase").then(({ transform }) => {
5664
- transpiler = (script) => {
5665
- const code = transform(script, {
5666
- transforms: ["typescript", "imports"]
5667
- }).code;
5668
- const moduleShim = { exports: {} };
5669
- new Function("exports", "require", "module", code)(
5670
- moduleShim.exports,
5671
- (spec2) => {
5672
- if (spec2 === "lineadraw/helpers" || spec2 === "linea/helpers")
5673
- return scriptHelpers;
5674
- if (spec2 === "lineadraw" || spec2 === "linea")
5675
- return {
5676
- helpers,
5677
- defineBlock: (blockSpec) => blockSpec,
5678
- defineCommand: (commandSpec) => commandSpec
5679
- };
5680
- throw new Error(
5681
- `Cannot import "${spec2}" \u2014 scripts may only import from "lineadraw" and "lineadraw/helpers"`
5682
- );
5683
- },
5684
- moduleShim
5685
- );
5686
- const exported = moduleShim.exports;
5687
- const spec = exported.default;
5688
- return spec !== null && typeof spec === "object" && !Array.isArray(spec) ? { ...exported, ...spec } : exported;
5689
- };
5690
- onTranspilerReady?.();
5691
- return transpiler;
5692
- });
7018
+ transpilerLoading ??= Promise.all([import("sucrase"), ensureSandbox()]).then(
7019
+ ([{ transform }]) => {
7020
+ transpiler = (script, kind = "command") => {
7021
+ const code = transform(script, {
7022
+ transforms: ["typescript", "imports"]
7023
+ }).code;
7024
+ const { exports: exported, release } = executeInSandbox(
7025
+ code,
7026
+ scriptHelpers,
7027
+ scriptHelpers_exports,
7028
+ kind === "block" ? { budgetMs: BLOCK_BUDGET_MS, poisonOnTimeout: true } : { budgetMs: COMMAND_BUDGET_MS }
7029
+ );
7030
+ const spec = exported.default;
7031
+ const mod = spec !== null && typeof spec === "object" && !Array.isArray(spec) ? { ...exported, ...spec } : exported;
7032
+ releases.set(mod, release);
7033
+ return mod;
7034
+ };
7035
+ onTranspilerReady?.();
7036
+ return transpiler;
7037
+ }
7038
+ );
5693
7039
  return transpilerLoading;
5694
7040
  };
5695
- var executeScriptModule = (script) => {
7041
+ var executeScriptModule = (script, kind) => {
5696
7042
  if (!transpiler) throw transpilerLoadingError();
5697
- return transpiler(script);
7043
+ return transpiler(script, kind);
5698
7044
  };
7045
+ onSandboxReset(() => onTranspilerReady?.());
5699
7046
  var scriptTranspilerReady = () => transpiler !== null;
5700
7047
  var transpilerLoadingError = () => {
5701
7048
  void ensureScriptTranspiler();
@@ -5717,6 +7064,7 @@ var hashString = (s) => {
5717
7064
  };
5718
7065
  var isLabelArray = (v2) => Array.isArray(v2) && v2.every((s) => typeof s === "string");
5719
7066
  var compileCache = /* @__PURE__ */ new Map();
7067
+ onSandboxReset(() => compileCache.clear());
5720
7068
  var COMPILE_CACHE_MAX = 200;
5721
7069
  var resultCache = /* @__PURE__ */ new Map();
5722
7070
  var RESULT_CACHE_MAX = 500;
@@ -5868,13 +7216,24 @@ var compileBlock = (script) => {
5868
7216
  compileCache.set(script, cached);
5869
7217
  return cached;
5870
7218
  }
5871
- const mod = toBlockModule(executeScriptModule(script));
5872
- const meta = extractMeta(mod);
7219
+ const raw = executeScriptModule(script, "block");
7220
+ let mod;
7221
+ let meta;
7222
+ try {
7223
+ mod = toBlockModule(raw);
7224
+ meta = extractMeta(mod);
7225
+ } catch (e) {
7226
+ releaseScriptModule(raw);
7227
+ throw e;
7228
+ }
5873
7229
  if (compileCache.size >= COMPILE_CACHE_MAX) {
5874
7230
  const oldest = compileCache.keys().next().value;
5875
- if (oldest !== void 0) compileCache.delete(oldest);
7231
+ if (oldest !== void 0) {
7232
+ releaseScriptModule(compileCache.get(oldest).raw);
7233
+ compileCache.delete(oldest);
7234
+ }
5876
7235
  }
5877
- const compiled = { mod, meta, hash: hashString(script) };
7236
+ const compiled = { raw, mod, meta, hash: hashString(script) };
5878
7237
  compileCache.set(script, compiled);
5879
7238
  return compiled;
5880
7239
  };
@@ -6149,7 +7508,9 @@ var testBlockDefinition = async (script) => {
6149
7508
  }
6150
7509
  if (mod.handles)
6151
7510
  parseBlockHandles(
6152
- mod.handles(scriptProps({ params: { ...defaultParams(meta) }, inputs: local })),
7511
+ mod.handles(
7512
+ scriptProps({ params: { ...defaultParams(meta) }, inputs: local })
7513
+ ),
6153
7514
  meta.params,
6154
7515
  meta.inputs,
6155
7516
  defaultParams(meta)
@@ -6228,9 +7589,21 @@ var framePose = (instance, hostId, scripts, resolveObject, depth) => {
6228
7589
  if (depth >= MAX_HOST_DEPTH) return null;
6229
7590
  const host = resolveObject?.(hostId);
6230
7591
  if (host?.type !== "block") return null;
6231
- return framePose(host, blockHostId(host, scripts), scripts, resolveObject, depth + 1);
7592
+ return framePose(
7593
+ host,
7594
+ blockHostId(host, scripts),
7595
+ scripts,
7596
+ resolveObject,
7597
+ depth + 1
7598
+ );
6232
7599
  };
6233
- var instancePose = (instance, scripts, resolveObject) => framePose(instance, blockHostId(instance, scripts), scripts, resolveObject, 0);
7600
+ var instancePose = (instance, scripts, resolveObject) => framePose(
7601
+ instance,
7602
+ blockHostId(instance, scripts),
7603
+ scripts,
7604
+ resolveObject,
7605
+ 0
7606
+ );
6234
7607
  var exposeMemo = /* @__PURE__ */ new Map();
6235
7608
  var getBlockExposed = (instance, scripts) => {
6236
7609
  const def = resolveDefinition(instance, scripts);
@@ -6238,9 +7611,7 @@ var getBlockExposed = (instance, scripts) => {
6238
7611
  try {
6239
7612
  const hit = exposeMemo.get(instance.id);
6240
7613
  if (hit && hit.key === def.key) return hit.value;
6241
- const value = z10.json().parse(
6242
- def.mod.expose(scriptProps({ params: def.params }))
6243
- );
7614
+ const value = z10.json().parse(def.mod.expose(scriptProps({ params: def.params })));
6244
7615
  exposeMemo.set(instance.id, { key: def.key, value });
6245
7616
  return value;
6246
7617
  } catch {
@@ -6305,7 +7676,12 @@ var resolvePlaced = (def, instance, scripts, resolveObject) => {
6305
7676
  const hosting = hostingProps(instance, def, scripts, resolveObject);
6306
7677
  const hostingSig = hosting.host === null && hosting.hosted.length === 0 ? "" : String(hashString(JSON.stringify(hosting)));
6307
7678
  let inputs;
6308
- const drawInputs = () => inputs ??= drawInputsFor(def.meta, instance.inputs, pose.pivot, resolveObject);
7679
+ const drawInputs = () => inputs ??= drawInputsFor(
7680
+ def.meta,
7681
+ instance.inputs,
7682
+ pose.pivot,
7683
+ resolveObject
7684
+ );
6309
7685
  return {
6310
7686
  ok: true,
6311
7687
  def,
@@ -10317,7 +11693,7 @@ var angularFrame = (obj) => {
10317
11693
  return { vertex, radius, start, sweep, frame };
10318
11694
  };
10319
11695
  var overlaps = (a2, b) => a2[0] < b[1] - 1e-9 && b[0] < a2[1] - 1e-9;
10320
- var placeLabel = (frame, spec, index2, label, style, arrowCount, mode, stack) => {
11696
+ var placeLabel = (frame, spec, index2, label, style, arrowCount, mode, stack2) => {
10321
11697
  const s = style.scale;
10322
11698
  const h = style.textHeight * s;
10323
11699
  const gap = style.textOffset * s;
@@ -10339,8 +11715,8 @@ var placeLabel = (frame, spec, index2, label, style, arrowCount, mode, stack) =>
10339
11715
  along = (frame.s0 + frame.s1) / 2;
10340
11716
  row = 1;
10341
11717
  const interval2 = [along - width / 2, along + width / 2];
10342
- if (stack && stack.row >= 1 && overlaps(interval2, stack.interval))
10343
- row = stack.row + 1;
11718
+ if (stack2 && stack2.row >= 1 && overlaps(interval2, stack2.interval))
11719
+ row = stack2.row + 1;
10344
11720
  across = row * (h + gap);
10345
11721
  }
10346
11722
  }
@@ -10399,7 +11775,7 @@ var linearGeometry = (obj, style) => {
10399
11775
  const arrows = [];
10400
11776
  const labels = [];
10401
11777
  const leaders = [];
10402
- let stack = null;
11778
+ let stack2 = null;
10403
11779
  frames.forEach((frame, i) => {
10404
11780
  const L = frame.s1 - frame.s0;
10405
11781
  const value = L;
@@ -10416,9 +11792,9 @@ var linearGeometry = (obj, style) => {
10416
11792
  style,
10417
11793
  2,
10418
11794
  mode,
10419
- stack
11795
+ stack2
10420
11796
  );
10421
- stack = placed.row > 0 ? {
11797
+ stack2 = placed.row > 0 ? {
10422
11798
  row: placed.row,
10423
11799
  interval: [
10424
11800
  placed.text.along - placed.text.width / 2,
@@ -11413,7 +12789,7 @@ var isSymbolFont = (fontCode) => /^symbol(\.ttf)?$/i.test(fontCode.split("|")[0]
11413
12789
  var scanMtext = (text, opts) => {
11414
12790
  const chunks = [];
11415
12791
  let st = { symbol: false };
11416
- const stack = [];
12792
+ const stack2 = [];
11417
12793
  const attrs = (extra) => opts ? {
11418
12794
  ...st.font !== void 0 ? { font: st.font } : {},
11419
12795
  ...st.bold !== void 0 ? { bold: st.bold } : {},
@@ -11439,11 +12815,11 @@ var scanMtext = (text, opts) => {
11439
12815
  while (i < text.length) {
11440
12816
  const ch = text[i];
11441
12817
  if (ch === "{") {
11442
- stack.push(st);
12818
+ stack2.push(st);
11443
12819
  st = { ...st };
11444
12820
  i++;
11445
12821
  } else if (ch === "}") {
11446
- st = stack.pop() ?? st;
12822
+ st = stack2.pop() ?? st;
11447
12823
  i++;
11448
12824
  } else if (ch !== "\\") {
11449
12825
  emit(st.symbol ? SYMBOL_FONT[ch] ?? ch : ch);
@@ -11984,7 +13360,24 @@ var classesSection = (content) => DXF_CLASSES.filter(([name]) => content.include
11984
13360
  0
11985
13361
  ${name}
11986
13362
  `)).map(
11987
- ([name, cpp, app, proxy, isEntity]) => [0, "CLASS", 1, name, 2, cpp, 3, app, 90, proxy, 91, 0, 280, 0, 281, isEntity].map((v2) => `${v2}
13363
+ ([name, cpp, app, proxy, isEntity]) => [
13364
+ 0,
13365
+ "CLASS",
13366
+ 1,
13367
+ name,
13368
+ 2,
13369
+ cpp,
13370
+ 3,
13371
+ app,
13372
+ 90,
13373
+ proxy,
13374
+ 91,
13375
+ 0,
13376
+ 280,
13377
+ 0,
13378
+ 281,
13379
+ isEntity
13380
+ ].map((v2) => `${v2}
11988
13381
  `).join("")
11989
13382
  ).join("");
11990
13383
 
@@ -12283,6 +13676,103 @@ var dxfPatternName = (name) => {
12283
13676
  const key = name.toUpperCase().replace(/-/g, "_").replace(/\./g, "_");
12284
13677
  return HatchPredefinedPatterns[key] ?? HatchPredefinedPatterns.ANSI31;
12285
13678
  };
13679
+ var HatchLoopPaths = class {
13680
+ loops;
13681
+ constructor(loops) {
13682
+ this.loops = loops;
13683
+ }
13684
+ get length() {
13685
+ return this.loops.length;
13686
+ }
13687
+ dxfy(dx) {
13688
+ for (const loop of this.loops) {
13689
+ const vertices = loopToVertices(loop);
13690
+ if (vertices) {
13691
+ dx.push(92, PATH_POLYLINE);
13692
+ new HatchPolylineBoundary(vertices).dxfy(dx);
13693
+ continue;
13694
+ }
13695
+ const chain = chainEdges(loop);
13696
+ dx.push(92, PATH_DEFAULT);
13697
+ dx.push(93, chain.length);
13698
+ for (const { edge, reversed } of chain) writeEdge(dx, edge, reversed);
13699
+ dx.push(97, 0);
13700
+ }
13701
+ }
13702
+ };
13703
+ var PATH_DEFAULT = 0;
13704
+ var PATH_POLYLINE = 2;
13705
+ var writeEdge = (dx, edge, reversed) => {
13706
+ switch (edge.kind) {
13707
+ case "line": {
13708
+ const [a2, b] = reversed ? [edge.b, edge.a] : [edge.a, edge.b];
13709
+ dx.push(72, 1);
13710
+ dx.point2d(a2);
13711
+ dx.push(11, b.x);
13712
+ dx.push(21, b.y);
13713
+ return;
13714
+ }
13715
+ case "arc": {
13716
+ const full = sameAngle(edge.startAngle, edge.endAngle);
13717
+ const s0 = edge.startAngle * RAD2DEG2;
13718
+ const e0 = full ? s0 + 360 : edge.endAngle * RAD2DEG2;
13719
+ dx.push(72, 2);
13720
+ dx.point2d(edge.center);
13721
+ dx.push(40, edge.radius);
13722
+ dx.push(50, reversed ? -e0 : s0);
13723
+ dx.push(51, reversed ? -s0 : e0);
13724
+ dx.push(73, reversed ? 0 : 1);
13725
+ return;
13726
+ }
13727
+ case "ellipse": {
13728
+ const full = sameAngle(edge.startAngle, edge.endAngle);
13729
+ const trueDeg = (t) => Math.atan2(edge.ratio * Math.sin(t), Math.cos(t)) * RAD2DEG2;
13730
+ const s0 = full ? 0 : trueDeg(edge.startAngle);
13731
+ const e0 = full ? 360 : trueDeg(edge.endAngle);
13732
+ dx.push(72, 3);
13733
+ dx.point2d(edge.center);
13734
+ dx.push(11, edge.majorAxis.x);
13735
+ dx.push(21, edge.majorAxis.y);
13736
+ dx.push(40, edge.ratio);
13737
+ dx.push(50, reversed ? -e0 : s0);
13738
+ dx.push(51, reversed ? -s0 : e0);
13739
+ dx.push(73, reversed ? 0 : 1);
13740
+ return;
13741
+ }
13742
+ case "spline":
13743
+ writeSplineEdge(dx, reversed ? reverseNurbs(edge) : edge);
13744
+ }
13745
+ };
13746
+ var sameAngle = (a2, b) => {
13747
+ const d2 = ((b - a2) % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2);
13748
+ return d2 < 1e-9 || Math.PI * 2 - d2 < 1e-9;
13749
+ };
13750
+ var reverseNurbs = (c2) => {
13751
+ const k0 = c2.knots[0];
13752
+ const kn = c2.knots[c2.knots.length - 1];
13753
+ return {
13754
+ degree: c2.degree,
13755
+ controlPoints: [...c2.controlPoints].reverse(),
13756
+ knots: [...c2.knots].reverse().map((k2) => k0 + kn - k2),
13757
+ ...c2.weights ? { weights: [...c2.weights].reverse() } : {}
13758
+ };
13759
+ };
13760
+ var writeSplineEdge = (dx, curve0) => {
13761
+ const curve = nurbsClamped(curve0) ? curve0 : nurbsSegment(curve0, ...nurbsDomain(curve0));
13762
+ const rational = curve.weights?.some((w2) => w2 !== 1) ?? false;
13763
+ dx.push(72, 4);
13764
+ dx.push(94, curve.degree);
13765
+ dx.push(73, rational ? 1 : 0);
13766
+ dx.push(74, 0);
13767
+ dx.push(95, curve.knots.length);
13768
+ dx.push(96, curve.controlPoints.length);
13769
+ for (const k2 of curve.knots) dx.push(40, k2);
13770
+ curve.controlPoints.forEach((p2, i) => {
13771
+ dx.point2d(p2);
13772
+ if (rational) dx.push(42, curve.weights[i]);
13773
+ });
13774
+ dx.push(97, 0);
13775
+ };
12286
13776
  var writeHatch = (space, obj, opts, ctx) => {
12287
13777
  if (obj.type !== "hatch") return;
12288
13778
  if (obj.fill.kind === "gradient") {
@@ -12292,14 +13782,7 @@ var writeHatch = (space, obj, opts, ctx) => {
12292
13782
  trueColor: String(hexToTrueColor(obj.fill.color1))
12293
13783
  };
12294
13784
  }
12295
- const boundary = new HatchBoundaryPaths();
12296
- for (const loop of obj.loops) {
12297
- boundary.addPolylineBoundary(
12298
- new HatchPolylineBoundary(
12299
- loop.points.map((v2) => ({ x: v2.x, y: v2.y, bulge: v2.bulge }))
12300
- )
12301
- );
12302
- }
13785
+ const boundary = new HatchLoopPaths(obj.loops);
12303
13786
  const fill = (
12304
13787
  // Gradient exports as SOLID in the start color — DXF gradient data
12305
13788
  // (codes 450+) is beyond dxf-writer, and a solid keeps the region and
@@ -12322,7 +13805,11 @@ var writeHatch = (space, obj, opts, ctx) => {
12322
13805
  scale: obj.fill.spacing * obj.scale / ANSI31_BASE_SPACING
12323
13806
  })
12324
13807
  );
12325
- const written = space.addHatch(boundary, fill, opts);
13808
+ const written = space.addHatch(
13809
+ boundary,
13810
+ fill,
13811
+ opts
13812
+ );
12326
13813
  if (obj.fill.kind === "pattern" && obj.fill.origin)
12327
13814
  ctx.hatchOrigins.set(written.handle, obj.fill.origin);
12328
13815
  };
@@ -12623,6 +14110,19 @@ var writeObjectEntities = (space, obj, ctx) => {
12623
14110
  opts
12624
14111
  );
12625
14112
  break;
14113
+ case "spline":
14114
+ space.addSpline(
14115
+ {
14116
+ controlPoints: obj.controlPoints.map(v3),
14117
+ degreeCurve: obj.degree,
14118
+ knots: obj.knots,
14119
+ ...obj.weights ? { weights: obj.weights } : {},
14120
+ ...obj.fitPoints ? { fitPoints: obj.fitPoints.map(v3) } : {},
14121
+ flags: 8 | (obj.closed ? 1 : 0) | (obj.closed && !nurbsClamped(obj) ? 2 : 0) | (obj.weights ? 4 : 0)
14122
+ },
14123
+ opts
14124
+ );
14125
+ break;
12626
14126
  case "hatch":
12627
14127
  writeHatch(space, obj, opts, ctx);
12628
14128
  break;
@@ -12647,8 +14147,16 @@ var writeObjectEntities = (space, obj, ctx) => {
12647
14147
  );
12648
14148
  if (obj.leaderLines.length > 0 && ctx.explodeLeaders) {
12649
14149
  for (const line of obj.leaderLines) {
14150
+ const start = arrowLineStart(
14151
+ line[0],
14152
+ line[1],
14153
+ arrowSize * obj.scale,
14154
+ arrowType
14155
+ );
12650
14156
  space.addLWPolyline(
12651
- line.map((v2) => ({ point: { x: v2.x, y: v2.y } })),
14157
+ [start, ...line.slice(1)].map((v2) => ({
14158
+ point: { x: v2.x, y: v2.y }
14159
+ })),
12652
14160
  opts
12653
14161
  );
12654
14162
  addArrowhead(
@@ -13068,13 +14576,35 @@ export {
13068
14576
  dot,
13069
14577
  len,
13070
14578
  dist,
13071
- norm,
13072
14579
  mid,
13073
14580
  angle,
13074
14581
  perp,
13075
14582
  fromAngle,
13076
14583
  normAngle,
13077
14584
  closestPointOnSegment,
14585
+ arcSweep,
14586
+ pointOnArc,
14587
+ arcStartPoint,
14588
+ arcEndPoint,
14589
+ arcMidPoint,
14590
+ angleInArc,
14591
+ bulgeToArc,
14592
+ bulgeFrom3Points,
14593
+ arcFrom3Points,
14594
+ distToArc,
14595
+ tessellateArc,
14596
+ isValidNurbs,
14597
+ sampleNurbs,
14598
+ interpolateFitPoints,
14599
+ interpolateClosed,
14600
+ nurbsToBeziers,
14601
+ curveTolerance,
14602
+ loopPolygon,
14603
+ emitLoopPath,
14604
+ loopCurves,
14605
+ loopCorners,
14606
+ hatchArea,
14607
+ verticesToLoop,
13078
14608
  Vec2Schema,
13079
14609
  ColorSchema,
13080
14610
  inputPoints,
@@ -13094,10 +14624,12 @@ export {
13094
14624
  fontFromDxfStyle,
13095
14625
  TextStyleSchema,
13096
14626
  DEFAULT_TEXT_STYLE,
14627
+ TextStyleOverrideSchema,
13097
14628
  textStyleFor,
13098
14629
  effectiveTextFont,
13099
14630
  DimStyleSchema,
13100
14631
  DEFAULT_DIM_STYLE,
14632
+ DimStyleOverrideSchema,
13101
14633
  assertKnownStyleOverrideKeys,
13102
14634
  dimStyleFor,
13103
14635
  dimFontFace,
@@ -13154,6 +14686,10 @@ export {
13154
14686
  resolveDocumentObject,
13155
14687
  documentBlocks,
13156
14688
  documentObjectResolver,
14689
+ splineThrough,
14690
+ hatchLoop,
14691
+ onSandboxReset,
14692
+ releaseScriptModule,
13157
14693
  ensureScriptTranspiler,
13158
14694
  executeScriptModule,
13159
14695
  scriptTranspilerReady,
@@ -13172,6 +14708,7 @@ export {
13172
14708
  getBlockMeta,
13173
14709
  getBlockMetaResult,
13174
14710
  listBlockMeta,
14711
+ findBlockScript,
13175
14712
  blockScriptId,
13176
14713
  blockDefinitionExists,
13177
14714
  dryRunObjectResolver,
@@ -13180,6 +14717,8 @@ export {
13180
14717
  hostedClosure,
13181
14718
  getEvaluatedWorldChildren,
13182
14719
  ANSI31_BASE_SPACING,
14720
+ arrowLineStart,
14721
+ paintArrowhead,
13183
14722
  linearAxis,
13184
14723
  dimensionGeometry,
13185
14724
  hexToRgb,
@@ -13194,4 +14733,4 @@ export {
13194
14733
  DWG_DXF_OPTIONS,
13195
14734
  buildDxf
13196
14735
  };
13197
- //# sourceMappingURL=chunk-YYJAXJOY.js.map
14736
+ //# sourceMappingURL=chunk-7UFXC7OI.js.map