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.
- package/README.md +18 -7
- package/bin/lineadraw.mjs +60 -10
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.js +1 -1
- package/dist/{chunk-YYJAXJOY.js → chunk-7UFXC7OI.js} +1680 -141
- package/dist/chunk-7UFXC7OI.js.map +1 -0
- package/dist/chunk-FDLANLIC.js +1161 -0
- package/dist/chunk-FDLANLIC.js.map +1 -0
- package/dist/chunk-M3EDRSHW.js +81 -0
- package/dist/chunk-M3EDRSHW.js.map +1 -0
- package/dist/chunk-MYP7RUYK.js +9 -0
- package/dist/chunk-MYP7RUYK.js.map +1 -0
- package/dist/{chunk-L2CWZAKW.js → chunk-RNA2RDGL.js} +13 -6
- package/dist/chunk-RNA2RDGL.js.map +1 -0
- package/dist/dist-56K6CNML.js +188 -0
- package/dist/dist-56K6CNML.js.map +1 -0
- package/dist/dist-IEN64QSV.js +10 -0
- package/dist/dist-IEN64QSV.js.map +1 -0
- package/dist/emscripten-module-Q67P5WYC-ITCU5LXL.js +2424 -0
- package/dist/emscripten-module-Q67P5WYC-ITCU5LXL.js.map +1 -0
- package/dist/{exportDxf-C4CLQCC3.js → exportDxf-6XTXQ4XN.js} +2 -2
- package/dist/ffi-SHMEF5YV.js +82 -0
- package/dist/ffi-SHMEF5YV.js.map +1 -0
- package/dist/module-ES6BEMUI-BJFWC656.js +14 -0
- package/dist/module-ES6BEMUI-BJFWC656.js.map +1 -0
- package/dist/module-asyncify-2EFITU5U-7F5WZXRA.js +9 -0
- package/dist/module-asyncify-2EFITU5U-7F5WZXRA.js.map +1 -0
- package/dist/sdk.d.ts +868 -95
- package/dist/sdk.js +619 -558
- package/dist/sdk.js.map +1 -1
- package/lineadraw.d.ts +162 -8
- package/package.json +2 -2
- package/dist/chunk-L2CWZAKW.js.map +0 -1
- package/dist/chunk-YYJAXJOY.js.map +0 -1
- /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
|
|
45
|
-
let sweep = ccw ? ((endAngle - startAngle) %
|
|
46
|
-
if (sweep === 0) sweep = ccw ?
|
|
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
|
-
|
|
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
|
|
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) /
|
|
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
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
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 {
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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)
|
|
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)
|
|
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(
|
|
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
|
|
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(
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
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
|
|
5872
|
-
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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 (
|
|
10343
|
-
row =
|
|
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
|
|
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
|
-
|
|
11795
|
+
stack2
|
|
10420
11796
|
);
|
|
10421
|
-
|
|
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
|
|
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
|
-
|
|
12818
|
+
stack2.push(st);
|
|
11443
12819
|
st = { ...st };
|
|
11444
12820
|
i++;
|
|
11445
12821
|
} else if (ch === "}") {
|
|
11446
|
-
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]) => [
|
|
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
|
|
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(
|
|
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) => ({
|
|
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-
|
|
14736
|
+
//# sourceMappingURL=chunk-7UFXC7OI.js.map
|