@bill_nee/dwg-reader 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +615 -0
  2. package/README.md +23 -2
  3. package/cordis.patch.yml +3 -0
  4. package/icon.svg +15 -0
  5. package/lib/index.js +355 -0
  6. package/locale/en.json +6 -0
  7. package/locale/zh.json +6 -0
  8. package/package.json +33 -4
  9. package/vendor/libredwg-web/lib/converter/converter.js +1102 -0
  10. package/vendor/libredwg-web/lib/converter/dwgColorToMLeaderRawColor.js +55 -0
  11. package/vendor/libredwg-web/lib/converter/entityConverter.js +2050 -0
  12. package/vendor/libredwg-web/lib/converter/index.js +3 -0
  13. package/vendor/libredwg-web/lib/converter/utils.js +46 -0
  14. package/vendor/libredwg-web/lib/database/classes/class.js +2 -0
  15. package/vendor/libredwg-web/lib/database/classes/index.js +2 -0
  16. package/vendor/libredwg-web/lib/database/codepage.js +101 -0
  17. package/vendor/libredwg-web/lib/database/common.js +2 -0
  18. package/vendor/libredwg-web/lib/database/database.js +2 -0
  19. package/vendor/libredwg-web/lib/database/entities/3dface.js +2 -0
  20. package/vendor/libredwg-web/lib/database/entities/arc.js +2 -0
  21. package/vendor/libredwg-web/lib/database/entities/arcAlignedText.js +2 -0
  22. package/vendor/libredwg-web/lib/database/entities/attdef.js +2 -0
  23. package/vendor/libredwg-web/lib/database/entities/attrib.js +2 -0
  24. package/vendor/libredwg-web/lib/database/entities/circle.js +2 -0
  25. package/vendor/libredwg-web/lib/database/entities/dimension.js +70 -0
  26. package/vendor/libredwg-web/lib/database/entities/ellipse.js +2 -0
  27. package/vendor/libredwg-web/lib/database/entities/entity.js +2 -0
  28. package/vendor/libredwg-web/lib/database/entities/hatch.js +54 -0
  29. package/vendor/libredwg-web/lib/database/entities/image.js +2 -0
  30. package/vendor/libredwg-web/lib/database/entities/index.js +38 -0
  31. package/vendor/libredwg-web/lib/database/entities/insert.js +2 -0
  32. package/vendor/libredwg-web/lib/database/entities/leader.js +2 -0
  33. package/vendor/libredwg-web/lib/database/entities/line.js +2 -0
  34. package/vendor/libredwg-web/lib/database/entities/lwpolyline.js +2 -0
  35. package/vendor/libredwg-web/lib/database/entities/mline.js +2 -0
  36. package/vendor/libredwg-web/lib/database/entities/mtext.js +2 -0
  37. package/vendor/libredwg-web/lib/database/entities/multileader.js +2 -0
  38. package/vendor/libredwg-web/lib/database/entities/ole2frame.js +2 -0
  39. package/vendor/libredwg-web/lib/database/entities/oleframe.js +2 -0
  40. package/vendor/libredwg-web/lib/database/entities/point.js +2 -0
  41. package/vendor/libredwg-web/lib/database/entities/polyline.js +19 -0
  42. package/vendor/libredwg-web/lib/database/entities/proxy.js +10 -0
  43. package/vendor/libredwg-web/lib/database/entities/ray.js +2 -0
  44. package/vendor/libredwg-web/lib/database/entities/section.js +2 -0
  45. package/vendor/libredwg-web/lib/database/entities/shape.js +2 -0
  46. package/vendor/libredwg-web/lib/database/entities/solid.js +2 -0
  47. package/vendor/libredwg-web/lib/database/entities/solid3d.js +2 -0
  48. package/vendor/libredwg-web/lib/database/entities/spline.js +2 -0
  49. package/vendor/libredwg-web/lib/database/entities/table.js +2 -0
  50. package/vendor/libredwg-web/lib/database/entities/text.js +23 -0
  51. package/vendor/libredwg-web/lib/database/entities/tolerance.js +2 -0
  52. package/vendor/libredwg-web/lib/database/entities/trace.js +2 -0
  53. package/vendor/libredwg-web/lib/database/entities/vertex.js +2 -0
  54. package/vendor/libredwg-web/lib/database/entities/viewport.js +2 -0
  55. package/vendor/libredwg-web/lib/database/entities/wipeout.js +2 -0
  56. package/vendor/libredwg-web/lib/database/entities/xline.js +2 -0
  57. package/vendor/libredwg-web/lib/database/header/header.js +2 -0
  58. package/vendor/libredwg-web/lib/database/header/index.js +3 -0
  59. package/vendor/libredwg-web/lib/database/header/variables.js +217 -0
  60. package/vendor/libredwg-web/lib/database/index.js +12 -0
  61. package/vendor/libredwg-web/lib/database/objects/common.js +2 -0
  62. package/vendor/libredwg-web/lib/database/objects/dictionary.js +19 -0
  63. package/vendor/libredwg-web/lib/database/objects/imageDef.js +2 -0
  64. package/vendor/libredwg-web/lib/database/objects/index.js +11 -0
  65. package/vendor/libredwg-web/lib/database/objects/layerFilter.js +2 -0
  66. package/vendor/libredwg-web/lib/database/objects/layerIndex.js +2 -0
  67. package/vendor/libredwg-web/lib/database/objects/layout.js +2 -0
  68. package/vendor/libredwg-web/lib/database/objects/mleaderStyle.js +2 -0
  69. package/vendor/libredwg-web/lib/database/objects/plotSetting.js +2 -0
  70. package/vendor/libredwg-web/lib/database/objects/spatialFilter.js +2 -0
  71. package/vendor/libredwg-web/lib/database/objects/xrecord.js +2 -0
  72. package/vendor/libredwg-web/lib/database/shared/index.js +2 -0
  73. package/vendor/libredwg-web/lib/database/shared/xdata.js +2 -0
  74. package/vendor/libredwg-web/lib/database/tables/appId.js +2 -0
  75. package/vendor/libredwg-web/lib/database/tables/blockRecord.js +2 -0
  76. package/vendor/libredwg-web/lib/database/tables/dimStyle.js +2 -0
  77. package/vendor/libredwg-web/lib/database/tables/index.js +9 -0
  78. package/vendor/libredwg-web/lib/database/tables/layer.js +2 -0
  79. package/vendor/libredwg-web/lib/database/tables/ltype.js +2 -0
  80. package/vendor/libredwg-web/lib/database/tables/style.js +2 -0
  81. package/vendor/libredwg-web/lib/database/tables/table.js +2 -0
  82. package/vendor/libredwg-web/lib/database/tables/vport.js +2 -0
  83. package/vendor/libredwg-web/lib/database/textEscapes.js +19 -0
  84. package/vendor/libredwg-web/lib/database/version.js +260 -0
  85. package/vendor/libredwg-web/lib/index.js +4 -0
  86. package/vendor/libredwg-web/lib/libredwg.js +1271 -0
  87. package/vendor/libredwg-web/lib/svg/box2d.js +104 -0
  88. package/vendor/libredwg-web/lib/svg/bspline.js +95 -0
  89. package/vendor/libredwg-web/lib/svg/color.js +371 -0
  90. package/vendor/libredwg-web/lib/svg/index.js +2 -0
  91. package/vendor/libredwg-web/lib/svg/polyline.js +70 -0
  92. package/vendor/libredwg-web/lib/svg/svgConverter.js +540 -0
  93. package/vendor/libredwg-web/lib/svg/transformBoundingBoxAndElement.js +20 -0
  94. package/vendor/libredwg-web/lib/svg/vector.js +27 -0
  95. package/vendor/libredwg-web/lib/types/common.js +2 -0
  96. package/vendor/libredwg-web/lib/types/enums.js +390 -0
  97. package/vendor/libredwg-web/lib/types/index.js +3 -0
  98. package/vendor/libredwg-web/wasm/libredwg-web.js +2 -0
  99. package/vendor/libredwg-web/wasm/libredwg-web.wasm +0 -0
@@ -0,0 +1,540 @@
1
+ import { isModelSpace } from '../converter/utils.js';
2
+ import { DwgAttachmentPoint, DwgTextHorizontalAlign } from '../database/index.js';
3
+ import { Box2D } from './box2d.js';
4
+ import { evaluateBSpline } from './bspline.js';
5
+ import { Color } from './color.js';
6
+ import { interpolatePolyline } from './polyline.js';
7
+ export class SvgConverter {
8
+ blockMap = new Map();
9
+ rotate(point, angle) {
10
+ const cos = Math.cos(angle);
11
+ const sin = Math.sin(angle);
12
+ return {
13
+ x: point.x * cos - point.y * sin,
14
+ y: point.x * sin + point.y * cos
15
+ };
16
+ }
17
+ /**
18
+ * Interpolates a B-spline curve and returns the resulting polyline.
19
+ *
20
+ * @param controlPoints The control points of the B-spline.
21
+ * @param degree The degree of the B-spline.
22
+ * @param knots The knot vector.
23
+ * @param interpolationsPerSplineSegment Number of interpolated points per spline segment.
24
+ * @param weights Optional weight vector for rational B-splines.
25
+ * @returns An array of interpolated 2D points representing the polyline.
26
+ */
27
+ interpolateBSpline(controlPoints, degree, knots, interpolationsPerSplineSegment = 25, weights) {
28
+ const polyline = [];
29
+ const controlPointsForLib = controlPoints.map((p) => [p.x, p.y]);
30
+ const segmentTs = [knots[degree]];
31
+ const domain = [
32
+ knots[degree],
33
+ knots[knots.length - 1 - degree]
34
+ ];
35
+ for (let k = degree + 1; k < knots.length - degree; ++k) {
36
+ if (segmentTs[segmentTs.length - 1] !== knots[k]) {
37
+ segmentTs.push(knots[k]);
38
+ }
39
+ }
40
+ for (let i = 1; i < segmentTs.length; ++i) {
41
+ const uMin = segmentTs[i - 1];
42
+ const uMax = segmentTs[i];
43
+ for (let k = 0; k <= interpolationsPerSplineSegment; ++k) {
44
+ const u = (k / interpolationsPerSplineSegment) * (uMax - uMin) + uMin;
45
+ let t = (u - domain[0]) / (domain[1] - domain[0]);
46
+ t = Math.max(0, Math.min(1, t)); // Clamp t to [0, 1]
47
+ const p = evaluateBSpline(t, degree, controlPointsForLib, knots, weights);
48
+ polyline.push({ x: p[0], y: p[1] });
49
+ }
50
+ }
51
+ return polyline;
52
+ }
53
+ addFlipXIfApplicable(entity, { bbox, element }) {
54
+ if ('extrusionDirection' in entity &&
55
+ entity.extrusionDirection.z === -1) {
56
+ return {
57
+ bbox: new Box2D()
58
+ .expandByPoint({ x: -bbox.min.x, y: bbox.min.y })
59
+ .expandByPoint({ x: -bbox.max.x, y: bbox.max.y }),
60
+ element: `<g transform="matrix(-1 0 0 1 0 0)">${element}</g>`
61
+ };
62
+ }
63
+ else {
64
+ return { bbox, element };
65
+ }
66
+ }
67
+ line(entity) {
68
+ const bbox = new Box2D()
69
+ .expandByPoint({ x: entity.startPoint.x, y: entity.startPoint.y })
70
+ .expandByPoint({ x: entity.endPoint.x, y: entity.endPoint.y });
71
+ const element = `<line x1="${entity.startPoint.x}" y1="${entity.startPoint.y}" x2="${entity.endPoint.x}" y2="${entity.endPoint.y}" />`;
72
+ return { bbox, element };
73
+ }
74
+ ray(entity) {
75
+ const scale = 10000;
76
+ const firstPoint = entity.firstPoint;
77
+ const secondPoint = {
78
+ x: firstPoint.x + entity.unitDirection.x * scale,
79
+ y: firstPoint.y + entity.unitDirection.y * scale
80
+ };
81
+ const bbox = new Box2D()
82
+ .expandByPoint(firstPoint)
83
+ .expandByPoint(secondPoint);
84
+ const element = `<line x1="${firstPoint.x}" y1="${firstPoint.y}" x2="${secondPoint.x}" y2="${secondPoint.y}" />`;
85
+ return { bbox, element };
86
+ }
87
+ xline(entity) {
88
+ const scale = 10000;
89
+ const firstPoint = {
90
+ x: entity.firstPoint.x - entity.unitDirection.x * scale,
91
+ y: entity.firstPoint.y - entity.unitDirection.y * scale
92
+ };
93
+ const secondPoint = {
94
+ x: entity.firstPoint.x + entity.unitDirection.x * scale,
95
+ y: entity.firstPoint.y + entity.unitDirection.y * scale
96
+ };
97
+ const bbox = new Box2D()
98
+ .expandByPoint(firstPoint)
99
+ .expandByPoint(secondPoint);
100
+ const element = `<line x1="${firstPoint.x}" y1="${firstPoint.y}" x2="${secondPoint.x}" y2="${secondPoint.y}" />`;
101
+ return { bbox, element };
102
+ }
103
+ extractMTextLines(mtext) {
104
+ return (mtext
105
+ // Convert Unicode codes to characters
106
+ .replace(/\\U\+([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
107
+ // Preserve line breaks: replace \P with newline placeholder
108
+ .replace(/\\P/g, '\n')
109
+ // Remove underline, overline
110
+ .replace(/\\[LOlo]/g, '')
111
+ // Remove font specs like \FArial|b0|i0|c134|p49;
112
+ .replace(/\\[Ff][^;\\]*?(?:\|[^;\\]*)*;/g, '')
113
+ // Remove formatting codes like \H1.0x; \W0.5; \C7 etc.
114
+ .replace(/\\[KkCcHhWwTtAa][^;\\]*;?/g, '')
115
+ // Remove general \word; style control codes like \x; \pxqc;
116
+ .replace(/\\[a-zA-Z]+;?/g, '')
117
+ // Remove AutoCAD %% control sequences like %%d, %%p, etc.
118
+ .replace(/%%(d|p|c|%)/gi, '')
119
+ // Replace escaped backslash
120
+ .replace(/\\\\/g, '\\')
121
+ // Replace non-breaking space
122
+ .replace(/\\~/g, '\u00A0')
123
+ // Remove grouping braces
124
+ .replace(/[{}]/g, '')
125
+ // Split by preserved newlines
126
+ .split('\n')
127
+ .map(line => line.trim())
128
+ .filter(line => line.length > 0));
129
+ }
130
+ lines(lines, fontsize, insertionPoint, extentsWidth, anchor = 'start') {
131
+ const bbox = new Box2D()
132
+ .expandByPoint({
133
+ x: insertionPoint.x,
134
+ y: insertionPoint.y
135
+ })
136
+ .expandByPoint({
137
+ x: insertionPoint.x + extentsWidth,
138
+ y: insertionPoint.y - lines.length * fontsize * 1.5
139
+ });
140
+ const texts = lines.map((line, index) => {
141
+ const x = insertionPoint.x;
142
+ const y = insertionPoint.y - index * fontsize * 1.5;
143
+ const transform = `translate(${x},${y}) scale(1,-1) translate(${-x},${-y})`;
144
+ return `<text x="${x}" y="${y}" font-size="${fontsize}" text-anchor="${anchor}" transform="${transform}">${line}</text>`;
145
+ });
146
+ return { bbox, element: texts.join('\n') };
147
+ }
148
+ mtext(entity) {
149
+ const fontsize = entity.textHeight;
150
+ const insertionPoint = entity.insertionPoint;
151
+ const lines = this.extractMTextLines(entity.text);
152
+ const attachmentPoint = entity.attachmentPoint;
153
+ let anchor = 'start';
154
+ if (attachmentPoint == DwgAttachmentPoint.BottomCenter ||
155
+ attachmentPoint == DwgAttachmentPoint.MiddleCenter ||
156
+ attachmentPoint == DwgAttachmentPoint.TopCenter) {
157
+ anchor = 'middle';
158
+ }
159
+ else if (attachmentPoint == DwgAttachmentPoint.BottomRight ||
160
+ attachmentPoint == DwgAttachmentPoint.MiddleRight ||
161
+ attachmentPoint == DwgAttachmentPoint.TopRight) {
162
+ anchor = 'end';
163
+ }
164
+ return this.lines(lines, fontsize, insertionPoint, entity.extentsWidth, anchor);
165
+ }
166
+ table(entity) {
167
+ const { rowCount, columnCount, rowHeightArr, columnWidthArr, startPoint, cells } = entity;
168
+ const originX = startPoint.x;
169
+ const originY = startPoint.y;
170
+ // Compute cell rectangles
171
+ const cellRects = [];
172
+ for (let row = 0, y = originY; row < rowCount; row++) {
173
+ const height = rowHeightArr[row];
174
+ let x = originX;
175
+ for (let col = 0; col < columnCount; col++) {
176
+ const cellIndex = row * columnCount + col;
177
+ const cell = cells[cellIndex];
178
+ const width = columnWidthArr[col];
179
+ cellRects.push({ x, y, width, height, cell, row, col });
180
+ x += width;
181
+ }
182
+ y += height;
183
+ }
184
+ // Create SVG content
185
+ const svgElements = cellRects
186
+ .map(({ x, y, width, height, cell }) => {
187
+ const lines = [];
188
+ if (cell.topBorderVisibility)
189
+ lines.push(`<line x1="${x}" y1="${y}" x2="${x + width}" y2="${y}" stroke="black" />`);
190
+ if (cell.bottomBorderVisibility)
191
+ lines.push(`<line x1="${x}" y1="${y + height}" x2="${x + width}" y2="${y + height}" stroke="black" />`);
192
+ if (cell.leftBorderVisibility)
193
+ lines.push(`<line x1="${x}" y1="${y}" x2="${x}" y2="${y + height}" stroke="black" />`);
194
+ if (cell.rightBorderVisibility)
195
+ lines.push(`<line x1="${x + width}" y1="${y}" x2="${x + width}" y2="${y + height}" stroke="black" />`);
196
+ const textX = x + width / 2;
197
+ const textY = y + height / 2 + cell.textHeight / 3;
198
+ const text = `<text x="${textX}" y="${textY}" font-size="${cell.textHeight}" text-anchor="middle" dominant-baseline="middle">${cell.text}</text>`;
199
+ return [...lines, text].join('\n');
200
+ })
201
+ .join('\n');
202
+ const totalWidth = columnWidthArr.reduce((sum, w) => sum + w, 0);
203
+ const totalHeight = rowHeightArr.reduce((sum, h) => sum + h, 0);
204
+ const bbox = new Box2D()
205
+ .expandByPoint({ x: originX, y: originY })
206
+ .expandByPoint({ x: originX + totalWidth, y: originY + totalHeight });
207
+ const svg = `
208
+ <svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="${totalHeight}" viewBox="${originX} ${originY} ${totalWidth} ${totalHeight}">
209
+ ${svgElements}
210
+ </svg>
211
+ `.trim();
212
+ return {
213
+ bbox,
214
+ element: svg
215
+ };
216
+ }
217
+ text(entity) {
218
+ const fontsize = entity.textHeight;
219
+ const insertionPoint = entity.startPoint;
220
+ const lines = [entity.text];
221
+ let extentsWidth = entity.endPoint.x - entity.endPoint.x;
222
+ if (entity.halign == 0) {
223
+ extentsWidth = entity.text.length * fontsize + entity.startPoint.x;
224
+ }
225
+ let anchor = 'start';
226
+ if (entity.halign == DwgTextHorizontalAlign.CENTER) {
227
+ anchor = 'middle';
228
+ }
229
+ else if (entity.halign == DwgTextHorizontalAlign.RIGHT) {
230
+ anchor = 'end';
231
+ }
232
+ return this.lines(lines, fontsize, insertionPoint, extentsWidth, anchor);
233
+ }
234
+ vertices(vertices, closed = false) {
235
+ const bbox = vertices.reduce((acc, point) => acc.expandByPoint(point), new Box2D());
236
+ let d = vertices.reduce((acc, point, i) => {
237
+ acc += i === 0 ? 'M' : 'L';
238
+ acc += point.x + ',' + point.y;
239
+ return acc;
240
+ }, '');
241
+ if (closed) {
242
+ d += 'Z';
243
+ }
244
+ return { bbox, element: `<path d="${d}" />` };
245
+ }
246
+ circle(entity) {
247
+ const bbox0 = new Box2D()
248
+ .expandByPoint({
249
+ x: entity.center.x + entity.radius,
250
+ y: entity.center.y + entity.radius
251
+ })
252
+ .expandByPoint({
253
+ x: entity.center.x - entity.radius,
254
+ y: entity.center.y - entity.radius
255
+ });
256
+ const element0 = `<circle cx="${entity.center.x}" cy="${entity.center.y}" r="${entity.radius}" />`;
257
+ return {
258
+ bbox: bbox0,
259
+ element: element0
260
+ };
261
+ }
262
+ ellipseOrArc(cx, cy, majorX, majorY, axisRatio, startAngle, endAngle) {
263
+ const rx = Math.sqrt(majorX * majorX + majorY * majorY);
264
+ const ry = axisRatio * rx;
265
+ const rotationAngle = -Math.atan2(-majorY, majorX);
266
+ const bbox = this.bboxEllipseOrArc(cx, cy, majorX, majorY, axisRatio, startAngle, endAngle);
267
+ if (Math.abs(startAngle - endAngle) < 1e-9 ||
268
+ Math.abs(startAngle - endAngle + Math.PI * 2) < 1e-9) {
269
+ const element = `<g transform="rotate(${(rotationAngle / Math.PI) * 180} ${cx}, ${cy})"><ellipse cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}" /></g>`;
270
+ return { bbox, element };
271
+ }
272
+ else {
273
+ const startOffset = this.rotate({ x: Math.cos(startAngle) * rx, y: Math.sin(startAngle) * ry }, rotationAngle);
274
+ const startPoint = { x: cx + startOffset.x, y: cy + startOffset.y };
275
+ const endOffset = this.rotate({ x: Math.cos(endAngle) * rx, y: Math.sin(endAngle) * ry }, rotationAngle);
276
+ const endPoint = { x: cx + endOffset.x, y: cy + endOffset.y };
277
+ const adjustedEndAngle = endAngle < startAngle ? endAngle + Math.PI * 2 : endAngle;
278
+ const largeArcFlag = adjustedEndAngle - startAngle < Math.PI ? 0 : 1;
279
+ const d = `M ${startPoint.x} ${startPoint.y} A ${rx} ${ry} ${(rotationAngle / Math.PI) * 180} ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`;
280
+ const element = `<path d="${d}" />`;
281
+ return { bbox, element };
282
+ }
283
+ }
284
+ bboxEllipseOrArc(cx, cy, majorX, majorY, axisRatio, startAngle, endAngle) {
285
+ while (startAngle < 0)
286
+ startAngle += Math.PI * 2;
287
+ while (endAngle <= startAngle)
288
+ endAngle += Math.PI * 2;
289
+ const angles = [];
290
+ if (Math.abs(majorX) < 1e-12 || Math.abs(majorY) < 1e-12) {
291
+ for (let i = 0; i < 4; i++) {
292
+ angles.push((i / 2) * Math.PI);
293
+ }
294
+ }
295
+ else {
296
+ angles[0] = Math.atan((-majorY * axisRatio) / majorX) - Math.PI;
297
+ angles[1] = Math.atan((majorX * axisRatio) / majorY) - Math.PI;
298
+ angles[2] = angles[0] - Math.PI;
299
+ angles[3] = angles[1] - Math.PI;
300
+ }
301
+ for (let i = 4; i >= 0; i--) {
302
+ while (angles[i] < startAngle)
303
+ angles[i] += Math.PI * 2;
304
+ if (angles[i] > endAngle) {
305
+ angles.splice(i, 1);
306
+ }
307
+ }
308
+ angles.push(startAngle);
309
+ angles.push(endAngle);
310
+ const pts = angles.map(a => ({ x: Math.cos(a), y: Math.sin(a) }));
311
+ const M = [
312
+ [majorX, -majorY * axisRatio],
313
+ [majorY, majorX * axisRatio]
314
+ ];
315
+ const rotatedPts = pts.map(p => ({
316
+ x: p.x * M[0][0] + p.y * M[0][1] + cx,
317
+ y: p.x * M[1][0] + p.y * M[1][1] + cy
318
+ }));
319
+ const bbox = rotatedPts.reduce((acc, p) => {
320
+ acc.expandByPoint(p);
321
+ return acc;
322
+ }, new Box2D());
323
+ return bbox;
324
+ }
325
+ ellipse(entity) {
326
+ const { bbox: bbox0, element: element0 } = this.ellipseOrArc(entity.center.x, entity.center.y, entity.majorAxisEndPoint.x, entity.majorAxisEndPoint.y, entity.axisRatio, entity.startAngle, entity.endAngle);
327
+ return {
328
+ bbox: bbox0,
329
+ element: element0
330
+ };
331
+ }
332
+ arc(entity) {
333
+ const { bbox: bbox0, element: element0 } = this.ellipseOrArc(entity.center.x, entity.center.y, entity.radius, 0, 1, entity.startAngle, entity.endAngle);
334
+ return {
335
+ bbox: bbox0,
336
+ element: element0
337
+ };
338
+ }
339
+ dimension(entity) {
340
+ const block = this.blockMap.get(entity.name);
341
+ if (block) {
342
+ return {
343
+ bbox: block.bbox,
344
+ element: `<use href="#${entity.name}" />`
345
+ };
346
+ }
347
+ return null;
348
+ }
349
+ insert(entity) {
350
+ const block = this.blockMap.get(entity.name);
351
+ if (block) {
352
+ // In SVG, the unit of rotate is degrees — not radians.
353
+ const insertionPoint = entity.insertionPoint;
354
+ // const basePoint = block.bbox.min
355
+ const rotation = entity.rotation * (180 / Math.PI);
356
+ const transform = `translate(${insertionPoint.x},${insertionPoint.y}) rotate(${rotation}) scale(${entity.xScale},${entity.yScale})`;
357
+ const newBBox = block.bbox
358
+ .clone()
359
+ .transform({ x: entity.xScale, y: entity.yScale }, { x: insertionPoint.x, y: insertionPoint.y })
360
+ .rotate(entity.rotation, insertionPoint);
361
+ return {
362
+ bbox: newBBox,
363
+ element: `<use href="#${entity.name}" transform="${transform}" />`
364
+ };
365
+ }
366
+ return null;
367
+ }
368
+ block(block, dwg) {
369
+ const entities = block.entities;
370
+ const { bbox, elements } = entities.reduce((acc, entity) => {
371
+ const boundsAndElement = this.entityToBoundsAndElement(entity);
372
+ if (boundsAndElement) {
373
+ const { bbox, element } = boundsAndElement;
374
+ if (bbox.valid) {
375
+ acc.bbox.expandByPoint(bbox.min);
376
+ acc.bbox.expandByPoint(bbox.max);
377
+ }
378
+ const color = this.getEntityColor(dwg.tables.LAYER.entries, entity);
379
+ const fill = entity.type == 'TEXT' || entity.type == 'MTEXT'
380
+ ? color.cssColor
381
+ : 'none';
382
+ if (color.isByBlock) {
383
+ acc.elements.push(`<g id="${entity.handle}">${element}</g>`);
384
+ }
385
+ else {
386
+ acc.elements.push(`<g id="${entity.handle}" stroke="${color.cssColor}" fill="${fill}">${element}</g>`);
387
+ }
388
+ }
389
+ return acc;
390
+ }, {
391
+ bbox: new Box2D(),
392
+ elements: []
393
+ });
394
+ if (bbox.valid) {
395
+ return {
396
+ bbox,
397
+ element: `<g id="${block.name}">${elements.join('\n')}</g>`
398
+ };
399
+ }
400
+ return null;
401
+ }
402
+ entityToBoundsAndElement(entity) {
403
+ let result = null;
404
+ switch (entity.type) {
405
+ case 'ARC':
406
+ result = this.arc(entity);
407
+ break;
408
+ case 'CIRCLE':
409
+ result = this.circle(entity);
410
+ break;
411
+ case 'DIMENSION':
412
+ result = this.dimension(entity);
413
+ break;
414
+ case 'ELLIPSE':
415
+ result = this.ellipse(entity);
416
+ break;
417
+ case 'INSERT':
418
+ result = this.insert(entity);
419
+ break;
420
+ case 'LINE':
421
+ result = this.line(entity);
422
+ break;
423
+ case 'LWPOLYLINE': {
424
+ const lwpolyline = entity;
425
+ const closed = !!(lwpolyline.flag & 0x200);
426
+ const vertices = interpolatePolyline(lwpolyline, closed);
427
+ result = this.vertices(vertices, closed);
428
+ break;
429
+ }
430
+ case 'MTEXT':
431
+ result = this.mtext(entity);
432
+ break;
433
+ case 'SPLINE': {
434
+ const spline = entity;
435
+ result = this.vertices(this.interpolateBSpline(spline.controlPoints, spline.degree, spline.knots, 25, spline.weights));
436
+ break;
437
+ }
438
+ case 'POLYLINE': {
439
+ // const polyline = entity as DwgPolylineEntity
440
+ // const closed = !!(polyline.flag & 0x1)
441
+ // const vertices = interpolatePolyline(polyline, closed)
442
+ // result = this.vertices(vertices, closed)
443
+ break;
444
+ }
445
+ case 'RAY':
446
+ result = this.ray(entity);
447
+ break;
448
+ case 'TABLE':
449
+ case 'ACAD_TABLE':
450
+ result = this.table(entity);
451
+ break;
452
+ case 'TEXT':
453
+ result = this.text(entity);
454
+ break;
455
+ case 'XLINE':
456
+ result = this.xline(entity);
457
+ break;
458
+ default:
459
+ result = null;
460
+ break;
461
+ }
462
+ if (result) {
463
+ return this.addFlipXIfApplicable(entity, result);
464
+ }
465
+ return null;
466
+ }
467
+ getEntityColor(layers, entity) {
468
+ // Get entity color
469
+ const color = new Color();
470
+ if (entity.colorIndex != null) {
471
+ color.colorIndex = entity.colorIndex;
472
+ }
473
+ else if (entity.colorName) {
474
+ color.colorName = entity.colorName;
475
+ }
476
+ else if (entity.color != null) {
477
+ color.color = entity.color;
478
+ }
479
+ // ACI 7 is one background-dependent color
480
+ if (color.colorIndex == 7) {
481
+ color.colorIndex = 256;
482
+ }
483
+ // If color is 'byLayer', use the layer color
484
+ if (color.isByLayer) {
485
+ const layer = layers.find((layer) => layer.name === entity.layer);
486
+ if (layer != null) {
487
+ color.colorIndex = layer.colorIndex;
488
+ }
489
+ }
490
+ if (color.color == null) {
491
+ color.color = 0xffffff;
492
+ }
493
+ return color;
494
+ }
495
+ convert(dwg) {
496
+ let modelSpace = null;
497
+ this.blockMap.clear();
498
+ let blockElements = '';
499
+ dwg.tables.BLOCK_RECORD.entries.forEach(block => {
500
+ if (isModelSpace(block.name)) {
501
+ modelSpace = block;
502
+ }
503
+ else {
504
+ const item = this.block(block, dwg);
505
+ if (item) {
506
+ blockElements += item.element;
507
+ this.blockMap.set(block.name, item);
508
+ }
509
+ }
510
+ });
511
+ const ms = this.block(modelSpace, dwg);
512
+ const viewBox = ms && ms.bbox.valid
513
+ ? {
514
+ x: ms.bbox.min.x,
515
+ y: -ms.bbox.max.y,
516
+ width: ms.bbox.max.x - ms.bbox.min.x,
517
+ height: ms.bbox.max.y - ms.bbox.min.y
518
+ }
519
+ : {
520
+ x: 0,
521
+ y: 0,
522
+ width: 0,
523
+ height: 0
524
+ };
525
+ return `<?xml version="1.0"?>
526
+ <svg
527
+ xmlns="http://www.w3.org/2000/svg"
528
+ xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
529
+ preserveAspectRatio="xMinYMin meet"
530
+ viewBox="${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}"
531
+ width="100%" height="100%"
532
+ >
533
+ <defs>${blockElements}</defs>
534
+ <g stroke="#000000" stroke-width="0.1%" fill="none" transform="matrix(1,0,0,-1,0,0)">
535
+ ${ms ? ms.element : ''}
536
+ </g>
537
+ </svg>`;
538
+ }
539
+ }
540
+ //# sourceMappingURL=svgConverter.js.map
@@ -0,0 +1,20 @@
1
+ export const transformBoundingBoxAndElement = (bbox, element, transforms = undefined) => {
2
+ if (!transforms || transforms.length === 0) {
3
+ return { bbox, element };
4
+ }
5
+ let transformedElement = element;
6
+ transforms.forEach(transform => {
7
+ // Apply each transformation to the element
8
+ if (transform.type === 'translate') {
9
+ transformedElement = `<g transform="translate(${transform.x}, ${transform.y})">${transformedElement}</g>`;
10
+ }
11
+ else if (transform.type === 'rotate') {
12
+ transformedElement = `<g transform="rotate(${transform.angle})">${transformedElement}</g>`;
13
+ }
14
+ else if (transform.type === 'scale') {
15
+ transformedElement = `<g transform="scale(${transform.x}, ${transform.y})">${transformedElement}</g>`;
16
+ }
17
+ });
18
+ return { bbox, element: transformedElement };
19
+ };
20
+ //# sourceMappingURL=transformBoundingBoxAndElement.js.map
@@ -0,0 +1,27 @@
1
+ export class Vector2D {
2
+ x;
3
+ y;
4
+ constructor(x, y) {
5
+ this.x = x;
6
+ this.y = y;
7
+ }
8
+ add(v) {
9
+ return new Vector2D(this.x + v.x, this.y + v.y);
10
+ }
11
+ sub(v) {
12
+ return new Vector2D(this.x - v.x, this.y - v.y);
13
+ }
14
+ multiply(scalar) {
15
+ return new Vector2D(this.x * scalar, this.y * scalar);
16
+ }
17
+ length() {
18
+ return Math.sqrt(this.x ** 2 + this.y ** 2);
19
+ }
20
+ norm() {
21
+ const len = this.length();
22
+ if (len === 0)
23
+ return new Vector2D(0, 0);
24
+ return new Vector2D(this.x / len, this.y / len);
25
+ }
26
+ }
27
+ //# sourceMappingURL=vector.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=common.js.map