@ifc-lite/drawing-2d 1.18.6 → 1.19.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 CHANGED
@@ -126,6 +126,29 @@ import {
126
126
 
127
127
  Each renderer returns SVG fragments that you wrap in your own `<svg>` document — see the [2D Drawings Guide](https://ifclite.dev/docs/guide/drawing-2d/) for a worked sheet-composition example.
128
128
 
129
+ ## DXF reference underlays
130
+
131
+ Import an existing DXF drawing (site plan, survey, coordination set) as a reference layer beneath a generated floor plan. `importDxf` parses ASCII DXF — `LINE`, `LWPOLYLINE`/`POLYLINE` (with bulge arcs), `CIRCLE`, `ARC`, `ELLIPSE`, `SPLINE`, `SOLID`/`TRACE`, `HATCH`, `TEXT`/`MTEXT`, `DIMENSION` blocks, and `INSERT`/`BLOCK` references — into world-plan geometry (metres, +Y = north; DXF and IFC are both Z-up) with per-layer visibility and resolved ACI/true colours and lineweights. `$INSUNITS` drives the unit conversion; unitless files with large extents are assumed to be millimetres (with a warning).
132
+
133
+ ```typescript
134
+ import { importDxf, exportToSVG } from '@ifc-lite/drawing-2d';
135
+
136
+ const underlay = importDxf(dxfFileText, 'site-plan.dxf');
137
+ // underlay.layers[n].paths / .fills / .texts, underlay.bounds, underlay.warnings
138
+
139
+ // Composite beneath an exported floor plan:
140
+ const svg = exportToSVG(drawing, {
141
+ underlays: [{
142
+ underlay,
143
+ placement: { offsetX: 0, offsetY: 0, rotationDeg: 0, scale: 1 },
144
+ layerVisibility: { 'A-SITE': true },
145
+ opacity: 0.8,
146
+ }],
147
+ });
148
+ ```
149
+
150
+ Unsupported entity types are counted in `underlay.skipped` rather than failing the import; parse problems (missing blocks, spline approximations, unknown units) surface in `underlay.warnings`.
151
+
129
152
  ## API
130
153
 
131
154
  See the [2D Drawings Guide](https://ifclite.dev/docs/guide/drawing-2d/) and [API Reference](https://ifclite.dev/docs/api/typescript/#ifc-litedrawing-2d).
@@ -0,0 +1,4 @@
1
+ export declare function rgbIntToCss(rgb: number): string;
2
+ /** Resolve an ACI colour number (1-255) to a CSS hex colour. */
3
+ export declare function aciToCss(index: number): string;
4
+ //# sourceMappingURL=aci-colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aci-colors.d.ts","sourceRoot":"","sources":["../../src/dxf/aci-colors.ts"],"names":[],"mappings":"AA+DA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI9C"}
@@ -0,0 +1,74 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * AutoCAD Color Index (ACI) → CSS colour.
6
+ *
7
+ * Indices 1-9 and 250-255 use the exact classic values. The 240 chromatic
8
+ * entries (10-249) are generated from the ACI band structure — 24 hue bands
9
+ * of 10 entries, alternating full/washed saturation over 5 brightness steps.
10
+ * That reproduces the classic table closely (visually indistinguishable for
11
+ * an underlay) without embedding 240 literals.
12
+ *
13
+ * ACI 7 is "white/black" (paper-dependent); the 2D canvas and SVG exports
14
+ * draw on white, so it maps to black.
15
+ */
16
+ function hsvToRgbInt(hueDeg, s, v) {
17
+ const c = v * s;
18
+ const hp = (((hueDeg % 360) + 360) % 360) / 60;
19
+ const x = c * (1 - Math.abs((hp % 2) - 1));
20
+ let r = 0;
21
+ let g = 0;
22
+ let b = 0;
23
+ if (hp < 1)
24
+ [r, g, b] = [c, x, 0];
25
+ else if (hp < 2)
26
+ [r, g, b] = [x, c, 0];
27
+ else if (hp < 3)
28
+ [r, g, b] = [0, c, x];
29
+ else if (hp < 4)
30
+ [r, g, b] = [0, x, c];
31
+ else if (hp < 5)
32
+ [r, g, b] = [x, 0, c];
33
+ else
34
+ [r, g, b] = [c, 0, x];
35
+ const m = v - c;
36
+ const to255 = (f) => Math.round((f + m) * 255);
37
+ return (to255(r) << 16) | (to255(g) << 8) | to255(b);
38
+ }
39
+ function buildAciTable() {
40
+ const t = new Array(256).fill(0x000000);
41
+ t[1] = 0xff0000; // red
42
+ t[2] = 0xffff00; // yellow
43
+ t[3] = 0x00ff00; // green
44
+ t[4] = 0x00ffff; // cyan
45
+ t[5] = 0x0000ff; // blue
46
+ t[6] = 0xff00ff; // magenta
47
+ t[7] = 0x000000; // white/black → black on a white canvas
48
+ t[8] = 0x414141;
49
+ t[9] = 0x808080;
50
+ const brightness = [1.0, 0.8, 0.6, 0.5, 0.35];
51
+ for (let i = 10; i <= 249; i++) {
52
+ const c = i - 10;
53
+ const hue = Math.floor(c / 10) * 15;
54
+ const v = brightness[Math.floor((c % 10) / 2)];
55
+ const s = c % 2 === 1 ? 0.45 : 1.0;
56
+ t[i] = hsvToRgbInt(hue, s, v);
57
+ }
58
+ const grays = [0x333333, 0x505050, 0x696969, 0x828282, 0xbebebe, 0xffffff];
59
+ for (let i = 0; i < grays.length; i++)
60
+ t[250 + i] = grays[i];
61
+ return t;
62
+ }
63
+ const ACI_TABLE = buildAciTable();
64
+ export function rgbIntToCss(rgb) {
65
+ return `#${(rgb & 0xffffff).toString(16).padStart(6, '0')}`;
66
+ }
67
+ /** Resolve an ACI colour number (1-255) to a CSS hex colour. */
68
+ export function aciToCss(index) {
69
+ const i = Math.trunc(index);
70
+ if (i < 1 || i > 255 || !Number.isFinite(i))
71
+ return '#000000';
72
+ return rgbIntToCss(ACI_TABLE[i]);
73
+ }
74
+ //# sourceMappingURL=aci-colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aci-colors.js","sourceRoot":"","sources":["../../src/dxf/aci-colors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Convert a parsed DXF document into a reference underlay (issue #1782):
3
+ * tessellate entities, expand INSERT/DIMENSION blocks, resolve ACI/true
4
+ * colours per layer, and scale $INSUNITS to metres. Output is in WORLD
5
+ * plan coordinates (metres, +Y = north; DXF and IFC are both Z-up).
6
+ * Consumers map world → drawing space themselves — for a plan view that
7
+ * is `(x - shiftX, -(y - shiftY))` with the render-frame origin shift.
8
+ */
9
+ import type { Point2D } from '../types.js';
10
+ import type { DxfDocument, DxfPlacement, DxfUnderlay } from './types.js';
11
+ export interface DxfConvertOptions {
12
+ /**
13
+ * Override the unit conversion (drawing units → metres). When set, the
14
+ * file's $INSUNITS is ignored. Used by `importDxf`'s unitless-mm
15
+ * heuristic and available for callers that know the drawing's units.
16
+ */
17
+ metersPerUnit?: number;
18
+ }
19
+ /**
20
+ * Convert a parsed DXF document to a reference underlay.
21
+ * `name` labels the underlay (typically the file name).
22
+ */
23
+ export declare function convertDxfToUnderlay(doc: DxfDocument, name?: string, options?: DxfConvertOptions): DxfUnderlay;
24
+ /**
25
+ * Apply a user placement to an underlay point in DRAWING space — i.e.
26
+ * after the world → drawing mapping (`x_d = x - shiftX`,
27
+ * `y_d = -(y - shiftY)` for a plan view). Rotation is counter-clockwise
28
+ * as seen on the plan (drawing space renders with +y downward on screen,
29
+ * hence the transposed rotation matrix).
30
+ */
31
+ export declare function applyDxfPlacement(p: Point2D, placement: DxfPlacement): Point2D;
32
+ //# sourceMappingURL=convert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/dxf/convert.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,aAAa,CAAC;AAehE,OAAO,KAAK,EACV,WAAW,EAGX,YAAY,EACZ,WAAW,EAGZ,MAAM,YAAY,CAAC;AAqDpB,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,SAAQ,EAAE,OAAO,GAAE,iBAAsB,GAAG,WAAW,CA+DjH;AAmTD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,GAAG,OAAO,CAU9E"}
@@ -0,0 +1,382 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { aciToCss, rgbIntToCss } from './aci-colors.js';
5
+ import { expandBulgedVertices, matApply, matMultiply, matTRS, matTranslate, sampleArc, sampleCircle, sampleEllipse, tessellateSpline, MAT_IDENTITY, } from './geom.js';
6
+ /** $INSUNITS → metres. Unknown codes fall back to 1 with a warning. */
7
+ const INSUNITS_TO_METRES = {
8
+ 0: 1, // unitless: assume metres (adjustable via placement scale)
9
+ 1: 0.0254, // inches
10
+ 2: 0.3048, // feet
11
+ 3: 1609.344, // miles
12
+ 4: 0.001, // millimetres
13
+ 5: 0.01, // centimetres
14
+ 6: 1, // metres
15
+ 7: 1000, // kilometres
16
+ 8: 2.54e-8, // microinches
17
+ 9: 2.54e-5, // mils
18
+ 10: 0.9144, // yards
19
+ 11: 1e-10, // angstroms
20
+ 12: 1e-9, // nanometres
21
+ 13: 1e-6, // microns
22
+ 14: 0.1, // decimetres
23
+ 15: 10, // decametres
24
+ 16: 100, // hectometres
25
+ };
26
+ /** Recursion guard for nested INSERTs. */
27
+ const MAX_BLOCK_DEPTH = 8;
28
+ /** Total block-instance expansion cap against pathological grids/nesting. */
29
+ const MAX_BLOCK_INSTANCES = 100_000;
30
+ const CONTINUOUS_LINETYPES = new Set(['', 'CONTINUOUS', 'BYLAYER', 'BYBLOCK']);
31
+ /**
32
+ * Convert a parsed DXF document to a reference underlay.
33
+ * `name` labels the underlay (typically the file name).
34
+ */
35
+ export function convertDxfToUnderlay(doc, name = 'DXF', options = {}) {
36
+ const warnings = [...doc.warnings];
37
+ let unitScale;
38
+ if (options.metersPerUnit !== undefined && options.metersPerUnit > 0) {
39
+ unitScale = options.metersPerUnit;
40
+ }
41
+ else {
42
+ const fromHeader = INSUNITS_TO_METRES[doc.insunits];
43
+ if (fromHeader === undefined) {
44
+ warnings.push(`Unknown $INSUNITS value ${doc.insunits}; drawing units treated as metres.`);
45
+ unitScale = 1;
46
+ }
47
+ else {
48
+ unitScale = fromHeader;
49
+ }
50
+ if (doc.insunits === 0) {
51
+ warnings.push('DXF has no $INSUNITS; drawing units treated as metres (adjust with the underlay scale).');
52
+ }
53
+ }
54
+ const state = {
55
+ doc,
56
+ unitScale,
57
+ layers: new Map(),
58
+ layerInfos: doc.layers,
59
+ bounds: { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },
60
+ warnings,
61
+ instanceCount: 0,
62
+ instanceCapHit: false,
63
+ };
64
+ const ctx = {
65
+ m: MAT_IDENTITY,
66
+ byBlockColor: null,
67
+ insertLayer: null,
68
+ depth: 0,
69
+ stack: [],
70
+ };
71
+ emitEntities(doc.entities, ctx, state);
72
+ const bounds = Number.isFinite(state.bounds.minX)
73
+ ? {
74
+ min: { x: state.bounds.minX, y: state.bounds.minY },
75
+ max: { x: state.bounds.maxX, y: state.bounds.maxY },
76
+ }
77
+ : { min: { x: 0, y: 0 }, max: { x: 0, y: 0 } };
78
+ // Stable layer order: DXF table order first, then referenced-only layers.
79
+ const ordered = [];
80
+ for (const layerName of doc.layers.keys()) {
81
+ const bucket = state.layers.get(layerName);
82
+ if (bucket)
83
+ ordered.push(bucket);
84
+ }
85
+ for (const [layerName, bucket] of state.layers) {
86
+ if (!doc.layers.has(layerName))
87
+ ordered.push(bucket);
88
+ }
89
+ return {
90
+ name,
91
+ layers: ordered.filter((l) => l.paths.length > 0 || l.fills.length > 0 || l.texts.length > 0),
92
+ bounds,
93
+ unitScale,
94
+ skipped: { ...doc.skipped },
95
+ warnings: state.warnings,
96
+ };
97
+ }
98
+ // ═══════════════════════════════════════════════════════════════════════════
99
+ // EMISSION
100
+ // ═══════════════════════════════════════════════════════════════════════════
101
+ function getBucket(state, layerName) {
102
+ let bucket = state.layers.get(layerName);
103
+ if (!bucket) {
104
+ const info = state.layerInfos.get(layerName);
105
+ const color = info
106
+ ? info.trueColor !== undefined
107
+ ? rgbIntToCss(info.trueColor)
108
+ : aciToCss(info.colorNumber)
109
+ : '#000000';
110
+ bucket = {
111
+ name: layerName,
112
+ color,
113
+ visible: info ? info.visible : true,
114
+ paths: [],
115
+ fills: [],
116
+ texts: [],
117
+ };
118
+ state.layers.set(layerName, bucket);
119
+ }
120
+ return bucket;
121
+ }
122
+ /** Resolve an entity's CSS colour given its layer and BYBLOCK context. */
123
+ function resolveColor(entity, layerColor, ctx) {
124
+ if (entity.trueColor !== undefined)
125
+ return rgbIntToCss(entity.trueColor);
126
+ const cn = entity.colorNumber;
127
+ if (cn === 0)
128
+ return ctx.byBlockColor ?? layerColor; // BYBLOCK
129
+ if (cn >= 1 && cn <= 255)
130
+ return aciToCss(cn);
131
+ return layerColor; // BYLAYER (256) and anything unexpected
132
+ }
133
+ function isDashed(entity, layerInfo) {
134
+ const lt = (entity.linetype ?? '').trim().toUpperCase();
135
+ if (lt && lt !== 'BYLAYER') {
136
+ return lt !== 'CONTINUOUS' && lt !== 'BYBLOCK';
137
+ }
138
+ const layerLt = (layerInfo?.linetype ?? '').trim().toUpperCase();
139
+ return !CONTINUOUS_LINETYPES.has(layerLt);
140
+ }
141
+ /** Map a DXF-space point through the block chain into world metres. */
142
+ function toWorld(state, ctx, x, y) {
143
+ const p = matApply(ctx.m, x, y);
144
+ const wx = p.x * state.unitScale;
145
+ const wy = p.y * state.unitScale;
146
+ if (wx < state.bounds.minX)
147
+ state.bounds.minX = wx;
148
+ if (wx > state.bounds.maxX)
149
+ state.bounds.maxX = wx;
150
+ if (wy < state.bounds.minY)
151
+ state.bounds.minY = wy;
152
+ if (wy > state.bounds.maxY)
153
+ state.bounds.maxY = wy;
154
+ return { x: wx, y: wy };
155
+ }
156
+ /** Lineweight in mm: entity group 370, else the layer default. */
157
+ function resolveWidthMm(entity, layerInfo) {
158
+ return entity.lineweightMm ?? layerInfo?.lineweightMm;
159
+ }
160
+ function emitEntities(entities, ctx, state) {
161
+ for (const entity of entities) {
162
+ if (entity.invisible)
163
+ continue;
164
+ const effLayerName = entity.layer === '0' && ctx.insertLayer ? ctx.insertLayer : entity.layer;
165
+ const bucket = getBucket(state, effLayerName);
166
+ const layerInfo = state.layerInfos.get(effLayerName);
167
+ const color = resolveColor(entity, bucket.color, ctx);
168
+ const colorOverride = color !== bucket.color ? color : undefined;
169
+ const mirror = entity.extrusionZ < 0 ? -1 : 1;
170
+ const dashed = isDashed(entity, layerInfo) || undefined;
171
+ const widthMm = resolveWidthMm(entity, layerInfo);
172
+ const pushPath = (pts, closed) => {
173
+ if (pts.length < 2)
174
+ return;
175
+ bucket.paths.push({
176
+ points: pts.map((p) => toWorld(state, ctx, p.x * mirror, p.y)),
177
+ closed,
178
+ color: colorOverride,
179
+ dashed,
180
+ widthMm,
181
+ });
182
+ };
183
+ switch (entity.kind) {
184
+ case 'line':
185
+ // LINE coordinates are WCS; the OCS mirror does not apply.
186
+ bucket.paths.push({
187
+ points: [toWorld(state, ctx, entity.x1, entity.y1), toWorld(state, ctx, entity.x2, entity.y2)],
188
+ closed: false,
189
+ color: colorOverride,
190
+ dashed,
191
+ widthMm,
192
+ });
193
+ break;
194
+ case 'polyline':
195
+ pushPath(expandBulgedVertices(entity.vertices, entity.closed), entity.closed);
196
+ break;
197
+ case 'spline':
198
+ pushPath(tessellateSpline(entity.degree, entity.knots, entity.controlPoints, entity.fitPoints), entity.closed);
199
+ break;
200
+ case 'circle':
201
+ pushPath(sampleCircle(entity.cx, entity.cy, entity.r), true);
202
+ break;
203
+ case 'arc': {
204
+ // Mirrored OCS also mirrors angles: θ → 180° − θ.
205
+ const start = mirror < 0 ? 180 - entity.endDeg : entity.startDeg;
206
+ const end = mirror < 0 ? 180 - entity.startDeg : entity.endDeg;
207
+ const pts = sampleArc(entity.cx * mirror, entity.cy, entity.r, start, end);
208
+ if (pts.length >= 2) {
209
+ bucket.paths.push({
210
+ points: pts.map((p) => toWorld(state, ctx, p.x, p.y)),
211
+ closed: false,
212
+ color: colorOverride,
213
+ dashed,
214
+ widthMm,
215
+ });
216
+ }
217
+ break;
218
+ }
219
+ case 'solid': {
220
+ const ring = entity.corners.map((p) => toWorld(state, ctx, p.x * mirror, p.y));
221
+ if (ring.length >= 3) {
222
+ bucket.fills.push({ polygon: { outer: ring, holes: [] }, color: colorOverride, pattern: false });
223
+ }
224
+ break;
225
+ }
226
+ case 'ellipse':
227
+ pushPath(sampleEllipse(entity.cx, entity.cy, entity.majorX, entity.majorY, entity.ratio, entity.startParam, entity.endParam), Math.abs(entity.endParam - entity.startParam) >= Math.PI * 2 - 1e-9);
228
+ break;
229
+ case 'hatch': {
230
+ if (entity.paths.length === 0)
231
+ break;
232
+ const rings = entity.paths
233
+ .map((path) => expandBulgedVertices(path.vertices, true).map((p) => toWorld(state, ctx, p.x * mirror, p.y)))
234
+ .filter((ring) => ring.length >= 3);
235
+ if (rings.length === 0)
236
+ break;
237
+ // Largest ring is the outer boundary; the rest render as holes.
238
+ let outerIdx = 0;
239
+ let outerArea = -1;
240
+ rings.forEach((ring, idx) => {
241
+ const area = Math.abs(ringArea(ring));
242
+ if (area > outerArea) {
243
+ outerArea = area;
244
+ outerIdx = idx;
245
+ }
246
+ });
247
+ const polygon = {
248
+ outer: rings[outerIdx],
249
+ holes: rings.filter((_, idx) => idx !== outerIdx),
250
+ };
251
+ bucket.fills.push({ polygon, color: colorOverride, pattern: !entity.solid });
252
+ break;
253
+ }
254
+ case 'text': {
255
+ if (!entity.text.trim())
256
+ break;
257
+ const anchor = toWorld(state, ctx, entity.x * mirror, entity.y);
258
+ const rad = (entity.rotationDeg * Math.PI) / 180;
259
+ const tip = toWorld(state, ctx, (entity.x + Math.cos(rad)) * mirror, entity.y + Math.sin(rad));
260
+ let dirX = tip.x - anchor.x;
261
+ let dirY = tip.y - anchor.y;
262
+ const len = Math.hypot(dirX, dirY);
263
+ if (len > 1e-12) {
264
+ dirX /= len;
265
+ dirY /= len;
266
+ }
267
+ else {
268
+ dirX = 1;
269
+ dirY = 0;
270
+ }
271
+ const scaleEstimate = Math.sqrt(Math.abs(ctx.m[0] * ctx.m[3] - ctx.m[1] * ctx.m[2]));
272
+ const text = {
273
+ position: anchor,
274
+ text: entity.text,
275
+ height: entity.height * scaleEstimate * state.unitScale,
276
+ dirX,
277
+ dirY,
278
+ align: entity.hAlign,
279
+ valign: entity.vAlign,
280
+ color: colorOverride,
281
+ };
282
+ bucket.texts.push(text);
283
+ break;
284
+ }
285
+ case 'insert':
286
+ emitInsert(entity, ctx, state, effLayerName, color);
287
+ break;
288
+ case 'dimension': {
289
+ const block = entity.blockName ? state.doc.blocks.get(entity.blockName) : undefined;
290
+ if (!block) {
291
+ state.doc.skipped['DIMENSION'] = (state.doc.skipped['DIMENSION'] ?? 0) + 1;
292
+ break;
293
+ }
294
+ if (ctx.depth >= MAX_BLOCK_DEPTH || ctx.stack.includes(block.name))
295
+ break;
296
+ // Dimension block geometry is already in the dimension's WCS.
297
+ emitEntities(block.entities, {
298
+ m: ctx.m,
299
+ byBlockColor: color,
300
+ insertLayer: effLayerName,
301
+ depth: ctx.depth + 1,
302
+ stack: [...ctx.stack, block.name],
303
+ }, state);
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ }
309
+ function emitInsert(entity, ctx, state, effLayerName, resolvedColor) {
310
+ const block = state.doc.blocks.get(entity.blockName);
311
+ if (!block) {
312
+ state.warnings.push(`INSERT references missing block "${entity.blockName}".`);
313
+ return;
314
+ }
315
+ if (ctx.depth >= MAX_BLOCK_DEPTH) {
316
+ state.warnings.push(`Block nesting deeper than ${MAX_BLOCK_DEPTH} levels; "${entity.blockName}" truncated.`);
317
+ return;
318
+ }
319
+ if (ctx.stack.includes(entity.blockName)) {
320
+ state.warnings.push(`Recursive block reference "${entity.blockName}" skipped.`);
321
+ return;
322
+ }
323
+ const mirror = entity.extrusionZ < 0 ? -1 : 1;
324
+ const cols = Math.min(entity.columnCount, 1024);
325
+ const rows = Math.min(entity.rowCount, 1024);
326
+ for (let row = 0; row < rows; row++) {
327
+ for (let col = 0; col < cols; col++) {
328
+ if (state.instanceCount >= MAX_BLOCK_INSTANCES) {
329
+ if (!state.instanceCapHit) {
330
+ state.instanceCapHit = true;
331
+ state.warnings.push(`Block instance limit (${MAX_BLOCK_INSTANCES}) reached; remaining inserts ignored.`);
332
+ }
333
+ return;
334
+ }
335
+ state.instanceCount++;
336
+ // insert translation ∘ rotation ∘ scale ∘ grid offset ∘ base-point shift
337
+ let local = matTRS(entity.x * mirror, entity.y, mirror < 0 ? -entity.rotationDeg : entity.rotationDeg, entity.scaleX * mirror, entity.scaleY);
338
+ if (col !== 0 || row !== 0) {
339
+ local = matMultiply(local, matTranslate(col * entity.columnSpacing, row * entity.rowSpacing));
340
+ }
341
+ local = matMultiply(local, matTranslate(-block.baseX, -block.baseY));
342
+ emitEntities(block.entities, {
343
+ m: matMultiply(ctx.m, local),
344
+ byBlockColor: resolvedColor,
345
+ insertLayer: effLayerName,
346
+ depth: ctx.depth + 1,
347
+ stack: [...ctx.stack, entity.blockName],
348
+ }, state);
349
+ }
350
+ }
351
+ }
352
+ function ringArea(ring) {
353
+ let area = 0;
354
+ for (let i = 0; i < ring.length; i++) {
355
+ const a = ring[i];
356
+ const b = ring[(i + 1) % ring.length];
357
+ area += a.x * b.y - b.x * a.y;
358
+ }
359
+ return area / 2;
360
+ }
361
+ // ═══════════════════════════════════════════════════════════════════════════
362
+ // PLACEMENT
363
+ // ═══════════════════════════════════════════════════════════════════════════
364
+ /**
365
+ * Apply a user placement to an underlay point in DRAWING space — i.e.
366
+ * after the world → drawing mapping (`x_d = x - shiftX`,
367
+ * `y_d = -(y - shiftY)` for a plan view). Rotation is counter-clockwise
368
+ * as seen on the plan (drawing space renders with +y downward on screen,
369
+ * hence the transposed rotation matrix).
370
+ */
371
+ export function applyDxfPlacement(p, placement) {
372
+ const rad = (placement.rotationDeg * Math.PI) / 180;
373
+ const c = Math.cos(rad);
374
+ const s = Math.sin(rad);
375
+ const x = p.x * placement.scale;
376
+ const y = p.y * placement.scale;
377
+ return {
378
+ x: x * c + y * s + placement.offsetX,
379
+ y: -x * s + y * c + placement.offsetY,
380
+ };
381
+ }
382
+ //# sourceMappingURL=convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/dxf/convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Geometry helpers for DXF import: arc/bulge tessellation and 2D affine
3
+ * transforms. Shared by the parser (HATCH edge paths) and the converter
4
+ * (entity tessellation, block expansion).
5
+ */
6
+ import type { DxfVertex } from './types.js';
7
+ export declare function arcSegmentCount(sweepRad: number): number;
8
+ /**
9
+ * Sample a circular arc from `startDeg` to `endDeg` (degrees, CCW from +X).
10
+ * When `endDeg <= startDeg` the arc wraps through 360 (DXF convention).
11
+ * Includes both endpoints.
12
+ */
13
+ export declare function sampleArc(cx: number, cy: number, r: number, startDeg: number, endDeg: number): Array<{
14
+ x: number;
15
+ y: number;
16
+ }>;
17
+ /** Sample a full circle (closed loop; last point NOT repeated). */
18
+ export declare function sampleCircle(cx: number, cy: number, r: number): Array<{
19
+ x: number;
20
+ y: number;
21
+ }>;
22
+ /**
23
+ * Sample an elliptical arc. `startParam`/`endParam` are parametric angles in
24
+ * radians; the point at parameter t is `c + major·cos(t) + minor·sin(t)`
25
+ * where `minor = ratio · perp(major)`.
26
+ */
27
+ export declare function sampleEllipse(cx: number, cy: number, majorX: number, majorY: number, ratio: number, startParam: number, endParam: number): Array<{
28
+ x: number;
29
+ y: number;
30
+ }>;
31
+ /**
32
+ * Expand a polyline vertex loop with bulges into a flat point list.
33
+ * A bulge b = tan(sweep/4) describes the arc from a vertex to the next one
34
+ * (positive = CCW). Closed loops also expand the bulge of the last vertex
35
+ * (arc back to the first). Includes the first point; for closed loops the
36
+ * first point is not repeated at the end.
37
+ */
38
+ export declare function expandBulgedVertices(vertices: DxfVertex[], closed: boolean): Array<{
39
+ x: number;
40
+ y: number;
41
+ }>;
42
+ /**
43
+ * Sample a SPLINE entity as a polyline. Fit points win when present (they
44
+ * lie on the curve); otherwise a clamped B-spline is evaluated with de
45
+ * Boor's algorithm. Degenerate knot vectors fall back to the control
46
+ * polygon.
47
+ */
48
+ export declare function tessellateSpline(degree: number, knots: number[], controlPoints: Array<{
49
+ x: number;
50
+ y: number;
51
+ }>, fitPoints: Array<{
52
+ x: number;
53
+ y: number;
54
+ }>, segmentsPerSpan?: number): Array<{
55
+ x: number;
56
+ y: number;
57
+ }>;
58
+ /** Column-major 2D affine: x' = a·x + c·y + tx, y' = b·x + d·y + ty. */
59
+ export type Mat2d = [number, number, number, number, number, number];
60
+ export declare const MAT_IDENTITY: Mat2d;
61
+ /** Compose so that `m2` is applied first, then `m1`. */
62
+ export declare function matMultiply(m1: Mat2d, m2: Mat2d): Mat2d;
63
+ export declare function matApply(m: Mat2d, x: number, y: number): {
64
+ x: number;
65
+ y: number;
66
+ };
67
+ /** translate(tx,ty) ∘ rotate(deg CCW) ∘ scale(sx,sy). */
68
+ export declare function matTRS(tx: number, ty: number, rotationDeg: number, sx: number, sy: number): Mat2d;
69
+ export declare function matTranslate(tx: number, ty: number): Mat2d;
70
+ //# sourceMappingURL=geom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geom.d.ts","sourceRoot":"","sources":["../../src/dxf/geom.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAO5C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAYjC;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ/F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAejC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,SAAS,EAAE,EACrB,MAAM,EAAE,OAAO,GACd,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiDjC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,EAAE,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9C,SAAS,EAAE,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,eAAe,SAAI,GAClB,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBjC;AAoCD,wEAAwE;AACxE,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErE,eAAO,MAAM,YAAY,EAAE,KAA0B,CAAC;AAEtD,wDAAwD;AACxD,wBAAgB,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,KAAK,CASvD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAEjF;AAED,yDAAyD;AACzD,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,CAKjG;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,CAE1D"}