lineadraw 0.9.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 +154 -20
- package/bin/lineadraw.mjs +60 -10
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.js +1 -1
- package/dist/{chunk-BQCSFVAF.js → chunk-7UFXC7OI.js} +5570 -1174
- 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-T2RTSTH5.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 +1118 -128
- package/dist/sdk.js +742 -620
- package/dist/sdk.js.map +1 -1
- package/lineadraw.d.ts +666 -44
- package/package.json +1 -1
- package/templates/README.md +6 -4
- package/dist/chunk-BQCSFVAF.js.map +0 -1
- package/dist/chunk-L2CWZAKW.js.map +0 -1
- /package/dist/{exportDxf-T2RTSTH5.js.map → exportDxf-6XTXQ4XN.js.map} +0 -0
package/dist/sdk.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BridgeError,
|
|
3
|
-
DEFAULT_BRIDGE_PORT,
|
|
4
|
-
bridgeFilePath,
|
|
5
|
-
connectEditors,
|
|
6
|
-
createBridge
|
|
7
|
-
} from "./chunk-L2CWZAKW.js";
|
|
8
1
|
import {
|
|
9
2
|
ADVANCE_TABLES,
|
|
10
3
|
ANSI31_BASE_SPACING,
|
|
@@ -13,11 +6,11 @@ import {
|
|
|
13
6
|
ColorSchema,
|
|
14
7
|
DEFAULT_DIM_STYLE,
|
|
15
8
|
DEFAULT_TEXT_STYLE,
|
|
9
|
+
DimStyleOverrideSchema,
|
|
16
10
|
DimStyleSchema,
|
|
17
11
|
EXTRACTED_EXTRAS,
|
|
18
12
|
EXTRACTED_RANGES,
|
|
19
13
|
FONTS,
|
|
20
|
-
HEX_COLOR,
|
|
21
14
|
HatchPatternSchema,
|
|
22
15
|
LineTypeSchema,
|
|
23
16
|
MAX_HATCH_SEGMENTS,
|
|
@@ -25,23 +18,36 @@ import {
|
|
|
25
18
|
PX_TO_MM,
|
|
26
19
|
REAL_FACES,
|
|
27
20
|
REFERENCE_FORMATS,
|
|
21
|
+
TextStyleOverrideSchema,
|
|
28
22
|
TextStyleSchema,
|
|
29
23
|
Vec2Schema,
|
|
30
24
|
aciToHex,
|
|
25
|
+
acquireInputTable,
|
|
31
26
|
add,
|
|
32
27
|
angle,
|
|
28
|
+
angleInArc,
|
|
33
29
|
approximateTextMeasurer,
|
|
30
|
+
arcEndPoint,
|
|
31
|
+
arcFrom3Points,
|
|
32
|
+
arcMidPoint,
|
|
33
|
+
arcStartPoint,
|
|
34
|
+
arcSweep,
|
|
34
35
|
arcToBeziers,
|
|
36
|
+
arrowLineStart,
|
|
35
37
|
assertKnownStyleOverrideKeys,
|
|
36
38
|
blockDefinitionExists,
|
|
37
39
|
blockPivot,
|
|
38
40
|
blockScriptId,
|
|
41
|
+
bulgeFrom3Points,
|
|
42
|
+
bulgeToArc,
|
|
39
43
|
bytesToDataUrl,
|
|
44
|
+
checkNamedInputs,
|
|
40
45
|
cleanRichText,
|
|
41
46
|
cleanText,
|
|
42
47
|
closestPointOnSegment,
|
|
43
48
|
computeHatchLines,
|
|
44
49
|
computePatternGeometry,
|
|
50
|
+
curveTolerance,
|
|
45
51
|
dataUrlBytes,
|
|
46
52
|
decodeTextEscapes,
|
|
47
53
|
dimFontFace,
|
|
@@ -50,17 +56,21 @@ import {
|
|
|
50
56
|
dimensionRawToLabels,
|
|
51
57
|
dimensionRawToOffset,
|
|
52
58
|
dist,
|
|
59
|
+
distToArc,
|
|
60
|
+
documentBlocks,
|
|
53
61
|
documentObjectResolver,
|
|
54
62
|
dot,
|
|
55
|
-
|
|
63
|
+
dryRunBlockPlacement,
|
|
56
64
|
dryRunObjectResolver,
|
|
57
65
|
effectiveTextFont,
|
|
58
66
|
ellipseArcToBeziers,
|
|
59
67
|
embeddedAssetId,
|
|
68
|
+
emitLoopPath,
|
|
60
69
|
ensureScriptTranspiler,
|
|
61
70
|
estimatePatternSegments,
|
|
62
71
|
executeScriptModule,
|
|
63
72
|
expandWithBlockDependents,
|
|
73
|
+
findBlockScript,
|
|
64
74
|
fontFace,
|
|
65
75
|
fontFromDxfStyle,
|
|
66
76
|
fromAngle,
|
|
@@ -71,16 +81,30 @@ import {
|
|
|
71
81
|
getHatchPattern,
|
|
72
82
|
getLineType,
|
|
73
83
|
hashAsset,
|
|
84
|
+
hatchArea,
|
|
85
|
+
hatchLoop,
|
|
74
86
|
hatchPatternKey,
|
|
75
87
|
hexToRgb,
|
|
88
|
+
hostedClosure,
|
|
76
89
|
imagePixelSize,
|
|
90
|
+
inputLabel,
|
|
91
|
+
inputPoints,
|
|
92
|
+
inputRefs,
|
|
93
|
+
interpolateClosed,
|
|
94
|
+
interpolateFitPoints,
|
|
77
95
|
invalidateBlockCache,
|
|
96
|
+
isRequiredInput,
|
|
97
|
+
isValidNurbs,
|
|
78
98
|
len,
|
|
79
99
|
lineSegments,
|
|
80
100
|
lineTypeKey,
|
|
81
101
|
lineWeightToMm,
|
|
82
102
|
linearAxis,
|
|
83
103
|
listBlockMeta,
|
|
104
|
+
loopCorners,
|
|
105
|
+
loopCurves,
|
|
106
|
+
loopPolygon,
|
|
107
|
+
mapInputValues,
|
|
84
108
|
matApply,
|
|
85
109
|
matIdentity,
|
|
86
110
|
matMultiply,
|
|
@@ -89,13 +113,19 @@ import {
|
|
|
89
113
|
mirrorObject,
|
|
90
114
|
mtextFontFlags,
|
|
91
115
|
mtextWidthFactor,
|
|
92
|
-
norm,
|
|
93
116
|
normAngle,
|
|
94
117
|
normalizeSpans,
|
|
118
|
+
nurbsToBeziers,
|
|
119
|
+
onSandboxReset,
|
|
120
|
+
paintArrowhead,
|
|
121
|
+
paramMismatch,
|
|
95
122
|
parseFontFace,
|
|
123
|
+
parseInputTable,
|
|
96
124
|
parseParamsExport,
|
|
97
125
|
perp,
|
|
126
|
+
pointOnArc,
|
|
98
127
|
realFace,
|
|
128
|
+
releaseScriptModule,
|
|
99
129
|
remapBlockInputRefs,
|
|
100
130
|
renderDashes,
|
|
101
131
|
resolveDocumentObject,
|
|
@@ -105,12 +135,17 @@ import {
|
|
|
105
135
|
rgbToHex,
|
|
106
136
|
richTextBlock,
|
|
107
137
|
rotateObject,
|
|
138
|
+
sampleNurbs,
|
|
108
139
|
scale,
|
|
109
140
|
scaleObjectUniform,
|
|
141
|
+
scanScriptId,
|
|
110
142
|
scriptTranspilerReady,
|
|
143
|
+
selectionFits,
|
|
111
144
|
signedArcSweep,
|
|
145
|
+
splineThrough,
|
|
112
146
|
sub,
|
|
113
147
|
tableLayout,
|
|
148
|
+
tessellateArc,
|
|
114
149
|
testBlockDefinition,
|
|
115
150
|
textArrowSize,
|
|
116
151
|
textArrowType,
|
|
@@ -121,108 +156,26 @@ import {
|
|
|
121
156
|
textStyleFor,
|
|
122
157
|
textWidth,
|
|
123
158
|
translateObject,
|
|
124
|
-
valueParams
|
|
125
|
-
|
|
159
|
+
valueParams,
|
|
160
|
+
verticesToLoop,
|
|
161
|
+
withEmptyLists
|
|
162
|
+
} from "./chunk-7UFXC7OI.js";
|
|
126
163
|
import {
|
|
127
164
|
embeddedPdfFonts
|
|
128
165
|
} from "./chunk-L4FNH35X.js";
|
|
166
|
+
import {
|
|
167
|
+
BridgeError,
|
|
168
|
+
DEFAULT_BRIDGE_PORT,
|
|
169
|
+
bridgeFilePath,
|
|
170
|
+
connectEditors,
|
|
171
|
+
createBridge
|
|
172
|
+
} from "./chunk-RNA2RDGL.js";
|
|
129
173
|
import "./chunk-PZ5AY32C.js";
|
|
130
174
|
|
|
131
175
|
// src/document.ts
|
|
132
176
|
import { readFile, writeFile } from "fs/promises";
|
|
133
177
|
import { dirname, isAbsolute, resolve } from "path";
|
|
134
178
|
|
|
135
|
-
// ../core/src/geometry/arcs.ts
|
|
136
|
-
var arcSweep = (a) => {
|
|
137
|
-
const s = normAngle(a.endAngle - a.startAngle);
|
|
138
|
-
return s === 0 ? Math.PI * 2 : s;
|
|
139
|
-
};
|
|
140
|
-
var pointOnArc = (a, angle2) => ({
|
|
141
|
-
x: a.center.x + Math.cos(angle2) * a.radius,
|
|
142
|
-
y: a.center.y + Math.sin(angle2) * a.radius
|
|
143
|
-
});
|
|
144
|
-
var arcStartPoint = (a) => pointOnArc(a, a.startAngle);
|
|
145
|
-
var arcEndPoint = (a) => pointOnArc(a, a.endAngle);
|
|
146
|
-
var arcMidPoint = (a) => pointOnArc(a, a.startAngle + arcSweep(a) / 2);
|
|
147
|
-
var angleInArc = (a, angle2) => normAngle(angle2 - a.startAngle) <= arcSweep(a) + 1e-12;
|
|
148
|
-
var bulgeToArc = (a, b, bulge) => {
|
|
149
|
-
if (Math.abs(bulge) < 1e-12) return null;
|
|
150
|
-
const chord = dist(a, b);
|
|
151
|
-
if (chord < 1e-12) return null;
|
|
152
|
-
const sweep = 4 * Math.atan(bulge);
|
|
153
|
-
const radius = Math.abs(chord / (2 * Math.sin(sweep / 2)));
|
|
154
|
-
const m = mid(a, b);
|
|
155
|
-
const dir = scale(sub(b, a), 1 / chord);
|
|
156
|
-
const h = chord / 2 / Math.tan(sweep / 2);
|
|
157
|
-
const center = add(m, scale(perp(dir), h));
|
|
158
|
-
const angA = angle(sub(a, center));
|
|
159
|
-
const angB = angle(sub(b, center));
|
|
160
|
-
return bulge > 0 ? { center, radius, startAngle: angA, endAngle: angB } : { center, radius, startAngle: angB, endAngle: angA };
|
|
161
|
-
};
|
|
162
|
-
var bulgeFrom3Points = (a, m, b) => {
|
|
163
|
-
let turn = angle(sub(b, m)) - angle(sub(m, a));
|
|
164
|
-
while (turn > Math.PI) turn -= 2 * Math.PI;
|
|
165
|
-
while (turn < -Math.PI) turn += 2 * Math.PI;
|
|
166
|
-
return Math.tan(turn / 2);
|
|
167
|
-
};
|
|
168
|
-
var circleFrom3Points = (p1, p2, p3) => {
|
|
169
|
-
const ax = p1.x;
|
|
170
|
-
const ay = p1.y;
|
|
171
|
-
const bx = p2.x;
|
|
172
|
-
const by = p2.y;
|
|
173
|
-
const cx = p3.x;
|
|
174
|
-
const cy = p3.y;
|
|
175
|
-
const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
|
|
176
|
-
if (Math.abs(d) < 1e-12) return null;
|
|
177
|
-
const a2 = ax * ax + ay * ay;
|
|
178
|
-
const b2 = bx * bx + by * by;
|
|
179
|
-
const c2 = cx * cx + cy * cy;
|
|
180
|
-
const center = {
|
|
181
|
-
x: (a2 * (by - cy) + b2 * (cy - ay) + c2 * (ay - by)) / d,
|
|
182
|
-
y: (a2 * (cx - bx) + b2 * (ax - cx) + c2 * (bx - ax)) / d
|
|
183
|
-
};
|
|
184
|
-
return { center, radius: dist(center, p1) };
|
|
185
|
-
};
|
|
186
|
-
var arcFrom3Points = (start, on, end) => {
|
|
187
|
-
const c = circleFrom3Points(start, on, end);
|
|
188
|
-
if (!c) return null;
|
|
189
|
-
const angS = angle(sub(start, c.center));
|
|
190
|
-
const angO = angle(sub(on, c.center));
|
|
191
|
-
const angE = angle(sub(end, c.center));
|
|
192
|
-
const ccw = {
|
|
193
|
-
center: c.center,
|
|
194
|
-
radius: c.radius,
|
|
195
|
-
startAngle: angS,
|
|
196
|
-
endAngle: angE
|
|
197
|
-
};
|
|
198
|
-
if (angleInArc(ccw, angO)) return ccw;
|
|
199
|
-
return {
|
|
200
|
-
center: c.center,
|
|
201
|
-
radius: c.radius,
|
|
202
|
-
startAngle: angE,
|
|
203
|
-
endAngle: angS
|
|
204
|
-
};
|
|
205
|
-
};
|
|
206
|
-
var closestPointOnArc = (a, p) => {
|
|
207
|
-
const v = sub(p, a.center);
|
|
208
|
-
const ang = angle(v);
|
|
209
|
-
if (angleInArc(a, ang)) return pointOnArc(a, ang);
|
|
210
|
-
const s = arcStartPoint(a);
|
|
211
|
-
const e = arcEndPoint(a);
|
|
212
|
-
return dist(p, s) <= dist(p, e) ? s : e;
|
|
213
|
-
};
|
|
214
|
-
var distToArc = (a, p) => dist(p, closestPointOnArc(a, p));
|
|
215
|
-
var tessellateArc = (a, chordTolerance = 0.1) => {
|
|
216
|
-
const sweep = arcSweep(a);
|
|
217
|
-
const maxStep = a.radius <= chordTolerance ? sweep : 2 * Math.acos(Math.max(-1, 1 - chordTolerance / a.radius));
|
|
218
|
-
const n2 = Math.max(2, Math.ceil(sweep / Math.max(maxStep, 1e-3)));
|
|
219
|
-
const pts = [];
|
|
220
|
-
for (let i = 0; i <= n2; i++) {
|
|
221
|
-
pts.push(pointOnArc(a, a.startAngle + sweep * i / n2));
|
|
222
|
-
}
|
|
223
|
-
return pts;
|
|
224
|
-
};
|
|
225
|
-
|
|
226
179
|
// ../core/src/geometry/ellipse.ts
|
|
227
180
|
var ellipseSweep = (e) => {
|
|
228
181
|
const s = normAngle(e.endAngle - e.startAngle);
|
|
@@ -340,12 +293,6 @@ var chainLength = (points, closed) => {
|
|
|
340
293
|
return sum;
|
|
341
294
|
};
|
|
342
295
|
var polylineArea = (points) => polygonArea(verticesToPolygon(points));
|
|
343
|
-
var hatchArea = (loops) => {
|
|
344
|
-
const areas = loops.map((l) => polygonArea(verticesToPolygon(l.points)));
|
|
345
|
-
if (areas.length === 0) return 0;
|
|
346
|
-
const holes = areas.slice(1).reduce((a, b) => a + b, 0);
|
|
347
|
-
return Math.max(areas[0] - holes, 0);
|
|
348
|
-
};
|
|
349
296
|
|
|
350
297
|
// ../core/src/model/document.ts
|
|
351
298
|
import { z as z2 } from "zod";
|
|
@@ -353,11 +300,13 @@ import { z as z2 } from "zod";
|
|
|
353
300
|
// ../core/src/model/paperLayout.ts
|
|
354
301
|
import { z } from "zod";
|
|
355
302
|
var SHEET_PRESETS = {
|
|
303
|
+
A5: [148, 210],
|
|
356
304
|
A4: [210, 297],
|
|
357
305
|
A3: [297, 420],
|
|
358
306
|
A2: [420, 594],
|
|
359
307
|
A1: [594, 841],
|
|
360
|
-
A0: [841, 1189]
|
|
308
|
+
A0: [841, 1189],
|
|
309
|
+
Letter: [215.9, 279.4]
|
|
361
310
|
};
|
|
362
311
|
var resolveSheetSize = (sheet = "A3", defaultOrientation = "landscape") => {
|
|
363
312
|
if (typeof sheet !== "string" && "width" in sheet)
|
|
@@ -408,7 +357,8 @@ var LayerSchema = z2.object({
|
|
|
408
357
|
});
|
|
409
358
|
var DEFAULT_DOCUMENT_NAME = "Untitled project";
|
|
410
359
|
var DocumentSettingsSchema = z2.object({
|
|
411
|
-
units: z2.enum(["mm", "in"]).default("mm")
|
|
360
|
+
units: z2.enum(["mm", "in"]).default("mm"),
|
|
361
|
+
modelScale: z2.number().positive().default(1)
|
|
412
362
|
});
|
|
413
363
|
var LineaDocumentSchema = z2.preprocess(
|
|
414
364
|
migrateDocument,
|
|
@@ -425,7 +375,7 @@ var LineaDocumentSchema = z2.preprocess(
|
|
|
425
375
|
/** Document-wide settings (`DocumentSettingsSchema`). `units` is
|
|
426
376
|
* declarative for now: geometry is always stored in mm and nothing
|
|
427
377
|
* renders in inches yet. */
|
|
428
|
-
settings: DocumentSettingsSchema.default({ units: "mm" }),
|
|
378
|
+
settings: DocumentSettingsSchema.default({ units: "mm", modelScale: 1 }),
|
|
429
379
|
layers: z2.array(LayerSchema).min(1),
|
|
430
380
|
currentLayerId: z2.string(),
|
|
431
381
|
/** Array order is draw order (bottom to top).
|
|
@@ -659,10 +609,10 @@ var SvgSink = class {
|
|
|
659
609
|
transforms.push(
|
|
660
610
|
`translate(${n(tp.x)} ${n(-tp.y)}) scale(${n(w)} 1) translate(${n(-tp.x)} ${n(tp.y)})`
|
|
661
611
|
);
|
|
662
|
-
const
|
|
612
|
+
const rot = transforms.length > 0 ? ` transform="${transforms.join(" ")}"` : "";
|
|
663
613
|
const alpha = t.opacity !== void 0 && t.opacity < 1 ? ` fill-opacity="${n(t.opacity)}"` : "";
|
|
664
614
|
this.els.push(
|
|
665
|
-
`<text x="${n(tp.x)}" y="${n(-tp.y)}" font-size="${n(t.heightMm / def.capHeight * scale2)}" font-family="${def.cssStack}"${face} fill="${t.color}"${alpha} text-anchor="${anchor}"${
|
|
615
|
+
`<text x="${n(tp.x)}" y="${n(-tp.y)}" font-size="${n(t.heightMm / def.capHeight * scale2)}" font-family="${def.cssStack}"${face} fill="${t.color}"${alpha} text-anchor="${anchor}"${rot}>${escapeXml(t.text)}</text>`
|
|
666
616
|
);
|
|
667
617
|
}
|
|
668
618
|
measureText(text, heightMm, font, widthFactor) {
|
|
@@ -677,10 +627,10 @@ var SvgSink = class {
|
|
|
677
627
|
});
|
|
678
628
|
const scale2 = Math.hypot(this.m[0], this.m[1]) || 1;
|
|
679
629
|
const deg = -i.rotation * 180 / Math.PI;
|
|
680
|
-
const
|
|
630
|
+
const rot = deg !== 0 ? ` transform="rotate(${n(deg)} ${n(topLeft.x)} ${n(-topLeft.y)})"` : "";
|
|
681
631
|
const opacity = i.opacity < 1 ? ` opacity="${n(i.opacity)}"` : "";
|
|
682
632
|
this.els.push(
|
|
683
|
-
`<image x="${n(topLeft.x)}" y="${n(-topLeft.y)}" width="${n(i.widthMm * scale2)}" height="${n(i.heightMm * scale2)}" preserveAspectRatio="none"${opacity}${
|
|
633
|
+
`<image x="${n(topLeft.x)}" y="${n(-topLeft.y)}" width="${n(i.widthMm * scale2)}" height="${n(i.heightMm * scale2)}" preserveAspectRatio="none"${opacity}${rot} href="${i.data}"/>`
|
|
684
634
|
);
|
|
685
635
|
}
|
|
686
636
|
pushTransform(m) {
|
|
@@ -813,6 +763,22 @@ var paintEllipse = (obj, sink, env) => {
|
|
|
813
763
|
sink.stroke(env.style);
|
|
814
764
|
};
|
|
815
765
|
|
|
766
|
+
// ../core/src/paint/painters/spline.ts
|
|
767
|
+
var paintSpline = (obj, sink, env) => {
|
|
768
|
+
sink.beginPath();
|
|
769
|
+
const pieces = nurbsToBeziers(obj);
|
|
770
|
+
if (pieces && pieces.length > 0) {
|
|
771
|
+
sink.moveTo(pieces[0].start);
|
|
772
|
+
for (const b of pieces) sink.bezierTo(b.c1, b.c2, b.end);
|
|
773
|
+
} else {
|
|
774
|
+
const pts = sampleNurbs(obj, curveTolerance(obj));
|
|
775
|
+
if (pts.length < 2) return;
|
|
776
|
+
sink.moveTo(pts[0]);
|
|
777
|
+
for (let i = 1; i < pts.length; i++) sink.lineTo(pts[i]);
|
|
778
|
+
}
|
|
779
|
+
sink.stroke(env.style);
|
|
780
|
+
};
|
|
781
|
+
|
|
816
782
|
// ../core/src/paint/painters/hatch.ts
|
|
817
783
|
var SINGLE_FAMILY = {
|
|
818
784
|
name: "",
|
|
@@ -820,7 +786,7 @@ var SINGLE_FAMILY = {
|
|
|
820
786
|
};
|
|
821
787
|
var paintSolid = (obj, sink, env) => {
|
|
822
788
|
sink.beginPath();
|
|
823
|
-
for (const loop of obj.loops)
|
|
789
|
+
for (const loop of obj.loops) emitLoopPath(sink, loop);
|
|
824
790
|
sink.fill({ color: env.style.color, opacity: env.style.opacity });
|
|
825
791
|
};
|
|
826
792
|
var paintGradient = (obj, fill, sink, env) => {
|
|
@@ -829,7 +795,7 @@ var paintGradient = (obj, fill, sink, env) => {
|
|
|
829
795
|
let maxX = -Infinity;
|
|
830
796
|
let maxY = -Infinity;
|
|
831
797
|
for (const loop of obj.loops)
|
|
832
|
-
for (const p of loop
|
|
798
|
+
for (const p of loopPolygon(loop)) {
|
|
833
799
|
if (p.x < minX) minX = p.x;
|
|
834
800
|
if (p.y < minY) minY = p.y;
|
|
835
801
|
if (p.x > maxX) maxX = p.x;
|
|
@@ -852,7 +818,7 @@ var paintGradient = (obj, fill, sink, env) => {
|
|
|
852
818
|
to = { x: c.x + dir.x * r, y: c.y + dir.y * r };
|
|
853
819
|
}
|
|
854
820
|
sink.beginPath();
|
|
855
|
-
for (const loop of obj.loops)
|
|
821
|
+
for (const loop of obj.loops) emitLoopPath(sink, loop);
|
|
856
822
|
sink.fill({
|
|
857
823
|
color: fill.color1,
|
|
858
824
|
opacity: env.style.opacity,
|
|
@@ -870,7 +836,7 @@ var paintHatch = (obj, sink, env) => {
|
|
|
870
836
|
}
|
|
871
837
|
let lines = env.cache?.hatchLines.get(obj);
|
|
872
838
|
if (!lines) {
|
|
873
|
-
const rings = obj.loops.map((loop) =>
|
|
839
|
+
const rings = obj.loops.map((loop) => loopPolygon(loop));
|
|
874
840
|
const s = obj.fill.kind === "pattern" ? obj.fill.scale * obj.scale : obj.scale;
|
|
875
841
|
const pat = obj.fill.kind === "pattern" ? resolveHatchPattern(obj.fill.name, env.hatchPatterns) : void 0;
|
|
876
842
|
const estimate = pat ? estimatePatternSegments(rings, pat, s) : estimatePatternSegments(
|
|
@@ -912,50 +878,6 @@ var paintHatch = (obj, sink, env) => {
|
|
|
912
878
|
});
|
|
913
879
|
};
|
|
914
880
|
|
|
915
|
-
// ../core/src/paint/painters/arrows.ts
|
|
916
|
-
var paintArrowhead = (sink, tip, toward, size, color, type = "filled", opacity) => {
|
|
917
|
-
if (type === "none") return;
|
|
918
|
-
const dir = norm(sub(toward, tip));
|
|
919
|
-
if (dir.x === 0 && dir.y === 0) return;
|
|
920
|
-
switch (type) {
|
|
921
|
-
case "filled": {
|
|
922
|
-
const base = add(tip, scale(dir, size));
|
|
923
|
-
const half = scale(perp(dir), size / 3);
|
|
924
|
-
sink.beginPath();
|
|
925
|
-
sink.moveTo(tip);
|
|
926
|
-
sink.lineTo(add(base, half));
|
|
927
|
-
sink.lineTo(sub(base, half));
|
|
928
|
-
sink.closePath();
|
|
929
|
-
sink.fill({ color, opacity });
|
|
930
|
-
break;
|
|
931
|
-
}
|
|
932
|
-
case "open": {
|
|
933
|
-
const base = add(tip, scale(dir, size));
|
|
934
|
-
const half = scale(perp(dir), size / 3);
|
|
935
|
-
sink.beginPath();
|
|
936
|
-
sink.moveTo(add(base, half));
|
|
937
|
-
sink.lineTo(tip);
|
|
938
|
-
sink.lineTo(sub(base, half));
|
|
939
|
-
sink.stroke({ color, widthMm: Math.min(size / 10, 0.25), opacity });
|
|
940
|
-
break;
|
|
941
|
-
}
|
|
942
|
-
case "tick": {
|
|
943
|
-
const diag = scale(norm(add(dir, perp(dir))), size / 2);
|
|
944
|
-
sink.beginPath();
|
|
945
|
-
sink.moveTo(sub(tip, diag));
|
|
946
|
-
sink.lineTo(add(tip, diag));
|
|
947
|
-
sink.stroke({ color, widthMm: Math.min(size / 8, 0.35), opacity });
|
|
948
|
-
break;
|
|
949
|
-
}
|
|
950
|
-
case "dot": {
|
|
951
|
-
sink.beginPath();
|
|
952
|
-
sink.arc(tip, size / 4, 0, Math.PI * 2, true);
|
|
953
|
-
sink.fill({ color, opacity });
|
|
954
|
-
break;
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
};
|
|
958
|
-
|
|
959
881
|
// ../core/src/paint/painters/text.ts
|
|
960
882
|
var paintText = (obj, sink, env) => {
|
|
961
883
|
const { font, widthFactor } = effectiveTextFont(obj, env.textStyles);
|
|
@@ -971,18 +893,20 @@ var paintText = (obj, sink, env) => {
|
|
|
971
893
|
)
|
|
972
894
|
};
|
|
973
895
|
const { color, widthMm, opacity } = env.style;
|
|
896
|
+
const arrowSize = textArrowSize(obj, env.textStyles);
|
|
897
|
+
const arrowType = textArrowType(obj, env.textStyles);
|
|
974
898
|
for (const line of obj.leaderLines) {
|
|
975
899
|
sink.beginPath();
|
|
976
|
-
sink.moveTo(line[0]);
|
|
900
|
+
sink.moveTo(arrowLineStart(line[0], line[1], arrowSize, arrowType));
|
|
977
901
|
for (let i = 1; i < line.length; i++) sink.lineTo(line[i]);
|
|
978
902
|
sink.stroke({ color, widthMm, opacity });
|
|
979
903
|
paintArrowhead(
|
|
980
904
|
sink,
|
|
981
905
|
line[0],
|
|
982
906
|
line[1],
|
|
983
|
-
|
|
907
|
+
arrowSize,
|
|
984
908
|
color,
|
|
985
|
-
|
|
909
|
+
arrowType,
|
|
986
910
|
opacity
|
|
987
911
|
);
|
|
988
912
|
}
|
|
@@ -1110,15 +1034,21 @@ var paintDimension = (obj, sink, env) => {
|
|
|
1110
1034
|
dashMm: env.style.dashMm,
|
|
1111
1035
|
opacity: env.style.opacity
|
|
1112
1036
|
};
|
|
1037
|
+
const trim = (p, other) => {
|
|
1038
|
+
const arrow = geom.arrows.find(
|
|
1039
|
+
(ar) => dist(ar.tip, p) < 1e-9 && dot(sub(ar.toward, ar.tip), sub(other, p)) > 0
|
|
1040
|
+
);
|
|
1041
|
+
return arrow ? arrowLineStart(p, other, arrow.size, geom.arrowType) : p;
|
|
1042
|
+
};
|
|
1113
1043
|
sink.beginPath();
|
|
1114
|
-
for (const seg of
|
|
1115
|
-
...geom.extensionLines,
|
|
1116
|
-
...geom.dimLines,
|
|
1117
|
-
...geom.leaders
|
|
1118
|
-
]) {
|
|
1044
|
+
for (const seg of geom.extensionLines) {
|
|
1119
1045
|
sink.moveTo(seg.a);
|
|
1120
1046
|
sink.lineTo(seg.b);
|
|
1121
1047
|
}
|
|
1048
|
+
for (const seg of [...geom.dimLines, ...geom.leaders]) {
|
|
1049
|
+
sink.moveTo(trim(seg.a, seg.b));
|
|
1050
|
+
sink.lineTo(trim(seg.b, seg.a));
|
|
1051
|
+
}
|
|
1122
1052
|
if (geom.dimArc) {
|
|
1123
1053
|
const arc = geom.dimArc;
|
|
1124
1054
|
sink.moveTo(add(arc.center, scale(fromAngle(arc.startAngle), arc.radius)));
|
|
@@ -1233,7 +1163,7 @@ var paintChildren = (children, sink, env, parentLayerId) => {
|
|
|
1233
1163
|
// Same width-proportional dash rule as resolveStyle.
|
|
1234
1164
|
dashMm: scaleDash(
|
|
1235
1165
|
dashForLineType(child.lineType, env.lineTypes),
|
|
1236
|
-
(child.lineWidth ?? env.style.widthMm) * (child.lineTypeScale ?? 1)
|
|
1166
|
+
(child.lineWidth ?? env.style.widthMm) * (child.lineTypeScale ?? 1) * (env.lineTypeScale ?? 1)
|
|
1237
1167
|
) ?? env.style.dashMm,
|
|
1238
1168
|
opacity: child.opacity ?? env.style.opacity
|
|
1239
1169
|
},
|
|
@@ -1243,6 +1173,7 @@ var paintChildren = (children, sink, env, parentLayerId) => {
|
|
|
1243
1173
|
lineTypes: env.lineTypes,
|
|
1244
1174
|
hatchPatterns: env.hatchPatterns,
|
|
1245
1175
|
blockDefinitions: env.blockDefinitions,
|
|
1176
|
+
lineTypeScale: env.lineTypeScale,
|
|
1246
1177
|
resolveObject: env.resolveObject,
|
|
1247
1178
|
assets: env.assets,
|
|
1248
1179
|
// A reference child (linked / embedded file) loads like any other.
|
|
@@ -1451,6 +1382,17 @@ var buildEllipse = (obj) => {
|
|
|
1451
1382
|
]
|
|
1452
1383
|
};
|
|
1453
1384
|
};
|
|
1385
|
+
var buildSpline = (obj) => {
|
|
1386
|
+
const pts = sampleNurbs(obj, curveTolerance(obj) / 10);
|
|
1387
|
+
const segments = [];
|
|
1388
|
+
for (let i = 1; i < pts.length; i++)
|
|
1389
|
+
segments.push({ a: pts[i - 1], b: pts[i], facet: true });
|
|
1390
|
+
const points = obj.closed || pts.length < 2 ? [] : [
|
|
1391
|
+
{ p: pts[0], type: "endpoint" },
|
|
1392
|
+
{ p: pts[pts.length - 1], type: "endpoint" }
|
|
1393
|
+
];
|
|
1394
|
+
return { bounds: boundsOfPoints(pts), points, segments, arcs: [] };
|
|
1395
|
+
};
|
|
1454
1396
|
var buildHatch = (obj) => {
|
|
1455
1397
|
let bounds = emptyBounds();
|
|
1456
1398
|
const points = [];
|
|
@@ -1458,12 +1400,11 @@ var buildHatch = (obj) => {
|
|
|
1458
1400
|
const arcs = [];
|
|
1459
1401
|
const rings = [];
|
|
1460
1402
|
for (const loop of obj.loops) {
|
|
1461
|
-
const curves =
|
|
1403
|
+
const curves = loopCurves(loop);
|
|
1462
1404
|
segments.push(...curves.segments);
|
|
1463
1405
|
arcs.push(...curves.arcs);
|
|
1464
|
-
for (const
|
|
1465
|
-
|
|
1466
|
-
rings.push(verticesToPolygon(loop.points));
|
|
1406
|
+
for (const p of loopCorners(loop)) points.push({ p, type: "endpoint" });
|
|
1407
|
+
rings.push(loopPolygon(loop));
|
|
1467
1408
|
bounds = unionBounds(bounds, curveBounds(curves.segments, curves.arcs));
|
|
1468
1409
|
}
|
|
1469
1410
|
return { bounds, points, segments, arcs, rings };
|
|
@@ -1649,6 +1590,8 @@ var buildEntry = (obj, ctx) => {
|
|
|
1649
1590
|
}
|
|
1650
1591
|
case "ellipse":
|
|
1651
1592
|
return buildEllipse(obj);
|
|
1593
|
+
case "spline":
|
|
1594
|
+
return buildSpline(obj);
|
|
1652
1595
|
case "hatch":
|
|
1653
1596
|
return buildHatch(obj);
|
|
1654
1597
|
case "text":
|
|
@@ -1682,10 +1625,8 @@ var buildEntry = (obj, ctx) => {
|
|
|
1682
1625
|
};
|
|
1683
1626
|
}
|
|
1684
1627
|
case "block": {
|
|
1685
|
-
const
|
|
1686
|
-
|
|
1687
|
-
);
|
|
1688
|
-
const points = (inputPoints.length > 0 ? inputPoints : [blockPivot(obj)]).map((p) => ({ p, type: "endpoint" }));
|
|
1628
|
+
const pts = inputPoints(obj.inputs);
|
|
1629
|
+
const points = (pts.length > 0 ? pts : inputRefs(obj.inputs).length > 0 ? [] : [blockPivot(obj)]).map((p) => ({ p, type: "endpoint" }));
|
|
1689
1630
|
const segments = [];
|
|
1690
1631
|
const arcs = [];
|
|
1691
1632
|
const ellipses = [];
|
|
@@ -1814,7 +1755,8 @@ var referenceEntry = (obj, ctx) => {
|
|
|
1814
1755
|
segments.push({
|
|
1815
1756
|
a: applyMat(m, kept[0]),
|
|
1816
1757
|
b: applyMat(m, kept[1]),
|
|
1817
|
-
chord: seg.chord
|
|
1758
|
+
chord: seg.chord,
|
|
1759
|
+
facet: seg.facet
|
|
1818
1760
|
});
|
|
1819
1761
|
}
|
|
1820
1762
|
for (const a of e.arcs) {
|
|
@@ -2050,174 +1992,6 @@ var mergeStyles = (existing, incoming, same, opts) => {
|
|
|
2050
1992
|
return { styles, idByName, created };
|
|
2051
1993
|
};
|
|
2052
1994
|
|
|
2053
|
-
// ../core/src/geometry/nurbs.ts
|
|
2054
|
-
var nurbsDomain = (c) => {
|
|
2055
|
-
const n2 = c.controlPoints.length;
|
|
2056
|
-
return [c.knots[c.degree], c.knots[n2]];
|
|
2057
|
-
};
|
|
2058
|
-
var findSpan = (c, u) => {
|
|
2059
|
-
const n2 = c.controlPoints.length;
|
|
2060
|
-
const p = c.degree;
|
|
2061
|
-
if (u >= c.knots[n2]) return n2 - 1;
|
|
2062
|
-
if (u <= c.knots[p]) return p;
|
|
2063
|
-
let lo = p;
|
|
2064
|
-
let hi = n2;
|
|
2065
|
-
let mid2 = lo + hi >> 1;
|
|
2066
|
-
while (u < c.knots[mid2] || u >= c.knots[mid2 + 1]) {
|
|
2067
|
-
if (u < c.knots[mid2]) hi = mid2;
|
|
2068
|
-
else lo = mid2;
|
|
2069
|
-
mid2 = lo + hi >> 1;
|
|
2070
|
-
}
|
|
2071
|
-
return mid2;
|
|
2072
|
-
};
|
|
2073
|
-
var evaluateNurbs = (c, u) => {
|
|
2074
|
-
const p = c.degree;
|
|
2075
|
-
const k = findSpan(c, u);
|
|
2076
|
-
const d = [];
|
|
2077
|
-
for (let j = 0; j <= p; j++) {
|
|
2078
|
-
const i = k - p + j;
|
|
2079
|
-
const cp = c.controlPoints[i];
|
|
2080
|
-
const w2 = c.weights?.[i] ?? 1;
|
|
2081
|
-
d.push([cp.x * w2, cp.y * w2, w2]);
|
|
2082
|
-
}
|
|
2083
|
-
for (let r = 1; r <= p; r++)
|
|
2084
|
-
for (let j = p; j >= r; j--) {
|
|
2085
|
-
const i = k - p + j;
|
|
2086
|
-
const den = c.knots[i + p - r + 1] - c.knots[i];
|
|
2087
|
-
const a = den === 0 ? 0 : (u - c.knots[i]) / den;
|
|
2088
|
-
d[j] = [
|
|
2089
|
-
(1 - a) * d[j - 1][0] + a * d[j][0],
|
|
2090
|
-
(1 - a) * d[j - 1][1] + a * d[j][1],
|
|
2091
|
-
(1 - a) * d[j - 1][2] + a * d[j][2]
|
|
2092
|
-
];
|
|
2093
|
-
}
|
|
2094
|
-
const [x, y, w] = d[p];
|
|
2095
|
-
return w === 0 ? { x, y } : { x: x / w, y: y / w };
|
|
2096
|
-
};
|
|
2097
|
-
var isValidNurbs = (c) => c.degree >= 1 && c.controlPoints.length > c.degree && c.knots.length === c.controlPoints.length + c.degree + 1 && (c.weights === void 0 || c.weights.length === c.controlPoints.length) && c.knots.every((v, i) => i === 0 || v >= c.knots[i - 1]);
|
|
2098
|
-
var sampleNurbs = (c, tolerance, maxDepth = 10) => {
|
|
2099
|
-
const [u0, u1] = nurbsDomain(c);
|
|
2100
|
-
const out = [evaluateNurbs(c, u0)];
|
|
2101
|
-
const push = (q) => {
|
|
2102
|
-
const last = out[out.length - 1];
|
|
2103
|
-
if (Math.hypot(q.x - last.x, q.y - last.y) > 1e-9) out.push(q);
|
|
2104
|
-
};
|
|
2105
|
-
const refine = (a, pa, b, pb, depth) => {
|
|
2106
|
-
const m = (a + b) / 2;
|
|
2107
|
-
const pm = evaluateNurbs(c, m);
|
|
2108
|
-
const chord = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };
|
|
2109
|
-
const dev = Math.hypot(pm.x - chord.x, pm.y - chord.y);
|
|
2110
|
-
if (depth >= maxDepth || dev <= tolerance) {
|
|
2111
|
-
if (dev > tolerance / 4) push(pm);
|
|
2112
|
-
push(pb);
|
|
2113
|
-
return;
|
|
2114
|
-
}
|
|
2115
|
-
refine(a, pa, m, pm, depth + 1);
|
|
2116
|
-
refine(m, pm, b, pb, depth + 1);
|
|
2117
|
-
};
|
|
2118
|
-
const spans = [];
|
|
2119
|
-
for (let i = c.degree; i < c.controlPoints.length; i++) {
|
|
2120
|
-
const a = Math.max(c.knots[i], u0);
|
|
2121
|
-
const b = Math.min(c.knots[i + 1], u1);
|
|
2122
|
-
if (b > a) spans.push(a, b);
|
|
2123
|
-
}
|
|
2124
|
-
for (let i = 0; i < spans.length; i += 2) {
|
|
2125
|
-
const a = spans[i];
|
|
2126
|
-
const b = spans[i + 1];
|
|
2127
|
-
const pa = evaluateNurbs(c, a);
|
|
2128
|
-
const pb = evaluateNurbs(c, b);
|
|
2129
|
-
const m = (a + b) / 2;
|
|
2130
|
-
const pm = evaluateNurbs(c, m);
|
|
2131
|
-
refine(a, pa, m, pm, 1);
|
|
2132
|
-
refine(m, pm, b, pb, 1);
|
|
2133
|
-
}
|
|
2134
|
-
return dropCollinear(out, tolerance / 10);
|
|
2135
|
-
};
|
|
2136
|
-
var dropCollinear = (pts, eps) => {
|
|
2137
|
-
if (pts.length < 3) return pts;
|
|
2138
|
-
const out = [pts[0]];
|
|
2139
|
-
for (let i = 1; i < pts.length - 1; i++) {
|
|
2140
|
-
const a = out[out.length - 1];
|
|
2141
|
-
const b = pts[i + 1];
|
|
2142
|
-
const q = pts[i];
|
|
2143
|
-
const abx = b.x - a.x;
|
|
2144
|
-
const aby = b.y - a.y;
|
|
2145
|
-
const len2 = abx * abx + aby * aby;
|
|
2146
|
-
const t = len2 === 0 ? 0 : Math.max(
|
|
2147
|
-
0,
|
|
2148
|
-
Math.min(1, ((q.x - a.x) * abx + (q.y - a.y) * aby) / len2)
|
|
2149
|
-
);
|
|
2150
|
-
const dist2 = Math.hypot(q.x - (a.x + t * abx), q.y - (a.y + t * aby));
|
|
2151
|
-
if (dist2 > eps) out.push(q);
|
|
2152
|
-
}
|
|
2153
|
-
out.push(pts[pts.length - 1]);
|
|
2154
|
-
return out;
|
|
2155
|
-
};
|
|
2156
|
-
var interpolateFitPoints = (points, degree = 3) => {
|
|
2157
|
-
const n2 = points.length;
|
|
2158
|
-
if (n2 < 2) return null;
|
|
2159
|
-
const p = Math.min(degree, n2 - 1);
|
|
2160
|
-
const u = [0];
|
|
2161
|
-
let total2 = 0;
|
|
2162
|
-
for (let i = 1; i < n2; i++) {
|
|
2163
|
-
total2 += Math.hypot(
|
|
2164
|
-
points[i].x - points[i - 1].x,
|
|
2165
|
-
points[i].y - points[i - 1].y
|
|
2166
|
-
);
|
|
2167
|
-
u.push(total2);
|
|
2168
|
-
}
|
|
2169
|
-
if (total2 === 0) return null;
|
|
2170
|
-
for (let i = 0; i < n2; i++) u[i] /= total2;
|
|
2171
|
-
const knots = new Array(p + 1).fill(0);
|
|
2172
|
-
for (let j = 1; j <= n2 - p - 1; j++) {
|
|
2173
|
-
let s = 0;
|
|
2174
|
-
for (let i = j; i <= j + p - 1; i++) s += u[i];
|
|
2175
|
-
knots.push(s / p);
|
|
2176
|
-
}
|
|
2177
|
-
knots.push(...new Array(p + 1).fill(1));
|
|
2178
|
-
const basisRow = (ui) => {
|
|
2179
|
-
const row = new Array(n2).fill(0);
|
|
2180
|
-
const probe = {
|
|
2181
|
-
degree: p,
|
|
2182
|
-
controlPoints: points.map(() => ({ x: 0, y: 0 })),
|
|
2183
|
-
knots
|
|
2184
|
-
};
|
|
2185
|
-
for (let j = 0; j < n2; j++) {
|
|
2186
|
-
probe.controlPoints = points.map((_, k) => ({
|
|
2187
|
-
x: k === j ? 1 : 0,
|
|
2188
|
-
y: 0
|
|
2189
|
-
}));
|
|
2190
|
-
row[j] = evaluateNurbs(probe, ui).x;
|
|
2191
|
-
}
|
|
2192
|
-
return row;
|
|
2193
|
-
};
|
|
2194
|
-
const A = u.map((ui) => basisRow(ui));
|
|
2195
|
-
const bx = points.map((q) => q.x);
|
|
2196
|
-
const by = points.map((q) => q.y);
|
|
2197
|
-
for (let col = 0; col < n2; col++) {
|
|
2198
|
-
let pivot = col;
|
|
2199
|
-
for (let r = col + 1; r < n2; r++)
|
|
2200
|
-
if (Math.abs(A[r][col]) > Math.abs(A[pivot][col])) pivot = r;
|
|
2201
|
-
if (Math.abs(A[pivot][col]) < 1e-12) return null;
|
|
2202
|
-
[A[col], A[pivot]] = [A[pivot], A[col]];
|
|
2203
|
-
[bx[col], bx[pivot]] = [bx[pivot], bx[col]];
|
|
2204
|
-
[by[col], by[pivot]] = [by[pivot], by[col]];
|
|
2205
|
-
for (let r = 0; r < n2; r++) {
|
|
2206
|
-
if (r === col) continue;
|
|
2207
|
-
const k = A[r][col] / A[col][col];
|
|
2208
|
-
if (k === 0) continue;
|
|
2209
|
-
for (let c = col; c < n2; c++) A[r][c] -= k * A[col][c];
|
|
2210
|
-
bx[r] -= k * bx[col];
|
|
2211
|
-
by[r] -= k * by[col];
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
const controlPoints = points.map((_, i) => ({
|
|
2215
|
-
x: bx[i] / A[i][i],
|
|
2216
|
-
y: by[i] / A[i][i]
|
|
2217
|
-
}));
|
|
2218
|
-
return { degree: p, controlPoints, knots };
|
|
2219
|
-
};
|
|
2220
|
-
|
|
2221
1995
|
// ../core/src/geometry/band.ts
|
|
2222
1996
|
var left = (d) => ({ x: -d.y, y: d.x });
|
|
2223
1997
|
var unit = (a, b) => {
|
|
@@ -3191,7 +2965,6 @@ var unitFactor = (insunits) => {
|
|
|
3191
2965
|
}
|
|
3192
2966
|
};
|
|
3193
2967
|
var IMPORT_LINE_WIDTH_MM = 0.25;
|
|
3194
|
-
var SPLINE_TOLERANCE_MM = 0.02;
|
|
3195
2968
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["TEXT", "MTEXT", "ATTRIB", "ATTDEF"]);
|
|
3196
2969
|
var DIM_TYPES = /* @__PURE__ */ new Set(["DIMENSION", "LEADER"]);
|
|
3197
2970
|
var scanTags = (lines) => {
|
|
@@ -3401,48 +3174,55 @@ var baseFor = (e, ctx) => {
|
|
|
3401
3174
|
hidden: false
|
|
3402
3175
|
};
|
|
3403
3176
|
};
|
|
3404
|
-
var
|
|
3405
|
-
const
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
}
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3177
|
+
var hatchLoopEdges = (path, f, mirrored) => {
|
|
3178
|
+
const edges = hatchLoopEdgesOcs(path, f);
|
|
3179
|
+
if (!mirrored || edges.length === 0) return edges;
|
|
3180
|
+
const reflected = mirrorObject(
|
|
3181
|
+
{
|
|
3182
|
+
type: "hatch",
|
|
3183
|
+
id: "",
|
|
3184
|
+
layerId: "",
|
|
3185
|
+
loops: [{ edges }],
|
|
3186
|
+
fill: { kind: "solid" },
|
|
3187
|
+
scale: 1
|
|
3188
|
+
},
|
|
3189
|
+
{ x: 0, y: 0 },
|
|
3190
|
+
{ x: 0, y: 1 }
|
|
3191
|
+
);
|
|
3192
|
+
return reflected.loops[0].edges;
|
|
3193
|
+
};
|
|
3194
|
+
var hatchLoopEdgesOcs = (path, f) => {
|
|
3195
|
+
const pt2 = (p) => ({ x: p.x * f, y: p.y * f });
|
|
3196
|
+
if (path.isPolyline)
|
|
3197
|
+
return verticesToLoop(
|
|
3198
|
+
(path.vertices ?? []).map((v) => ({
|
|
3199
|
+
...pt2(v),
|
|
3200
|
+
bulge: v.bulge ?? 0
|
|
3201
|
+
}))
|
|
3202
|
+
).edges;
|
|
3203
|
+
const edges = [];
|
|
3419
3204
|
for (const edge of path.edges ?? []) {
|
|
3420
3205
|
switch (edge.kind) {
|
|
3421
3206
|
case 1: {
|
|
3422
|
-
const
|
|
3423
|
-
|
|
3207
|
+
const a = edge.points[0];
|
|
3208
|
+
const b = edge.end;
|
|
3209
|
+
if (a && b) edges.push({ kind: "line", a: pt2(a), b: pt2(b) });
|
|
3424
3210
|
break;
|
|
3425
3211
|
}
|
|
3426
3212
|
case 2: {
|
|
3427
3213
|
const c = edge.points[0];
|
|
3428
3214
|
if (!c || !(edge.r40 > 0)) break;
|
|
3429
|
-
const ccw = edge.ccw !== false;
|
|
3430
3215
|
const a0 = (edge.startAngle ?? 0) * DEG2RAD;
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
const
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
c.x + edge.r40 * Math.cos(ang),
|
|
3442
|
-
c.y + edge.r40 * Math.sin(ang),
|
|
3443
|
-
bulge
|
|
3444
|
-
);
|
|
3445
|
-
}
|
|
3216
|
+
const a1 = (edge.endAngle ?? 360) * DEG2RAD;
|
|
3217
|
+
const ccw = edge.ccw !== false;
|
|
3218
|
+
const full = Math.abs(a1 - a0) >= Math.PI * 2 - 1e-9;
|
|
3219
|
+
edges.push({
|
|
3220
|
+
kind: "arc",
|
|
3221
|
+
center: pt2(c),
|
|
3222
|
+
radius: edge.r40 * f,
|
|
3223
|
+
startAngle: ccw ? a0 : -a1,
|
|
3224
|
+
endAngle: full ? ccw ? a0 : -a1 : ccw ? a1 : -a0
|
|
3225
|
+
});
|
|
3446
3226
|
break;
|
|
3447
3227
|
}
|
|
3448
3228
|
case 3: {
|
|
@@ -3452,29 +3232,21 @@ var hatchLoopPointsOcs = (path, f) => {
|
|
|
3452
3232
|
const ratio = edge.r40 > 0 ? edge.r40 : 1;
|
|
3453
3233
|
const ccw = edge.ccw !== false;
|
|
3454
3234
|
const a0 = (edge.startAngle ?? 0) * DEG2RAD;
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
const
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
push(
|
|
3467
|
-
c.x + major.x * Math.cos(t) - major.y * ratio * Math.sin(t),
|
|
3468
|
-
c.y + major.y * Math.cos(t) + major.x * ratio * Math.sin(t)
|
|
3469
|
-
);
|
|
3470
|
-
}
|
|
3235
|
+
const a1 = (edge.endAngle ?? 360) * DEG2RAD;
|
|
3236
|
+
const full = Math.abs(a1 - a0) >= Math.PI * 2 - 1e-9;
|
|
3237
|
+
const param = (theta) => Math.atan2(Math.sin(theta) / ratio, Math.cos(theta));
|
|
3238
|
+
edges.push({
|
|
3239
|
+
kind: "ellipse",
|
|
3240
|
+
center: pt2(c),
|
|
3241
|
+
majorAxis: pt2(major),
|
|
3242
|
+
ratio: Math.min(1, ratio),
|
|
3243
|
+
startAngle: full ? 0 : param(ccw ? a0 : -a1),
|
|
3244
|
+
endAngle: full ? Math.PI * 2 : param(ccw ? a1 : -a0)
|
|
3245
|
+
});
|
|
3471
3246
|
break;
|
|
3472
3247
|
}
|
|
3473
3248
|
case 4: {
|
|
3474
|
-
const control = (edge.points ?? []).map(
|
|
3475
|
-
x: p.x,
|
|
3476
|
-
y: p.y
|
|
3477
|
-
}));
|
|
3249
|
+
const control = (edge.points ?? []).map(pt2);
|
|
3478
3250
|
const weights = edge.weights ?? [];
|
|
3479
3251
|
const curve = {
|
|
3480
3252
|
degree: edge.degree ?? 3,
|
|
@@ -3482,36 +3254,24 @@ var hatchLoopPointsOcs = (path, f) => {
|
|
|
3482
3254
|
knots: edge.knots ?? [],
|
|
3483
3255
|
...edge.rational && weights.length === control.length ? { weights } : {}
|
|
3484
3256
|
};
|
|
3485
|
-
const fit = (edge.fitPoints ?? []).map(
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3257
|
+
const fit = (edge.fitPoints ?? []).map(pt2);
|
|
3258
|
+
const exact = isValidNurbs(curve) ? curve : interpolateFitPoints(fit);
|
|
3259
|
+
if (exact) {
|
|
3260
|
+
edges.push({
|
|
3261
|
+
kind: "spline",
|
|
3262
|
+
...exact,
|
|
3263
|
+
...fit.length >= 2 ? { fitPoints: fit } : {}
|
|
3264
|
+
});
|
|
3265
|
+
break;
|
|
3266
|
+
}
|
|
3267
|
+
const poly = fit.length >= 2 ? fit : control;
|
|
3268
|
+
for (let i = 1; i < poly.length; i++)
|
|
3269
|
+
edges.push({ kind: "line", a: poly[i - 1], b: poly[i] });
|
|
3492
3270
|
break;
|
|
3493
3271
|
}
|
|
3494
3272
|
}
|
|
3495
3273
|
}
|
|
3496
|
-
return
|
|
3497
|
-
(p, i) => i === 0 || Math.abs(p.x - points[i - 1].x) > 1e-9 || Math.abs(p.y - points[i - 1].y) > 1e-9 || points[i - 1].bulge !== 0
|
|
3498
|
-
);
|
|
3499
|
-
};
|
|
3500
|
-
var atLeastThreeVertices = (points) => {
|
|
3501
|
-
if (points.length !== 2 || points.every((p) => p.bulge === 0)) return points;
|
|
3502
|
-
const out = [];
|
|
3503
|
-
for (let i = 0; i < 2; i++) {
|
|
3504
|
-
const a = points[i];
|
|
3505
|
-
const b = points[1 - i];
|
|
3506
|
-
out.push(a);
|
|
3507
|
-
const arc = a.bulge === 0 ? null : bulgeToArc(a, b, a.bulge);
|
|
3508
|
-
if (!arc) continue;
|
|
3509
|
-
const half = Math.tan(Math.atan(a.bulge) / 2);
|
|
3510
|
-
const mid2 = arcMidPoint(arc);
|
|
3511
|
-
out[out.length - 1] = { ...a, bulge: half };
|
|
3512
|
-
out.push({ x: mid2.x, y: mid2.y, bulge: half });
|
|
3513
|
-
}
|
|
3514
|
-
return out;
|
|
3274
|
+
return edges;
|
|
3515
3275
|
};
|
|
3516
3276
|
var convertHatch = (e, ctx) => {
|
|
3517
3277
|
const anyE = e;
|
|
@@ -3519,8 +3279,8 @@ var convertHatch = (e, ctx) => {
|
|
|
3519
3279
|
const mirrored = ctx.tags.mirroredHandles.has(String(anyE.handle));
|
|
3520
3280
|
const flip = mirrored ? -1 : 1;
|
|
3521
3281
|
const loops = (anyE.boundaryPaths ?? []).map((path) => ({
|
|
3522
|
-
|
|
3523
|
-
})).filter((loop) => loop.
|
|
3282
|
+
edges: hatchLoopEdges(path, ctx.f, mirrored)
|
|
3283
|
+
})).filter((loop) => loop.edges.length > 0);
|
|
3524
3284
|
if (loops.length === 0) return [];
|
|
3525
3285
|
let fill;
|
|
3526
3286
|
const patternMatch = typeof anyE.patternName === "string" ? getHatchPattern(anyE.patternName) : void 0;
|
|
@@ -3984,9 +3744,9 @@ var convertEntityInner = (e, dxf, ctx) => {
|
|
|
3984
3744
|
return [
|
|
3985
3745
|
{
|
|
3986
3746
|
type: "hatch",
|
|
3987
|
-
loops: loops.map(
|
|
3988
|
-
|
|
3989
|
-
|
|
3747
|
+
loops: loops.map(
|
|
3748
|
+
(l) => verticesToLoop(l.map((p) => ({ ...p, bulge: 0 })))
|
|
3749
|
+
),
|
|
3990
3750
|
fill: { kind: "solid" },
|
|
3991
3751
|
scale: 1,
|
|
3992
3752
|
...base
|
|
@@ -4116,32 +3876,46 @@ var convertEntityInner = (e, dxf, ctx) => {
|
|
|
4116
3876
|
case "SPLINE": {
|
|
4117
3877
|
const control = anyE.controlPoints ?? [];
|
|
4118
3878
|
const weights = ctx.tags.splineWeightsByHandle.get(String(anyE.handle));
|
|
3879
|
+
const fit = (anyE.fitPoints ?? []).map((p) => ({
|
|
3880
|
+
x: p.x * f,
|
|
3881
|
+
y: p.y * f
|
|
3882
|
+
}));
|
|
4119
3883
|
const curve = {
|
|
4120
3884
|
degree: anyE.degreeOfSplineCurve ?? 3,
|
|
4121
|
-
controlPoints: control.map((p) => ({ x: p.x, y: p.y })),
|
|
3885
|
+
controlPoints: control.map((p) => ({ x: p.x * f, y: p.y * f })),
|
|
4122
3886
|
knots: anyE.knotValues ?? [],
|
|
4123
3887
|
...weights && weights.length === control.length ? { weights } : {}
|
|
4124
3888
|
};
|
|
4125
|
-
const
|
|
4126
|
-
const
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
3889
|
+
const tangent = (t) => t && Math.hypot(t.x, t.y) > 1e-12 ? { x: t.x, y: t.y } : void 0;
|
|
3890
|
+
const startTangent = tangent(anyE.startTangent);
|
|
3891
|
+
const endTangent = tangent(anyE.endTangent);
|
|
3892
|
+
const closed = anyE.closed === true;
|
|
3893
|
+
const fitted = isValidNurbs(curve) ? curve : closed ? interpolateClosed(fit) : interpolateFitPoints(fit, 3, {
|
|
3894
|
+
start: startTangent,
|
|
3895
|
+
end: endTangent
|
|
3896
|
+
});
|
|
3897
|
+
if (fitted && isValidNurbs(fitted))
|
|
3898
|
+
return [
|
|
3899
|
+
{
|
|
3900
|
+
type: "spline",
|
|
3901
|
+
degree: fitted.degree,
|
|
3902
|
+
controlPoints: fitted.controlPoints,
|
|
3903
|
+
knots: fitted.knots,
|
|
3904
|
+
...fitted.weights ? { weights: fitted.weights } : {},
|
|
3905
|
+
...fit.length >= 2 ? { fitPoints: fit } : {},
|
|
3906
|
+
...fit.length >= 2 && !closed && startTangent ? { startTangent } : {},
|
|
3907
|
+
...fit.length >= 2 && !closed && endTangent ? { endTangent } : {},
|
|
3908
|
+
closed,
|
|
3909
|
+
...base
|
|
3910
|
+
}
|
|
3911
|
+
];
|
|
3912
|
+
const raw = fit.length >= 2 ? fit : control.map((p) => ({ x: p.x * f, y: p.y * f }));
|
|
3913
|
+
if (raw.length < 2) return [];
|
|
3914
|
+
bump(ctx.degraded, "SPLINE\u2192polyline (control points)");
|
|
4141
3915
|
return [
|
|
4142
3916
|
{
|
|
4143
3917
|
type: "polyline",
|
|
4144
|
-
points:
|
|
3918
|
+
points: raw.map((p) => ({ x: p.x, y: p.y, bulge: 0 })),
|
|
4145
3919
|
closed: anyE.closed === true,
|
|
4146
3920
|
...base
|
|
4147
3921
|
}
|
|
@@ -4156,7 +3930,9 @@ var convertEntityInner = (e, dxf, ctx) => {
|
|
|
4156
3930
|
return [
|
|
4157
3931
|
{
|
|
4158
3932
|
type: "hatch",
|
|
4159
|
-
loops: [
|
|
3933
|
+
loops: [
|
|
3934
|
+
verticesToLoop(points.map((p) => ({ ...pt(p, f), bulge: 0 })))
|
|
3935
|
+
],
|
|
4160
3936
|
fill: { kind: "solid" },
|
|
4161
3937
|
scale: 1,
|
|
4162
3938
|
...base
|
|
@@ -4172,9 +3948,7 @@ var convertEntityInner = (e, dxf, ctx) => {
|
|
|
4172
3948
|
{
|
|
4173
3949
|
type: "hatch",
|
|
4174
3950
|
loops: [
|
|
4175
|
-
{
|
|
4176
|
-
points: ordered.map((p) => ({ ...ocs(p), bulge: 0 }))
|
|
4177
|
-
}
|
|
3951
|
+
verticesToLoop(ordered.map((p) => ({ ...ocs(p), bulge: 0 })))
|
|
4178
3952
|
],
|
|
4179
3953
|
fill: { kind: "solid" },
|
|
4180
3954
|
scale: 1,
|
|
@@ -4386,7 +4160,7 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4386
4160
|
const sx = anyE.xScale ?? 1;
|
|
4387
4161
|
const sy = (anyE.yScale ?? 1) * (mirrored ? -1 : 1);
|
|
4388
4162
|
const rot0 = (anyE.rotation ?? 0) * DEG2RAD;
|
|
4389
|
-
const
|
|
4163
|
+
const rot = mirrored ? Math.PI - rot0 : rot0;
|
|
4390
4164
|
const pos = anyE.position ?? { x: 0, y: 0 };
|
|
4391
4165
|
const insert = mirrored ? { x: -pos.x * ctx.f, y: pos.y * ctx.f } : pt(pos, ctx.f);
|
|
4392
4166
|
if (e.type === "INSERT" && depth === 0 && !mirrored && sx > 0 && sy > 0 && Math.abs(sx - sy) < 1e-9) {
|
|
@@ -4397,7 +4171,7 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4397
4171
|
type: "block",
|
|
4398
4172
|
definitionId: def.id,
|
|
4399
4173
|
inputs: [insert],
|
|
4400
|
-
rotation:
|
|
4174
|
+
rotation: rot,
|
|
4401
4175
|
scale: sx,
|
|
4402
4176
|
params: {},
|
|
4403
4177
|
...baseFor(e, ctx)
|
|
@@ -4406,8 +4180,8 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4406
4180
|
}
|
|
4407
4181
|
if (e.type === "INSERT" && depth === 0) bump(ctx.degraded, "INSERT\u2192exploded");
|
|
4408
4182
|
const base = pt(block.position ?? { x: 0, y: 0 }, ctx.f);
|
|
4409
|
-
const cos = Math.cos(
|
|
4410
|
-
const sin = Math.sin(
|
|
4183
|
+
const cos = Math.cos(rot);
|
|
4184
|
+
const sin = Math.sin(rot);
|
|
4411
4185
|
const reflect = sx * sy < 0;
|
|
4412
4186
|
const meanScale = Math.sqrt(Math.abs(sx * sy)) || 1e-6;
|
|
4413
4187
|
const lin = (v) => ({
|
|
@@ -4460,7 +4234,7 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4460
4234
|
return t;
|
|
4461
4235
|
}
|
|
4462
4236
|
const majorLen = Math.max(ax, ay);
|
|
4463
|
-
const ang =
|
|
4237
|
+
const ang = rot + (ax >= ay ? 0 : Math.PI / 2);
|
|
4464
4238
|
return {
|
|
4465
4239
|
type: "ellipse",
|
|
4466
4240
|
center,
|
|
@@ -4508,7 +4282,18 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4508
4282
|
return t;
|
|
4509
4283
|
case "hatch": {
|
|
4510
4284
|
t.loops = t.loops.map((loop) => ({
|
|
4511
|
-
|
|
4285
|
+
edges: loop.edges.flatMap((edge) => {
|
|
4286
|
+
const { kind, ...geometry } = edge;
|
|
4287
|
+
const moved = transform({
|
|
4288
|
+
...geometry,
|
|
4289
|
+
type: kind,
|
|
4290
|
+
layerId: t.layerId
|
|
4291
|
+
});
|
|
4292
|
+
if (!moved || moved.type !== kind) return [];
|
|
4293
|
+
const out = { kind };
|
|
4294
|
+
for (const key of Object.keys(geometry)) out[key] = moved[key];
|
|
4295
|
+
return [out];
|
|
4296
|
+
})
|
|
4512
4297
|
}));
|
|
4513
4298
|
if (t.fill.kind === "pattern" || t.fill.kind === "lines") {
|
|
4514
4299
|
const d = lin({
|
|
@@ -4525,9 +4310,15 @@ var convertInsertInner = (e, dxf, ctx, depth, inheritedColor) => {
|
|
|
4525
4310
|
}
|
|
4526
4311
|
return t;
|
|
4527
4312
|
}
|
|
4313
|
+
case "spline":
|
|
4314
|
+
t.controlPoints = t.controlPoints.map(map);
|
|
4315
|
+
if (t.fitPoints) t.fitPoints = t.fitPoints.map(map);
|
|
4316
|
+
if (t.startTangent) t.startTangent = lin(t.startTangent);
|
|
4317
|
+
if (t.endTangent) t.endTangent = lin(t.endTangent);
|
|
4318
|
+
return t;
|
|
4528
4319
|
case "text":
|
|
4529
4320
|
t.position = map(t.position);
|
|
4530
|
-
t.rotation +=
|
|
4321
|
+
t.rotation += rot;
|
|
4531
4322
|
if (meanScale !== 1) {
|
|
4532
4323
|
const style = t.styleId && ctx.textStyleById.get(t.styleId) || ctx.defaultTextStyle;
|
|
4533
4324
|
const o = t.styleOverride ?? {};
|
|
@@ -4983,7 +4774,10 @@ var contentFromDocument = (doc, refId, bounds = emptyBounds()) => {
|
|
|
4983
4774
|
(o) => o.type === "block" ? {
|
|
4984
4775
|
...o,
|
|
4985
4776
|
id: prefix + o.id,
|
|
4986
|
-
inputs:
|
|
4777
|
+
inputs: mapInputValues(
|
|
4778
|
+
o.inputs,
|
|
4779
|
+
(v) => typeof v === "string" ? prefix + v : v
|
|
4780
|
+
)
|
|
4987
4781
|
} : { ...o, id: prefix + o.id }
|
|
4988
4782
|
);
|
|
4989
4783
|
const byId = new Map(objects.map((o) => [o.id, o]));
|
|
@@ -5134,7 +4928,7 @@ var FALLBACK_STYLE = {
|
|
|
5134
4928
|
color: "#e8e8e8",
|
|
5135
4929
|
widthMm: 0.25
|
|
5136
4930
|
};
|
|
5137
|
-
var resolveStyle = (obj, layers, lineTypes) => {
|
|
4931
|
+
var resolveStyle = (obj, layers, lineTypes, lineTypeScale = 1) => {
|
|
5138
4932
|
const layer = layers.find((l) => l.id === obj.layerId);
|
|
5139
4933
|
const widthMm = obj.lineWidth ?? layer?.lineWidth ?? FALLBACK_STYLE.widthMm;
|
|
5140
4934
|
return {
|
|
@@ -5142,10 +4936,11 @@ var resolveStyle = (obj, layers, lineTypes) => {
|
|
|
5142
4936
|
widthMm,
|
|
5143
4937
|
// Dash patterns are defined per 1 mm of line width (ISO 128 style —
|
|
5144
4938
|
// pattern legibility tracks stroke weight), so the resolved lineweight
|
|
5145
|
-
// scales them; lineTypeScale (CELTSCALE)
|
|
4939
|
+
// scales them; lineTypeScale (CELTSCALE) and the model scale multiply
|
|
4940
|
+
// on top.
|
|
5146
4941
|
dashMm: scaleDash(
|
|
5147
4942
|
dashForLineType(obj.lineType ?? layer?.lineType, lineTypes),
|
|
5148
|
-
widthMm * (obj.lineTypeScale ?? 1)
|
|
4943
|
+
widthMm * (obj.lineTypeScale ?? 1) * lineTypeScale
|
|
5149
4944
|
),
|
|
5150
4945
|
opacity: obj.opacity ?? layer?.opacity
|
|
5151
4946
|
};
|
|
@@ -5162,7 +4957,7 @@ var rebaseSink = (sink, origin) => {
|
|
|
5162
4957
|
lineTo: (p) => sink.lineTo(at(p)),
|
|
5163
4958
|
bezierTo: (c1, c2, end) => sink.bezierTo(at(c1), at(c2), at(end)),
|
|
5164
4959
|
arc: (center, r, a0, a1, ccw) => sink.arc(at(center), r, a0, a1, ccw),
|
|
5165
|
-
ellipse: (center, rx, ry,
|
|
4960
|
+
ellipse: (center, rx, ry, rot, a0, a1) => sink.ellipse(at(center), rx, ry, rot, a0, a1),
|
|
5166
4961
|
closePath: () => sink.closePath(),
|
|
5167
4962
|
stroke: (s) => sink.stroke(s),
|
|
5168
4963
|
fill: (f) => sink.fill(
|
|
@@ -5250,7 +5045,8 @@ var paintReference = (obj, sink, env) => {
|
|
|
5250
5045
|
const own = resolveStyle(
|
|
5251
5046
|
child,
|
|
5252
5047
|
content.layers,
|
|
5253
|
-
content.lineTypes
|
|
5048
|
+
content.lineTypes,
|
|
5049
|
+
env.lineTypeScale
|
|
5254
5050
|
);
|
|
5255
5051
|
paintObject(child, out, {
|
|
5256
5052
|
// A highlight paints the whole reference in one style.
|
|
@@ -5319,6 +5115,7 @@ var painters = {
|
|
|
5319
5115
|
circle: paintCircle,
|
|
5320
5116
|
arc: paintArc,
|
|
5321
5117
|
ellipse: paintEllipse,
|
|
5118
|
+
spline: paintSpline,
|
|
5322
5119
|
hatch: paintHatch,
|
|
5323
5120
|
text: paintText,
|
|
5324
5121
|
dimension: paintDimension,
|
|
@@ -5344,7 +5141,7 @@ var renderBlockThumbnailSvg = async (script, {
|
|
|
5344
5141
|
} = {}) => {
|
|
5345
5142
|
await ensureScriptTranspiler();
|
|
5346
5143
|
const defId = getBlockMeta(script).id;
|
|
5347
|
-
const inputs = await
|
|
5144
|
+
const { inputs, params } = await dryRunBlockPlacement(script);
|
|
5348
5145
|
const defs = [script];
|
|
5349
5146
|
const present = /* @__PURE__ */ new Set([defId]);
|
|
5350
5147
|
for (const extra of definitions) {
|
|
@@ -5360,7 +5157,7 @@ var renderBlockThumbnailSvg = async (script, {
|
|
|
5360
5157
|
definitionId: defId,
|
|
5361
5158
|
rotation: 0,
|
|
5362
5159
|
scale: 1,
|
|
5363
|
-
params
|
|
5160
|
+
params,
|
|
5364
5161
|
inputs
|
|
5365
5162
|
};
|
|
5366
5163
|
const env = {
|
|
@@ -5526,8 +5323,23 @@ var OptionalMetaSchema = z3.object({
|
|
|
5526
5323
|
version: z3.string().optional(),
|
|
5527
5324
|
authors: z3.array(z3.string()).optional(),
|
|
5528
5325
|
tags: z3.array(z3.string()).optional(),
|
|
5529
|
-
|
|
5326
|
+
requiresEditor: z3.boolean().optional()
|
|
5530
5327
|
});
|
|
5328
|
+
var isInputTable = (inputs) => inputs !== void 0 && inputs.length > 0 && typeof inputs[0] !== "string";
|
|
5329
|
+
var parseCommandInputs = (raw, params) => {
|
|
5330
|
+
if (raw === void 0) return void 0;
|
|
5331
|
+
if (Array.isArray(raw) && raw.every((l) => typeof l === "string")) {
|
|
5332
|
+
if (raw.some((l) => l === ""))
|
|
5333
|
+
throw new Error("Invalid command metadata \u2014 inputs: empty label");
|
|
5334
|
+
return raw;
|
|
5335
|
+
}
|
|
5336
|
+
const table = parseInputTable(raw, params);
|
|
5337
|
+
if (table?.some((d) => d.type === "host"))
|
|
5338
|
+
throw new Error(
|
|
5339
|
+
"Invalid command metadata \u2014 inputs: `host` is a block input (a command has no frame to live in)"
|
|
5340
|
+
);
|
|
5341
|
+
return table;
|
|
5342
|
+
};
|
|
5531
5343
|
var extractCommandMeta = (mod) => {
|
|
5532
5344
|
if (typeof mod.id !== "string" || mod.id.trim() === "")
|
|
5533
5345
|
throw new Error("Command script must export a non-empty string `id`");
|
|
@@ -5541,14 +5353,17 @@ var extractCommandMeta = (mod) => {
|
|
|
5541
5353
|
);
|
|
5542
5354
|
}
|
|
5543
5355
|
const params = parseParamsExport(mod.params);
|
|
5356
|
+
const inputs = parseCommandInputs(mod.inputs, params);
|
|
5544
5357
|
return {
|
|
5545
5358
|
id: mod.id,
|
|
5546
5359
|
name: mod.name,
|
|
5547
5360
|
...parsed.data,
|
|
5361
|
+
...inputs ? { inputs } : {},
|
|
5548
5362
|
...params.length > 0 ? { params } : {}
|
|
5549
5363
|
};
|
|
5550
5364
|
};
|
|
5551
5365
|
var compileCache = /* @__PURE__ */ new Map();
|
|
5366
|
+
onSandboxReset(() => compileCache.clear());
|
|
5552
5367
|
var COMPILE_CACHE_MAX = 100;
|
|
5553
5368
|
var compileCommand = (script) => {
|
|
5554
5369
|
const cached = compileCache.get(script);
|
|
@@ -5557,16 +5372,24 @@ var compileCommand = (script) => {
|
|
|
5557
5372
|
compileCache.set(script, cached);
|
|
5558
5373
|
return cached;
|
|
5559
5374
|
}
|
|
5560
|
-
const mod = executeScriptModule(script);
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5375
|
+
const mod = executeScriptModule(script, "command");
|
|
5376
|
+
let meta;
|
|
5377
|
+
try {
|
|
5378
|
+
meta = extractCommandMeta(mod);
|
|
5379
|
+
if (typeof mod.run !== "function")
|
|
5380
|
+
throw new Error("Command script must export a `run` function");
|
|
5381
|
+
} catch (e) {
|
|
5382
|
+
releaseScriptModule(mod);
|
|
5383
|
+
throw e;
|
|
5384
|
+
}
|
|
5565
5385
|
if (compileCache.size >= COMPILE_CACHE_MAX) {
|
|
5566
5386
|
const oldest = compileCache.keys().next().value;
|
|
5567
|
-
if (oldest !== void 0)
|
|
5387
|
+
if (oldest !== void 0) {
|
|
5388
|
+
releaseScriptModule(compileCache.get(oldest).mod);
|
|
5389
|
+
compileCache.delete(oldest);
|
|
5390
|
+
}
|
|
5568
5391
|
}
|
|
5569
|
-
const compiled = { meta, run };
|
|
5392
|
+
const compiled = { mod, meta, run: mod.run };
|
|
5570
5393
|
compileCache.set(script, compiled);
|
|
5571
5394
|
return compiled;
|
|
5572
5395
|
};
|
|
@@ -5583,16 +5406,11 @@ var getCommandMetaResult = (script) => {
|
|
|
5583
5406
|
};
|
|
5584
5407
|
var listCommandMeta = (scripts) => scripts.map(getCommandMetaResult);
|
|
5585
5408
|
var getCommandRun = (script) => compileCommand(script).run;
|
|
5586
|
-
var ID_EXPORT_RE = /export\s+const\s+id\s*=\s*["']([^"']+)["']/;
|
|
5587
5409
|
var commandScriptId = (script) => {
|
|
5588
5410
|
try {
|
|
5589
5411
|
return compileCommand(script).meta.id;
|
|
5590
5412
|
} catch {
|
|
5591
|
-
|
|
5592
|
-
if (named) return named[1];
|
|
5593
|
-
const call = script.search(/defineCommand\s*\(|export\s+default\s*\{/);
|
|
5594
|
-
if (call === -1) return void 0;
|
|
5595
|
-
return /\bid\s*:\s*["']([^"']+)["']/.exec(script.slice(call))?.[1];
|
|
5413
|
+
return scanScriptId(script, /defineCommand\s*\(|export\s+default\s*\{/);
|
|
5596
5414
|
}
|
|
5597
5415
|
};
|
|
5598
5416
|
var mergeCommandModules = (existing, incoming) => mergeScriptModules(existing, incoming, {
|
|
@@ -6763,12 +6581,19 @@ var renderModelToSvg = (model, opts = {}) => {
|
|
|
6763
6581
|
const origin = far ? { x: bbox.minX, y: bbox.minY } : { x: 0, y: 0 };
|
|
6764
6582
|
const out = rebaseSink(sink, origin);
|
|
6765
6583
|
for (const obj of toPaint) {
|
|
6766
|
-
const
|
|
6584
|
+
const lineTypeScale = opts.lineTypeScale ?? 1;
|
|
6585
|
+
const style = resolveStyle(
|
|
6586
|
+
obj,
|
|
6587
|
+
model.layers,
|
|
6588
|
+
model.lineTypes,
|
|
6589
|
+
lineTypeScale
|
|
6590
|
+
);
|
|
6767
6591
|
sink.beginObject(obj.id, layerName.get(obj.layerId));
|
|
6768
6592
|
paintObject(obj, out, {
|
|
6769
6593
|
style: { ...style, color: mapColor(style.color) },
|
|
6770
6594
|
...model,
|
|
6771
|
-
mapColor
|
|
6595
|
+
mapColor,
|
|
6596
|
+
lineTypeScale
|
|
6772
6597
|
});
|
|
6773
6598
|
sink.endObject();
|
|
6774
6599
|
}
|
|
@@ -6779,7 +6604,12 @@ var renderModelToSvg = (model, opts = {}) => {
|
|
|
6779
6604
|
maxX: bbox.maxX - origin.x,
|
|
6780
6605
|
maxY: bbox.maxY - origin.y
|
|
6781
6606
|
},
|
|
6782
|
-
|
|
6607
|
+
// Default: 2% of the frame (at least 5 mm), so strokes and arrowheads
|
|
6608
|
+
// at the extents aren't cut by the image edge.
|
|
6609
|
+
opts.padding ?? Math.max(
|
|
6610
|
+
5,
|
|
6611
|
+
0.02 * Math.max(bbox.maxX - bbox.minX, bbox.maxY - bbox.minY)
|
|
6612
|
+
)
|
|
6783
6613
|
);
|
|
6784
6614
|
};
|
|
6785
6615
|
var FAR_MM = 1e7;
|
|
@@ -8171,7 +8001,9 @@ var invalidationIds = (op) => {
|
|
|
8171
8001
|
switch (op.type) {
|
|
8172
8002
|
case "add-objects":
|
|
8173
8003
|
case "update-objects":
|
|
8174
|
-
return op.objects.
|
|
8004
|
+
return op.objects.flatMap(
|
|
8005
|
+
(o) => o.type === "block" ? [o.id, ...inputRefs(o.inputs)] : [o.id]
|
|
8006
|
+
);
|
|
8175
8007
|
case "remove-objects":
|
|
8176
8008
|
return op.ids;
|
|
8177
8009
|
case "set-current-layer":
|
|
@@ -8351,17 +8183,188 @@ var DocumentKernel = class {
|
|
|
8351
8183
|
|
|
8352
8184
|
// ../core/src/drawing/localDrawing.ts
|
|
8353
8185
|
import { z as z6 } from "zod";
|
|
8186
|
+
|
|
8187
|
+
// ../core/src/drawing/inputChecks.ts
|
|
8188
|
+
var DrawingError = class extends Error {
|
|
8189
|
+
code;
|
|
8190
|
+
issues;
|
|
8191
|
+
constructor(code, message, issues) {
|
|
8192
|
+
super(message);
|
|
8193
|
+
this.code = code;
|
|
8194
|
+
if (issues) this.issues = issues;
|
|
8195
|
+
}
|
|
8196
|
+
};
|
|
8197
|
+
var MAX_COORDINATE_MM = 1e9;
|
|
8198
|
+
var STYLE_OVERRIDE_KEYS = {
|
|
8199
|
+
text: TextStyleOverrideSchema.shape,
|
|
8200
|
+
table: TextStyleOverrideSchema.shape,
|
|
8201
|
+
dimension: DimStyleOverrideSchema.shape
|
|
8202
|
+
};
|
|
8203
|
+
var hintFor = (type, key) => {
|
|
8204
|
+
if (type && key in (STYLE_OVERRIDE_KEYS[type] ?? {}))
|
|
8205
|
+
return ` \u2014 style keys go in styleOverride: { ${key}: \u2026 }`;
|
|
8206
|
+
if (type === "layer" && key === "hidden") return " \u2014 use visible: false";
|
|
8207
|
+
if (type === "dimension" && (key === "upVector" || key === "linePoint"))
|
|
8208
|
+
return " \u2014 `offset` is the signed distance of the dimension line";
|
|
8209
|
+
if (type === "dimension" && key === "textOverride")
|
|
8210
|
+
return " \u2014 use labels[i].content (with {value} for the measurement)";
|
|
8211
|
+
return "";
|
|
8212
|
+
};
|
|
8213
|
+
var assertNoUnknownKeys = (sent, parsed, context, type) => {
|
|
8214
|
+
const unknown = Object.keys(sent).filter(
|
|
8215
|
+
(k) => sent[k] !== void 0 && !(k in parsed)
|
|
8216
|
+
);
|
|
8217
|
+
if (unknown.length > 0)
|
|
8218
|
+
throw new DrawingError(
|
|
8219
|
+
"unknownField",
|
|
8220
|
+
`${context}: unknown field(s) ${unknown.map((k) => `"${k}"${hintFor(type, k)}`).join(", ")}`
|
|
8221
|
+
);
|
|
8222
|
+
};
|
|
8223
|
+
var assertSaneNumbers = (value, context) => {
|
|
8224
|
+
const walk = (v, path) => {
|
|
8225
|
+
if (typeof v === "number") {
|
|
8226
|
+
if (Math.abs(v) > MAX_COORDINATE_MM)
|
|
8227
|
+
throw new DrawingError(
|
|
8228
|
+
"outOfRange",
|
|
8229
|
+
`${context}: ${path || "value"} = ${v} is out of range (|value| \u2264 ${MAX_COORDINATE_MM} mm)`
|
|
8230
|
+
);
|
|
8231
|
+
} else if (Array.isArray(v)) v.forEach((x, i) => walk(x, `${path}[${i}]`));
|
|
8232
|
+
else if (v !== null && typeof v === "object")
|
|
8233
|
+
for (const [k, x] of Object.entries(v))
|
|
8234
|
+
walk(x, path ? `${path}.${k}` : k);
|
|
8235
|
+
};
|
|
8236
|
+
walk(value, "");
|
|
8237
|
+
};
|
|
8238
|
+
var knownLineType = (name, sources) => resolveLineType(name, sources.lineTypes) !== void 0 || getLineType(name) !== void 0;
|
|
8239
|
+
var knownFont = (font) => (font.includes(";") ? font.slice(0, font.indexOf(";")) : font) in FONTS;
|
|
8240
|
+
var fontList = Object.keys(FONTS).join(", ");
|
|
8241
|
+
var assertLineType = (name, sources, context) => {
|
|
8242
|
+
if (name !== void 0 && !knownLineType(name, sources))
|
|
8243
|
+
throw new DrawingError(
|
|
8244
|
+
"unknownLineType",
|
|
8245
|
+
`${context}: unknown line type "${name}" (the built-in catalogue or linea_list_line_types)`
|
|
8246
|
+
);
|
|
8247
|
+
};
|
|
8248
|
+
var assertFont = (font, context) => {
|
|
8249
|
+
if (typeof font === "string" && !knownFont(font))
|
|
8250
|
+
throw new DrawingError(
|
|
8251
|
+
"unknownFont",
|
|
8252
|
+
`${context}: unknown font "${font}" (one of ${fontList})`
|
|
8253
|
+
);
|
|
8254
|
+
};
|
|
8255
|
+
var assertObjectFields = (obj, fields, sources, context) => {
|
|
8256
|
+
const o = obj;
|
|
8257
|
+
if (fields.has("lineType"))
|
|
8258
|
+
assertLineType(o.lineType, sources, context);
|
|
8259
|
+
if (fields.has("font")) assertFont(o.font, context);
|
|
8260
|
+
if (fields.has("styleOverride"))
|
|
8261
|
+
assertFont(
|
|
8262
|
+
o.styleOverride?.font,
|
|
8263
|
+
context
|
|
8264
|
+
);
|
|
8265
|
+
if (obj.type === "hatch" && fields.has("fill") && obj.fill.kind === "pattern") {
|
|
8266
|
+
if (!resolveHatchPattern(obj.fill.name, sources.hatchPatterns))
|
|
8267
|
+
throw new DrawingError(
|
|
8268
|
+
"unknownHatchPattern",
|
|
8269
|
+
`${context}: unknown hatch pattern "${obj.fill.name}" (the built-in catalogue or linea_list_hatch_patterns)`
|
|
8270
|
+
);
|
|
8271
|
+
}
|
|
8272
|
+
if (obj.type === "text" && (fields.has("spans") || fields.has("content")))
|
|
8273
|
+
for (const [i, s] of (obj.spans ?? []).entries()) {
|
|
8274
|
+
if (s.end > obj.content.length || s.start >= s.end)
|
|
8275
|
+
throw new DrawingError(
|
|
8276
|
+
"invalidSpan",
|
|
8277
|
+
`${context}: spans[${i}] ${s.start}\u2013${s.end} must satisfy start < end \u2264 ${obj.content.length} (the content's length)`
|
|
8278
|
+
);
|
|
8279
|
+
assertFont(s.font, `${context}: spans[${i}]`);
|
|
8280
|
+
}
|
|
8281
|
+
if (obj.type === "block" && fields.has("params"))
|
|
8282
|
+
assertBlockParams(obj, sources, context);
|
|
8283
|
+
};
|
|
8284
|
+
var assertBlockParams = (obj, sources, context) => {
|
|
8285
|
+
let script;
|
|
8286
|
+
try {
|
|
8287
|
+
script = findBlockScript(sources.blockDefinitions, obj.definitionId);
|
|
8288
|
+
} catch {
|
|
8289
|
+
return;
|
|
8290
|
+
}
|
|
8291
|
+
if (!script) return;
|
|
8292
|
+
const meta = getBlockMetaResult(script);
|
|
8293
|
+
if (!meta.ok) return;
|
|
8294
|
+
const defs = valueParams(meta.meta.params);
|
|
8295
|
+
for (const [name, value] of Object.entries(obj.params ?? {})) {
|
|
8296
|
+
const def = defs.find((d) => d.name === name);
|
|
8297
|
+
if (!def)
|
|
8298
|
+
throw new DrawingError(
|
|
8299
|
+
"invalidParam",
|
|
8300
|
+
`${context}: block "${obj.definitionId}" has no parameter "${name}"${defs.length ? ` (declares ${defs.map((d) => d.name).join(", ")})` : ""}`
|
|
8301
|
+
);
|
|
8302
|
+
const mismatch = paramMismatch(def, value);
|
|
8303
|
+
if (mismatch)
|
|
8304
|
+
throw new DrawingError(
|
|
8305
|
+
"invalidParam",
|
|
8306
|
+
`${context}: parameter "${name}" \u2014 ${mismatch}`
|
|
8307
|
+
);
|
|
8308
|
+
}
|
|
8309
|
+
};
|
|
8310
|
+
|
|
8311
|
+
// ../core/src/drawing/localDrawing.ts
|
|
8354
8312
|
var toVec = (p) => Vec2Schema.parse(p);
|
|
8313
|
+
var refuseRejected = (report, kind) => {
|
|
8314
|
+
if (report.rejected.length === 0) return;
|
|
8315
|
+
const lines = report.rejected.map(
|
|
8316
|
+
(r, i) => `${i + 1}) ${scanScriptId(r.script, /define(Block|Command)\(|export\s+default\s*\{/) ?? "(no id)"}: ${r.error}`
|
|
8317
|
+
);
|
|
8318
|
+
throw Object.assign(
|
|
8319
|
+
new Error(
|
|
8320
|
+
`${report.rejected.length} ${kind} source(s) rejected, so none were added:
|
|
8321
|
+
${lines.join("\n")}`
|
|
8322
|
+
),
|
|
8323
|
+
{ code: "moduleRejected" }
|
|
8324
|
+
);
|
|
8325
|
+
};
|
|
8326
|
+
var checkedStyle = (schema, full, sent, context) => {
|
|
8327
|
+
let style;
|
|
8328
|
+
try {
|
|
8329
|
+
style = schema.parse(full);
|
|
8330
|
+
} catch (e) {
|
|
8331
|
+
throw wrapZod(e, context);
|
|
8332
|
+
}
|
|
8333
|
+
assertNoUnknownKeys(sent, style, context);
|
|
8334
|
+
if ("font" in sent) assertFont(sent.font, context);
|
|
8335
|
+
return style;
|
|
8336
|
+
};
|
|
8337
|
+
var assertDataUrl = (dataUrl) => {
|
|
8338
|
+
const m = /^data:([\w.+-]+\/[\w.+-]+)(;[^,]*)?;base64,([A-Za-z0-9+/]*={0,2})$/.exec(
|
|
8339
|
+
dataUrl
|
|
8340
|
+
);
|
|
8341
|
+
if (!m)
|
|
8342
|
+
throw new DrawingError(
|
|
8343
|
+
"invalidAsset",
|
|
8344
|
+
"An asset must be a base64 data URL (data:<type>;base64,...)"
|
|
8345
|
+
);
|
|
8346
|
+
const bytes = Math.floor(m[3].length * 3 / 4) - (m[3].match(/=/g)?.length ?? 0);
|
|
8347
|
+
if (bytes < 16)
|
|
8348
|
+
throw new DrawingError(
|
|
8349
|
+
"invalidAsset",
|
|
8350
|
+
`The ${m[1]} data URL holds only ${bytes} bytes, not a real file`
|
|
8351
|
+
);
|
|
8352
|
+
};
|
|
8353
|
+
var MAX_COPIES = 1e4;
|
|
8355
8354
|
var wrapZod = (e, context) => {
|
|
8356
8355
|
if (!(e instanceof z6.ZodError))
|
|
8357
8356
|
return e instanceof Error ? e : new Error(String(e));
|
|
8358
|
-
return new
|
|
8357
|
+
return new DrawingError(
|
|
8358
|
+
"validation",
|
|
8359
|
+
`${context}: ${z6.prettifyError(e)}`,
|
|
8360
|
+
e.issues
|
|
8361
|
+
);
|
|
8359
8362
|
};
|
|
8360
8363
|
var PDF_PAGE_GAP_MM = 50;
|
|
8361
8364
|
var selectPdfLayouts = (layouts, opts, fallback) => {
|
|
8362
8365
|
const byRef = (ref) => {
|
|
8363
8366
|
const l = layouts.find((x) => x.name === ref || x.id === ref);
|
|
8364
|
-
if (!l) throw new
|
|
8367
|
+
if (!l) throw new DrawingError("unknownLayout", `Unknown layout "${ref}"`);
|
|
8365
8368
|
return l;
|
|
8366
8369
|
};
|
|
8367
8370
|
let selected = opts.layouts !== void 0 ? opts.layouts.map(byRef) : layouts.length > 0 ? [...layouts] : [fallback()];
|
|
@@ -8468,11 +8471,6 @@ var kernelHooks = (doc) => {
|
|
|
8468
8471
|
revision: () => rev
|
|
8469
8472
|
};
|
|
8470
8473
|
};
|
|
8471
|
-
var withVisible = (layer) => {
|
|
8472
|
-
const { hidden, ...rest } = layer;
|
|
8473
|
-
if (hidden === void 0) return layer;
|
|
8474
|
-
return { ...rest, visible: !hidden };
|
|
8475
|
-
};
|
|
8476
8474
|
var LocalDrawing = class {
|
|
8477
8475
|
hooks;
|
|
8478
8476
|
/** Schema-version migration applied on open; null when none was needed. */
|
|
@@ -8528,7 +8526,7 @@ var LocalDrawing = class {
|
|
|
8528
8526
|
findObject(id) {
|
|
8529
8527
|
const doc = this.state;
|
|
8530
8528
|
const obj = resolveDocumentObject(doc, id);
|
|
8531
|
-
if (!obj) throw new
|
|
8529
|
+
if (!obj) throw new DrawingError("unknownObject", `Unknown object "${id}"`);
|
|
8532
8530
|
const layout = doc.layouts.find((l) => l.objects.includes(obj));
|
|
8533
8531
|
return { obj, space: layout ? { layoutId: layout.id } : "model" };
|
|
8534
8532
|
}
|
|
@@ -8610,8 +8608,11 @@ var LocalDrawing = class {
|
|
|
8610
8608
|
(l) => l.name.toLowerCase() === layer.name.toLowerCase()
|
|
8611
8609
|
);
|
|
8612
8610
|
if (clash)
|
|
8613
|
-
throw new
|
|
8614
|
-
|
|
8611
|
+
throw new DrawingError(
|
|
8612
|
+
"duplicateName",
|
|
8613
|
+
`Layer "${clash.name}" already exists`
|
|
8614
|
+
);
|
|
8615
|
+
const full = this.checkedLayer(layer, layer, "add layer");
|
|
8615
8616
|
this.applyForward({ type: "add-layer", layer: full });
|
|
8616
8617
|
return full.id;
|
|
8617
8618
|
}
|
|
@@ -8619,7 +8620,8 @@ var LocalDrawing = class {
|
|
|
8619
8620
|
const l = this.state.layers.find(
|
|
8620
8621
|
(x) => x.id === nameOrId || x.name === nameOrId
|
|
8621
8622
|
);
|
|
8622
|
-
if (!l)
|
|
8623
|
+
if (!l)
|
|
8624
|
+
throw new DrawingError("unknownLayer", `Unknown layer "${nameOrId}"`);
|
|
8623
8625
|
return l;
|
|
8624
8626
|
}
|
|
8625
8627
|
/** Patch a layer (rename, color, lineWidth, visible, locked) by name or id. */
|
|
@@ -8630,13 +8632,36 @@ var LocalDrawing = class {
|
|
|
8630
8632
|
(l) => l.name.toLowerCase() === patch.name.toLowerCase()
|
|
8631
8633
|
);
|
|
8632
8634
|
if (clash)
|
|
8633
|
-
throw new
|
|
8635
|
+
throw new DrawingError(
|
|
8636
|
+
"duplicateName",
|
|
8637
|
+
`Layer "${clash.name}" already exists`
|
|
8638
|
+
);
|
|
8634
8639
|
}
|
|
8635
8640
|
this.applyForward({
|
|
8636
8641
|
type: "update-layer",
|
|
8637
|
-
layer:
|
|
8642
|
+
layer: this.checkedLayer(
|
|
8643
|
+
{ ...cur, ...patch, id: cur.id },
|
|
8644
|
+
patch,
|
|
8645
|
+
`update layer "${cur.name}"`
|
|
8646
|
+
)
|
|
8638
8647
|
});
|
|
8639
8648
|
}
|
|
8649
|
+
/** A layer parsed from `full`, refusing an empty name, unknown fields
|
|
8650
|
+
* and an unknown line type among what the caller `sent`. */
|
|
8651
|
+
checkedLayer(full, sent, context) {
|
|
8652
|
+
if (typeof sent.name === "string" && sent.name.trim() === "")
|
|
8653
|
+
throw new DrawingError("validation", `${context}: the name is empty`);
|
|
8654
|
+
let layer;
|
|
8655
|
+
try {
|
|
8656
|
+
layer = LayerSchema.parse(full);
|
|
8657
|
+
} catch (e) {
|
|
8658
|
+
throw wrapZod(e, context);
|
|
8659
|
+
}
|
|
8660
|
+
assertNoUnknownKeys(sent, layer, context, "layer");
|
|
8661
|
+
if ("lineType" in sent)
|
|
8662
|
+
assertLineType(layer.lineType, this.nameSources, context);
|
|
8663
|
+
return layer;
|
|
8664
|
+
}
|
|
8640
8665
|
/** Remove an EMPTY, non-current layer (the kernel refuses otherwise). */
|
|
8641
8666
|
removeLayer(nameOrId) {
|
|
8642
8667
|
this.applyForward({
|
|
@@ -8671,6 +8696,7 @@ var LocalDrawing = class {
|
|
|
8671
8696
|
* Content-keyed: the same data reuses one entry.
|
|
8672
8697
|
*/
|
|
8673
8698
|
addAsset(dataUrl) {
|
|
8699
|
+
assertDataUrl(dataUrl);
|
|
8674
8700
|
const id = hashAsset(dataUrl);
|
|
8675
8701
|
if (this.state.assets[id] !== dataUrl)
|
|
8676
8702
|
this.applyForward({ type: "set-asset", id, dataUrl });
|
|
@@ -8778,25 +8804,32 @@ var LocalDrawing = class {
|
|
|
8778
8804
|
// (case-insensitive) on add and rename.
|
|
8779
8805
|
resolveStyle(styles, nameOrId, what) {
|
|
8780
8806
|
const s = styles.find((x) => x.id === nameOrId || x.name === nameOrId);
|
|
8781
|
-
if (!s)
|
|
8807
|
+
if (!s)
|
|
8808
|
+
throw new DrawingError("unknownStyle", `Unknown ${what} "${nameOrId}"`);
|
|
8782
8809
|
return s;
|
|
8783
8810
|
}
|
|
8784
|
-
assertStyleName(styles, name,
|
|
8811
|
+
assertStyleName(styles, name, except) {
|
|
8785
8812
|
const clash = styles.find(
|
|
8786
8813
|
(s) => s.id !== except && s.name.toLowerCase() === name.toLowerCase()
|
|
8787
8814
|
);
|
|
8788
8815
|
if (clash)
|
|
8789
|
-
throw new
|
|
8816
|
+
throw new DrawingError(
|
|
8817
|
+
"duplicateName",
|
|
8818
|
+
`Style "${clash.name}" already exists`
|
|
8819
|
+
);
|
|
8790
8820
|
}
|
|
8791
8821
|
/** Layouts are addressed by name everywhere (`layout` on the object
|
|
8792
8822
|
* tools, remove, reorder, render) — a duplicate would silently resolve to
|
|
8793
8823
|
* the first match. */
|
|
8794
|
-
assertLayoutName(name,
|
|
8824
|
+
assertLayoutName(name, except) {
|
|
8795
8825
|
const clash = this.state.layouts.find(
|
|
8796
8826
|
(l) => l.id !== except && l.name.toLowerCase() === name.toLowerCase()
|
|
8797
8827
|
);
|
|
8798
8828
|
if (clash)
|
|
8799
|
-
throw new
|
|
8829
|
+
throw new DrawingError(
|
|
8830
|
+
"duplicateName",
|
|
8831
|
+
`Layout "${clash.name}" already exists`
|
|
8832
|
+
);
|
|
8800
8833
|
}
|
|
8801
8834
|
/** Objects reference styles by id, but callers often pass the NAME:
|
|
8802
8835
|
* resolve it (text/table → text styles, dimension → dim styles). An
|
|
@@ -8808,7 +8841,8 @@ var LocalDrawing = class {
|
|
|
8808
8841
|
if (!styles) return {};
|
|
8809
8842
|
const s = styles.find((x) => x.id === obj.styleId) ?? styles.find((x) => x.name === obj.styleId);
|
|
8810
8843
|
if (!s)
|
|
8811
|
-
throw new
|
|
8844
|
+
throw new DrawingError(
|
|
8845
|
+
"unknownStyle",
|
|
8812
8846
|
`${context}: unknown ${obj.type === "dimension" ? "dim" : "text"} style "${obj.styleId}"`
|
|
8813
8847
|
);
|
|
8814
8848
|
return { styleId: s.id };
|
|
@@ -8822,8 +8856,8 @@ var LocalDrawing = class {
|
|
|
8822
8856
|
/** Create a text style (unique name; unset fields take the defaults);
|
|
8823
8857
|
* returns its id. */
|
|
8824
8858
|
addTextStyle(props) {
|
|
8825
|
-
this.assertStyleName(this.state.textStyles, props.name
|
|
8826
|
-
const style = TextStyleSchema
|
|
8859
|
+
this.assertStyleName(this.state.textStyles, props.name);
|
|
8860
|
+
const style = checkedStyle(TextStyleSchema, props, props, "add text style");
|
|
8827
8861
|
this.applyForward({ type: "add-text-style", style });
|
|
8828
8862
|
return style.id;
|
|
8829
8863
|
}
|
|
@@ -8834,15 +8868,15 @@ var LocalDrawing = class {
|
|
|
8834
8868
|
"text style"
|
|
8835
8869
|
);
|
|
8836
8870
|
if (patch.name !== void 0)
|
|
8837
|
-
this.assertStyleName(
|
|
8838
|
-
this.state.textStyles,
|
|
8839
|
-
patch.name,
|
|
8840
|
-
"updateTextStyle()",
|
|
8841
|
-
cur.id
|
|
8842
|
-
);
|
|
8871
|
+
this.assertStyleName(this.state.textStyles, patch.name, cur.id);
|
|
8843
8872
|
this.applyForward({
|
|
8844
8873
|
type: "update-text-style",
|
|
8845
|
-
style:
|
|
8874
|
+
style: checkedStyle(
|
|
8875
|
+
TextStyleSchema,
|
|
8876
|
+
{ ...cur, ...patch, id: cur.id },
|
|
8877
|
+
patch,
|
|
8878
|
+
`update text style "${cur.name}"`
|
|
8879
|
+
)
|
|
8846
8880
|
});
|
|
8847
8881
|
}
|
|
8848
8882
|
// --- line types / hatch patterns (name-keyed definitions) -----------------
|
|
@@ -8861,7 +8895,8 @@ var LocalDrawing = class {
|
|
|
8861
8895
|
const cur = this.state.lineTypes.find(
|
|
8862
8896
|
(t) => lineTypeKey(t.name) === lineTypeKey(name)
|
|
8863
8897
|
);
|
|
8864
|
-
if (!cur)
|
|
8898
|
+
if (!cur)
|
|
8899
|
+
throw new DrawingError("unknownLineType", `Unknown line type "${name}"`);
|
|
8865
8900
|
const next = LineTypeSchema.parse({ ...cur, ...patch });
|
|
8866
8901
|
if (lineTypeKey(next.name) !== lineTypeKey(cur.name)) {
|
|
8867
8902
|
this.transaction(() => {
|
|
@@ -8888,7 +8923,11 @@ var LocalDrawing = class {
|
|
|
8888
8923
|
const cur = this.state.hatchPatterns.find(
|
|
8889
8924
|
(p) => hatchPatternKey(p.name) === hatchPatternKey(name)
|
|
8890
8925
|
);
|
|
8891
|
-
if (!cur)
|
|
8926
|
+
if (!cur)
|
|
8927
|
+
throw new DrawingError(
|
|
8928
|
+
"unknownHatchPattern",
|
|
8929
|
+
`Unknown hatch pattern "${name}"`
|
|
8930
|
+
);
|
|
8892
8931
|
const next = HatchPatternSchema.parse({ ...cur, ...patch });
|
|
8893
8932
|
if (hatchPatternKey(next.name) !== hatchPatternKey(cur.name)) {
|
|
8894
8933
|
this.transaction(() => {
|
|
@@ -8911,23 +8950,23 @@ var LocalDrawing = class {
|
|
|
8911
8950
|
/** Create a dimension style (unique name; unset fields take the
|
|
8912
8951
|
* defaults); returns its id. */
|
|
8913
8952
|
addDimStyle(props) {
|
|
8914
|
-
this.assertStyleName(this.state.dimStyles, props.name
|
|
8915
|
-
const style = DimStyleSchema
|
|
8953
|
+
this.assertStyleName(this.state.dimStyles, props.name);
|
|
8954
|
+
const style = checkedStyle(DimStyleSchema, props, props, "add dim style");
|
|
8916
8955
|
this.applyForward({ type: "add-dim-style", style });
|
|
8917
8956
|
return style.id;
|
|
8918
8957
|
}
|
|
8919
8958
|
updateDimStyle(nameOrId, patch) {
|
|
8920
8959
|
const cur = this.resolveStyle(this.state.dimStyles, nameOrId, "dim style");
|
|
8921
8960
|
if (patch.name !== void 0)
|
|
8922
|
-
this.assertStyleName(
|
|
8923
|
-
this.state.dimStyles,
|
|
8924
|
-
patch.name,
|
|
8925
|
-
"updateDimStyle()",
|
|
8926
|
-
cur.id
|
|
8927
|
-
);
|
|
8961
|
+
this.assertStyleName(this.state.dimStyles, patch.name, cur.id);
|
|
8928
8962
|
this.applyForward({
|
|
8929
8963
|
type: "update-dim-style",
|
|
8930
|
-
style:
|
|
8964
|
+
style: checkedStyle(
|
|
8965
|
+
DimStyleSchema,
|
|
8966
|
+
{ ...cur, ...patch, id: cur.id },
|
|
8967
|
+
patch,
|
|
8968
|
+
`update dim style "${cur.name}"`
|
|
8969
|
+
)
|
|
8931
8970
|
});
|
|
8932
8971
|
}
|
|
8933
8972
|
/** Remove a dimension style no dimension uses (the kernel refuses
|
|
@@ -9003,6 +9042,7 @@ var LocalDrawing = class {
|
|
|
9003
9042
|
async addBlockDefinitions(sources) {
|
|
9004
9043
|
await ensureScriptTranspiler();
|
|
9005
9044
|
const report = mergeBlockModules(this.state.blockDefinitions, sources);
|
|
9045
|
+
refuseRejected(report, "block definition");
|
|
9006
9046
|
this.applyForwardAll(
|
|
9007
9047
|
diffModuleOps(
|
|
9008
9048
|
this.state.blockDefinitions,
|
|
@@ -9015,6 +9055,7 @@ var LocalDrawing = class {
|
|
|
9015
9055
|
async addUserCommands(sources) {
|
|
9016
9056
|
await ensureScriptTranspiler();
|
|
9017
9057
|
const report = mergeCommandModules(this.state.commands, sources);
|
|
9058
|
+
refuseRejected(report, "user command");
|
|
9018
9059
|
this.applyForwardAll(
|
|
9019
9060
|
diffModuleOps(this.state.commands, report.merged, "commands")
|
|
9020
9061
|
);
|
|
@@ -9104,7 +9145,6 @@ var LocalDrawing = class {
|
|
|
9104
9145
|
};
|
|
9105
9146
|
for (const plan of plans) {
|
|
9106
9147
|
const r = plan.kind === "block" ? await this.addBlockDefinitions(plan.sources) : await this.addUserCommands(plan.sources);
|
|
9107
|
-
if (r.rejected.length > 0) throw new Error(r.rejected[0].error);
|
|
9108
9148
|
report.merged = r.merged;
|
|
9109
9149
|
report.added.push(...r.added);
|
|
9110
9150
|
report.replaced.push(...r.replaced);
|
|
@@ -9118,7 +9158,8 @@ var LocalDrawing = class {
|
|
|
9118
9158
|
const source = this.state.blockDefinitions.find(
|
|
9119
9159
|
(s) => listBlockMeta([s]).some((r) => r.ok && r.meta.id === id)
|
|
9120
9160
|
);
|
|
9121
|
-
if (source === void 0)
|
|
9161
|
+
if (source === void 0)
|
|
9162
|
+
throw new DrawingError("unknownBlock", `Unknown block "${id}"`);
|
|
9122
9163
|
this.applyForward({ type: "remove-block-definition", source });
|
|
9123
9164
|
}
|
|
9124
9165
|
/** Remove a command module by its exported id (unknown id → error). */
|
|
@@ -9126,7 +9167,8 @@ var LocalDrawing = class {
|
|
|
9126
9167
|
const source = this.state.commands.find(
|
|
9127
9168
|
(s) => listCommandMeta([s]).some((r) => r.ok && r.meta.id === id)
|
|
9128
9169
|
);
|
|
9129
|
-
if (source === void 0)
|
|
9170
|
+
if (source === void 0)
|
|
9171
|
+
throw new DrawingError("unknownCommand", `Unknown command "${id}"`);
|
|
9130
9172
|
this.applyForward({ type: "remove-document-command", source });
|
|
9131
9173
|
}
|
|
9132
9174
|
/**
|
|
@@ -9202,7 +9244,7 @@ var LocalDrawing = class {
|
|
|
9202
9244
|
* to the model extents. Returns the layout id.
|
|
9203
9245
|
*/
|
|
9204
9246
|
addLayout(name, opts = {}) {
|
|
9205
|
-
this.assertLayoutName(name
|
|
9247
|
+
this.assertLayoutName(name);
|
|
9206
9248
|
const layout = this.makeLayout(name, opts);
|
|
9207
9249
|
this.applyForward({ type: "add-layout", layout, index: opts.index });
|
|
9208
9250
|
return layout.id;
|
|
@@ -9225,8 +9267,7 @@ var LocalDrawing = class {
|
|
|
9225
9267
|
/** Patch a layout's name / sheet (preset or mm) / print palette. */
|
|
9226
9268
|
updateLayout(nameOrId, patch) {
|
|
9227
9269
|
const layout = this.resolveLayout(nameOrId);
|
|
9228
|
-
if (patch.name !== void 0)
|
|
9229
|
-
this.assertLayoutName(patch.name, "updateLayout()", layout.id);
|
|
9270
|
+
if (patch.name !== void 0) this.assertLayoutName(patch.name, layout.id);
|
|
9230
9271
|
const { sheet, ...rest } = patch;
|
|
9231
9272
|
this.applyForward({
|
|
9232
9273
|
type: "update-layout-meta",
|
|
@@ -9236,6 +9277,14 @@ var LocalDrawing = class {
|
|
|
9236
9277
|
});
|
|
9237
9278
|
}
|
|
9238
9279
|
// --- object mutations ----------------------------------------------------
|
|
9280
|
+
/** What names in a new or changed object must resolve against. */
|
|
9281
|
+
get nameSources() {
|
|
9282
|
+
return {
|
|
9283
|
+
lineTypes: this.state.lineTypes,
|
|
9284
|
+
hatchPatterns: this.state.hatchPatterns,
|
|
9285
|
+
blockDefinitions: this.state.blockDefinitions
|
|
9286
|
+
};
|
|
9287
|
+
}
|
|
9239
9288
|
normalize(input, index) {
|
|
9240
9289
|
const { layer, layerId, id, ...rest } = input;
|
|
9241
9290
|
const context = `add(): objects[${index ?? 0}] (${String(input.type ?? "?")})`;
|
|
@@ -9248,9 +9297,16 @@ var LocalDrawing = class {
|
|
|
9248
9297
|
layerId: this.resolveLayerId(layer, layerId),
|
|
9249
9298
|
id: id ?? crypto.randomUUID()
|
|
9250
9299
|
};
|
|
9251
|
-
|
|
9252
|
-
|
|
9300
|
+
const obj = ModelObjectSchema.parse(raw);
|
|
9301
|
+
assertNoUnknownKeys(raw, obj, context, obj.type);
|
|
9302
|
+
assertSaneNumbers(obj, context);
|
|
9303
|
+
assertObjectFields(
|
|
9304
|
+
obj,
|
|
9305
|
+
new Set(Object.keys(rest)),
|
|
9306
|
+
this.nameSources,
|
|
9307
|
+
context
|
|
9253
9308
|
);
|
|
9309
|
+
return obj;
|
|
9254
9310
|
} catch (e) {
|
|
9255
9311
|
throw wrapZod(
|
|
9256
9312
|
e,
|
|
@@ -9282,18 +9338,25 @@ var LocalDrawing = class {
|
|
|
9282
9338
|
`update(): "${id}" (${cur.type})`
|
|
9283
9339
|
) : {};
|
|
9284
9340
|
const staleSpans = cur.type === "text" && "content" in rest && !("spans" in rest) ? { spans: void 0 } : {};
|
|
9341
|
+
const context = `update(): "${id}" (${cur.type})`;
|
|
9285
9342
|
try {
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9343
|
+
const obj = ModelObjectSchema.parse({
|
|
9344
|
+
...cur,
|
|
9345
|
+
...rest,
|
|
9346
|
+
...staleSpans,
|
|
9347
|
+
...styleRef,
|
|
9348
|
+
...resolvedLayerId ? { layerId: resolvedLayerId } : {},
|
|
9349
|
+
id
|
|
9350
|
+
});
|
|
9351
|
+
assertNoUnknownKeys(rest, obj, context, cur.type);
|
|
9352
|
+
assertSaneNumbers(rest, context);
|
|
9353
|
+
assertObjectFields(
|
|
9354
|
+
obj,
|
|
9355
|
+
new Set(Object.keys(rest)),
|
|
9356
|
+
this.nameSources,
|
|
9357
|
+
context
|
|
9358
|
+
);
|
|
9359
|
+
return { space, obj };
|
|
9297
9360
|
} catch (e) {
|
|
9298
9361
|
throw wrapZod(e, `update(): "${id}" (${cur.type})`);
|
|
9299
9362
|
}
|
|
@@ -9312,7 +9375,12 @@ var LocalDrawing = class {
|
|
|
9312
9375
|
/** Delete objects by id (unknown ids are skipped); returns how many went. */
|
|
9313
9376
|
remove(ids) {
|
|
9314
9377
|
const entries = [];
|
|
9315
|
-
|
|
9378
|
+
const all = hostedClosure(
|
|
9379
|
+
ids,
|
|
9380
|
+
this.state.blockDefinitions,
|
|
9381
|
+
documentBlocks(this.state)
|
|
9382
|
+
);
|
|
9383
|
+
for (const id of all) {
|
|
9316
9384
|
try {
|
|
9317
9385
|
entries.push({ space: this.findObject(id).space, item: id });
|
|
9318
9386
|
} catch {
|
|
@@ -9397,22 +9465,50 @@ var LocalDrawing = class {
|
|
|
9397
9465
|
mirror(ids, a, b) {
|
|
9398
9466
|
const pa = toVec(a);
|
|
9399
9467
|
const pb = toVec(b);
|
|
9468
|
+
if (pa.x === pb.x && pa.y === pb.y)
|
|
9469
|
+
throw new DrawingError(
|
|
9470
|
+
"validation",
|
|
9471
|
+
"Mirror needs two different points for its axis"
|
|
9472
|
+
);
|
|
9400
9473
|
this.transformEach(ids, (o) => mirrorObject(o, pa, pb));
|
|
9401
9474
|
}
|
|
9402
9475
|
/** Duplicate objects (into their own space) displaced by `delta`. */
|
|
9403
9476
|
copy(ids, delta) {
|
|
9404
|
-
|
|
9477
|
+
return this.copySteps(ids, [toVec(delta)]);
|
|
9478
|
+
}
|
|
9479
|
+
/**
|
|
9480
|
+
* Linear array: `count` TOTAL instances (including the originals) stepped
|
|
9481
|
+
* by `delta`. Returns the new ids, one batch per step, in one undo step.
|
|
9482
|
+
*/
|
|
9483
|
+
array(ids, count, delta) {
|
|
9484
|
+
if (!Number.isInteger(count) || count < 1)
|
|
9485
|
+
throw new Error(`Invalid array count ${count}`);
|
|
9405
9486
|
const d = toVec(delta);
|
|
9406
|
-
const
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9487
|
+
const steps = Array.from({ length: count - 1 }, (_, i) => ({
|
|
9488
|
+
x: d.x * (i + 1),
|
|
9489
|
+
y: d.y * (i + 1)
|
|
9490
|
+
}));
|
|
9491
|
+
return this.copySteps(ids, steps);
|
|
9492
|
+
}
|
|
9493
|
+
/** One displaced copy of `ids` per step, applied as ONE add op per space
|
|
9494
|
+
* (an op per step re-copied the whole space each time: quadratic). */
|
|
9495
|
+
copySteps(ids, steps) {
|
|
9496
|
+
if (ids.length === 0 || steps.length === 0) return [];
|
|
9497
|
+
const total2 = ids.length * steps.length;
|
|
9498
|
+
if (total2 > MAX_COPIES)
|
|
9499
|
+
throw new Error(
|
|
9500
|
+
`That would create ${total2} objects; one copy or array makes at most ${MAX_COPIES}.`
|
|
9501
|
+
);
|
|
9502
|
+
const sources = ids.map((id) => this.findObject(id));
|
|
9503
|
+
const clones = steps.flatMap((d) => {
|
|
9504
|
+
const idMap = new Map(ids.map((id) => [id, crypto.randomUUID()]));
|
|
9505
|
+
return sources.map(({ obj, space }) => ({
|
|
9410
9506
|
space,
|
|
9411
9507
|
obj: ModelObjectSchema.parse({
|
|
9412
9508
|
...remapBlockInputRefs(translateObject(obj, d), idMap),
|
|
9413
|
-
id: idMap.get(id)
|
|
9509
|
+
id: idMap.get(obj.id)
|
|
9414
9510
|
})
|
|
9415
|
-
};
|
|
9511
|
+
}));
|
|
9416
9512
|
});
|
|
9417
9513
|
this.applyBySpace(clones, (space, objects) => ({
|
|
9418
9514
|
type: "add-objects",
|
|
@@ -9421,21 +9517,6 @@ var LocalDrawing = class {
|
|
|
9421
9517
|
}));
|
|
9422
9518
|
return clones.map((c) => c.obj.id);
|
|
9423
9519
|
}
|
|
9424
|
-
/**
|
|
9425
|
-
* Linear array: `count` TOTAL instances (including the originals) stepped
|
|
9426
|
-
* by `delta`. Returns the new ids, one batch per step, in one undo step.
|
|
9427
|
-
*/
|
|
9428
|
-
array(ids, count, delta) {
|
|
9429
|
-
if (!Number.isInteger(count) || count < 1)
|
|
9430
|
-
throw new Error(`Invalid array count ${count}`);
|
|
9431
|
-
const d = toVec(delta);
|
|
9432
|
-
return this.transaction(() => {
|
|
9433
|
-
const created = [];
|
|
9434
|
-
for (let i = 1; i < count; i++)
|
|
9435
|
-
created.push(...this.copy(ids, { x: d.x * i, y: d.y * i }));
|
|
9436
|
-
return created;
|
|
9437
|
-
});
|
|
9438
|
-
}
|
|
9439
9520
|
// --- reads ---------------------------------------------------------------
|
|
9440
9521
|
get measurer() {
|
|
9441
9522
|
return this.hooks.measure ?? approximateTextMeasurer;
|
|
@@ -9599,7 +9680,8 @@ var LocalDrawing = class {
|
|
|
9599
9680
|
const layout = this.state.layouts.find(
|
|
9600
9681
|
(l) => l.name === nameOrId || l.id === nameOrId
|
|
9601
9682
|
);
|
|
9602
|
-
if (!layout)
|
|
9683
|
+
if (!layout)
|
|
9684
|
+
throw new DrawingError("unknownLayout", `Unknown layout "${nameOrId}"`);
|
|
9603
9685
|
return layout;
|
|
9604
9686
|
}
|
|
9605
9687
|
/** Render model space (or a paper layout via `layout`) to an SVG string. */
|
|
@@ -9610,11 +9692,18 @@ var LocalDrawing = class {
|
|
|
9610
9692
|
this.paintContext(),
|
|
9611
9693
|
opts
|
|
9612
9694
|
);
|
|
9613
|
-
return renderModelToSvg(this.paintContext(),
|
|
9695
|
+
return renderModelToSvg(this.paintContext(), {
|
|
9696
|
+
lineTypeScale: this.document.settings.modelScale,
|
|
9697
|
+
// Model lineweights are true mm: on a building-sized drawing they
|
|
9698
|
+
// rasterize sub-pixel and read as a blank sheet. Keep every stroke
|
|
9699
|
+
// ≥ ~1.5 px at the output width (PNG) or a 1024 px view (SVG).
|
|
9700
|
+
minStrokeFrac: 1.5 / (opts.width ?? 1024),
|
|
9701
|
+
...opts
|
|
9702
|
+
});
|
|
9614
9703
|
}
|
|
9615
9704
|
/** Export the document to a DXF string. */
|
|
9616
9705
|
async toDxf() {
|
|
9617
|
-
const { buildDxf } = await import("./exportDxf-
|
|
9706
|
+
const { buildDxf } = await import("./exportDxf-6XTXQ4XN.js");
|
|
9618
9707
|
return buildDxf(this.state, this.measurer).content;
|
|
9619
9708
|
}
|
|
9620
9709
|
/** Export the document to DWG bytes (the DXF content, wasm-transcoded).
|
|
@@ -9623,7 +9712,7 @@ var LocalDrawing = class {
|
|
|
9623
9712
|
* exploded to plain geometry (DWG_DXF_OPTIONS — the transcoder's DWG
|
|
9624
9713
|
* output for them is not accepted by AutoCAD). */
|
|
9625
9714
|
async toDwg(opts) {
|
|
9626
|
-
const { buildDxf, DWG_DXF_OPTIONS } = await import("./exportDxf-
|
|
9715
|
+
const { buildDxf, DWG_DXF_OPTIONS } = await import("./exportDxf-6XTXQ4XN.js");
|
|
9627
9716
|
const dxf = buildDxf(this.state, this.measurer, DWG_DXF_OPTIONS).content;
|
|
9628
9717
|
return dxfToDwg(dxf, opts?.version ?? "AC1027");
|
|
9629
9718
|
}
|
|
@@ -9642,46 +9731,6 @@ var makeContext = (opts, inputs, params) => {
|
|
|
9642
9731
|
params
|
|
9643
9732
|
};
|
|
9644
9733
|
};
|
|
9645
|
-
var paramMismatch = (def, value) => {
|
|
9646
|
-
switch (def.type) {
|
|
9647
|
-
case "number":
|
|
9648
|
-
if (typeof value !== "number" || !Number.isFinite(value))
|
|
9649
|
-
return "expected a number";
|
|
9650
|
-
if (def.integer && !Number.isInteger(value))
|
|
9651
|
-
return "expected a whole number";
|
|
9652
|
-
if (def.min !== void 0 && value < def.min)
|
|
9653
|
-
return `below the minimum ${def.min}`;
|
|
9654
|
-
if (def.max !== void 0 && value > def.max)
|
|
9655
|
-
return `above the maximum ${def.max}`;
|
|
9656
|
-
return null;
|
|
9657
|
-
case "string":
|
|
9658
|
-
case "textStyle":
|
|
9659
|
-
case "dimStyle":
|
|
9660
|
-
case "font":
|
|
9661
|
-
case "lineType":
|
|
9662
|
-
case "hatchPattern":
|
|
9663
|
-
return typeof value === "string" ? null : "expected a string";
|
|
9664
|
-
case "boolean":
|
|
9665
|
-
return typeof value === "boolean" ? null : "expected true or false";
|
|
9666
|
-
case "numberList": {
|
|
9667
|
-
if (!Array.isArray(value) || !value.every((v) => typeof v === "number" && Number.isFinite(v)))
|
|
9668
|
-
return "expected an array of numbers";
|
|
9669
|
-
const low = value.find((v) => def.min !== void 0 && v < def.min);
|
|
9670
|
-
if (low !== void 0) return `${low} is below the minimum ${def.min}`;
|
|
9671
|
-
const high = value.find((v) => def.max !== void 0 && v > def.max);
|
|
9672
|
-
if (high !== void 0) return `${high} is above the maximum ${def.max}`;
|
|
9673
|
-
return null;
|
|
9674
|
-
}
|
|
9675
|
-
case "color":
|
|
9676
|
-
return typeof value === "string" && HEX_COLOR.test(value) ? null : 'expected a "#rrggbb" color';
|
|
9677
|
-
case "stringList":
|
|
9678
|
-
return Array.isArray(value) && value.every((v) => typeof v === "string") ? null : "expected an array of strings";
|
|
9679
|
-
case "enum":
|
|
9680
|
-
return def.options.some((o) => o.value === value) ? null : `expected one of ${def.options.map((o) => JSON.stringify(o.value)).join(", ")}`;
|
|
9681
|
-
default:
|
|
9682
|
-
return "a label carries no value";
|
|
9683
|
-
}
|
|
9684
|
-
};
|
|
9685
9734
|
var resolveCommandParams = (meta, given = {}) => {
|
|
9686
9735
|
const defs = valueParams(meta.params ?? []);
|
|
9687
9736
|
const params = /* @__PURE__ */ Object.create(null);
|
|
@@ -9699,8 +9748,57 @@ var resolveCommandParams = (meta, given = {}) => {
|
|
|
9699
9748
|
}
|
|
9700
9749
|
return params;
|
|
9701
9750
|
};
|
|
9751
|
+
var surfacePickers = (editor, document) => {
|
|
9752
|
+
let selectionUsed = false;
|
|
9753
|
+
const fromSelection = (def) => {
|
|
9754
|
+
if (selectionUsed) return null;
|
|
9755
|
+
const selected = editor.state().selectedIds.map((id) => document.getObject(id)).filter((o) => o !== void 0);
|
|
9756
|
+
if (!selectionFits(def, selected)) return null;
|
|
9757
|
+
selectionUsed = true;
|
|
9758
|
+
return selected.map((o) => o.id);
|
|
9759
|
+
};
|
|
9760
|
+
return {
|
|
9761
|
+
point: (def, ref) => editor.pickPoint({ label: inputLabel(def), referencePoint: ref }),
|
|
9762
|
+
points: (def, ref) => editor.pickPoints({ ...def, referencePoint: ref }),
|
|
9763
|
+
object: async (def) => fromSelection({ types: def.types, min: 1, max: 1 })?.[0] ?? editor.pickObject({ label: inputLabel(def), types: def.types }),
|
|
9764
|
+
objects: async (def) => fromSelection(def) ?? editor.pickObjects(def)
|
|
9765
|
+
};
|
|
9766
|
+
};
|
|
9767
|
+
var acquireNamedCommandInputs = async (meta, table, opts) => {
|
|
9768
|
+
const { inputs, missing } = checkNamedInputs(
|
|
9769
|
+
meta.name,
|
|
9770
|
+
table,
|
|
9771
|
+
opts.inputs,
|
|
9772
|
+
(id) => opts.document.getObject(id)
|
|
9773
|
+
);
|
|
9774
|
+
if (!opts.editor) {
|
|
9775
|
+
const required = missing.filter(isRequiredInput);
|
|
9776
|
+
if (required.length > 0)
|
|
9777
|
+
throw new Error(
|
|
9778
|
+
`${meta.name} needs an editor for: ${required.map((d) => d.name).join(", ")} \u2014 supply inputs`
|
|
9779
|
+
);
|
|
9780
|
+
return withEmptyLists(table, inputs);
|
|
9781
|
+
}
|
|
9782
|
+
if (missing.length === 0) return inputs;
|
|
9783
|
+
const picked = await acquireInputTable(
|
|
9784
|
+
missing,
|
|
9785
|
+
surfacePickers(opts.editor, opts.document)
|
|
9786
|
+
);
|
|
9787
|
+
const out = {};
|
|
9788
|
+
for (const def of table) {
|
|
9789
|
+
const v = inputs[def.name] ?? picked[def.name];
|
|
9790
|
+
if (v !== void 0) out[def.name] = v;
|
|
9791
|
+
}
|
|
9792
|
+
return out;
|
|
9793
|
+
};
|
|
9702
9794
|
var acquireCommandInputs = async (meta, opts) => {
|
|
9795
|
+
if (isInputTable(meta.inputs))
|
|
9796
|
+
return acquireNamedCommandInputs(meta, meta.inputs, opts);
|
|
9703
9797
|
const labels = meta.inputs ?? [];
|
|
9798
|
+
if (opts.inputs !== void 0 && !Array.isArray(opts.inputs))
|
|
9799
|
+
throw new Error(
|
|
9800
|
+
`${meta.name}: inputs are positional (${labels.join(", ") || "none declared"}) \u2014 pass an array`
|
|
9801
|
+
);
|
|
9704
9802
|
const given = (opts.inputs ?? []).map((p, i) => {
|
|
9705
9803
|
try {
|
|
9706
9804
|
return Vec2Schema.parse(p);
|
|
@@ -9732,11 +9830,29 @@ var runCommandModule = async (source, opts) => {
|
|
|
9732
9830
|
const result = getCommandMetaResult(source);
|
|
9733
9831
|
if (!result.ok) throw new Error(`Command failed to compile: ${result.error}`);
|
|
9734
9832
|
const run = getCommandRun(source);
|
|
9833
|
+
if (result.meta.requiresEditor && !opts.editor)
|
|
9834
|
+
throw new Error(
|
|
9835
|
+
`${result.meta.name} needs the editor (it asks during the run) \u2014 run it from Linea`
|
|
9836
|
+
);
|
|
9735
9837
|
const params = resolveCommandParams(result.meta, opts.params);
|
|
9736
9838
|
const inputs = await acquireCommandInputs(result.meta, opts);
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9839
|
+
try {
|
|
9840
|
+
return await opts.document.transaction(
|
|
9841
|
+
() => run(makeContext(opts, inputs, params)),
|
|
9842
|
+
result.meta.name
|
|
9843
|
+
);
|
|
9844
|
+
} catch (e) {
|
|
9845
|
+
throw opts.editor ? e : namedEditorError(result.meta.name, e);
|
|
9846
|
+
}
|
|
9847
|
+
};
|
|
9848
|
+
var namedEditorError = (name, e) => {
|
|
9849
|
+
const m = e instanceof TypeError ? /(?:reading|property) '(pickPoint|pickPoints|pickObject|pickObjects|prompt|ask|toast|state|setSelection|setActiveSpace|zoom|listCommands|runCommand)'/.exec(
|
|
9850
|
+
e.message
|
|
9851
|
+
) : null;
|
|
9852
|
+
if (!m) return e;
|
|
9853
|
+
return new Error(
|
|
9854
|
+
`${name} used editor.${m[1]} but runs without an editor here \u2014 check \`editor\` before using it, or declare \`requiresEditor: true\``,
|
|
9855
|
+
{ cause: e }
|
|
9740
9856
|
);
|
|
9741
9857
|
};
|
|
9742
9858
|
var runDocumentCommand = async (id, opts) => {
|
|
@@ -9922,7 +10038,10 @@ var Drawing = class extends LocalDrawing {
|
|
|
9922
10038
|
this.paintContext(),
|
|
9923
10039
|
opts
|
|
9924
10040
|
);
|
|
9925
|
-
return renderModelToPng(this.paintContext(),
|
|
10041
|
+
return renderModelToPng(this.paintContext(), {
|
|
10042
|
+
lineTypeScale: this.document.settings.modelScale,
|
|
10043
|
+
...opts
|
|
10044
|
+
});
|
|
9926
10045
|
}
|
|
9927
10046
|
/** Multi-page PDF of the layouts (default: all) with the embedded fonts. */
|
|
9928
10047
|
async renderPdf(opts = {}) {
|
|
@@ -9982,7 +10101,8 @@ var Drawing = class extends LocalDrawing {
|
|
|
9982
10101
|
}
|
|
9983
10102
|
// --- scripts ---------------------------------------------------------------
|
|
9984
10103
|
/** Run a command module source (`defineCommand`) against this drawing as
|
|
9985
|
-
* ONE undo step, headlessly: declared `inputs` must be supplied
|
|
10104
|
+
* ONE undo step, headlessly: declared `inputs` must be supplied (points
|
|
10105
|
+
* in label order, or a record by name for an inputs table); declared
|
|
9986
10106
|
* `params` take their defaults unless given by name (unknown names and
|
|
9987
10107
|
* wrong types throw). Resolves with the script's return value. */
|
|
9988
10108
|
runScript(source, inputs, params) {
|
|
@@ -10033,10 +10153,12 @@ export {
|
|
|
10033
10153
|
ensureScriptTranspiler,
|
|
10034
10154
|
getBlockMetaResult,
|
|
10035
10155
|
getCommandMetaResult,
|
|
10156
|
+
hatchLoop,
|
|
10036
10157
|
newDrawing,
|
|
10037
10158
|
openDrawing,
|
|
10038
10159
|
parseScale,
|
|
10039
10160
|
renderBlockThumbnailSvg,
|
|
10161
|
+
splineThrough,
|
|
10040
10162
|
testBlockDefinition
|
|
10041
10163
|
};
|
|
10042
10164
|
//# sourceMappingURL=sdk.js.map
|