@linkiez/dxf-renew 5.3.1 → 7.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 (133) hide show
  1. package/{docs/CODE_PATTERNS.md → .github/instructions/code-patterns.instructions.md} +4 -1
  2. package/.github/instructions/exdxf.instruction.md +161 -0
  3. package/.github/instructions/tdd.instructions.md +271 -0
  4. package/.github/workflows/release.yml +4 -5
  5. package/.releaserc.json +1 -1
  6. package/.yarn/install-state.gz +0 -0
  7. package/CHANGELOG.md +59 -0
  8. package/CONTRIBUTING.md +16 -14
  9. package/PLAN.md +34 -84
  10. package/README.md +43 -8
  11. package/dist/dxf.js +1388 -376
  12. package/docs/DIMENSION_SUMMARY.md +11 -5
  13. package/docs/DXF_VERSION_SUPPORT.md +45 -0
  14. package/docs/ENTITY_SVG_ROADMAP.md +96 -0
  15. package/docs/EZDXF_REFERENCE_SITEMAP.md +55 -0
  16. package/docs/FIXTURE_VALIDATION_EZDXF.md +62 -0
  17. package/docs/README.md +22 -0
  18. package/docs/SVG_RENDERING_INTEGRATION_TESTS.md +119 -0
  19. package/docs/TEXT-MTEXT-DIMENSION-SUPPORT.md +1 -1
  20. package/lib/Helper.cjs +2 -2
  21. package/lib/Helper.cjs.map +2 -2
  22. package/lib/Helper.js +2 -2
  23. package/lib/Helper.js.map +2 -2
  24. package/lib/denormalise.cjs +131 -91
  25. package/lib/denormalise.cjs.map +2 -2
  26. package/lib/denormalise.js +131 -91
  27. package/lib/denormalise.js.map +2 -2
  28. package/lib/dimensionToSVG.cjs +318 -53
  29. package/lib/dimensionToSVG.cjs.map +3 -3
  30. package/lib/dimensionToSVG.js +316 -52
  31. package/lib/dimensionToSVG.js.map +2 -2
  32. package/lib/handlers/entities.cjs +90 -26
  33. package/lib/handlers/entities.cjs.map +3 -3
  34. package/lib/handlers/entities.js +90 -26
  35. package/lib/handlers/entities.js.map +3 -3
  36. package/lib/handlers/entity/dgnUnderlay.cjs +106 -0
  37. package/lib/handlers/entity/dgnUnderlay.cjs.map +7 -0
  38. package/lib/handlers/entity/dgnUnderlay.js +71 -0
  39. package/lib/handlers/entity/dgnUnderlay.js.map +7 -0
  40. package/lib/handlers/entity/dimension.cjs +24 -0
  41. package/lib/handlers/entity/dimension.cjs.map +2 -2
  42. package/lib/handlers/entity/dimension.js +24 -0
  43. package/lib/handlers/entity/dimension.js.map +2 -2
  44. package/lib/handlers/entity/dwfUnderlay.cjs +106 -0
  45. package/lib/handlers/entity/dwfUnderlay.cjs.map +7 -0
  46. package/lib/handlers/entity/dwfUnderlay.js +71 -0
  47. package/lib/handlers/entity/dwfUnderlay.js.map +7 -0
  48. package/lib/handlers/entity/image.cjs +123 -0
  49. package/lib/handlers/entity/image.cjs.map +7 -0
  50. package/lib/handlers/entity/image.js +88 -0
  51. package/lib/handlers/entity/image.js.map +7 -0
  52. package/lib/handlers/entity/leader.cjs +148 -0
  53. package/lib/handlers/entity/leader.cjs.map +7 -0
  54. package/lib/handlers/entity/leader.js +113 -0
  55. package/lib/handlers/entity/leader.js.map +7 -0
  56. package/lib/handlers/entity/pdfUnderlay.cjs +106 -0
  57. package/lib/handlers/entity/pdfUnderlay.cjs.map +7 -0
  58. package/lib/handlers/entity/pdfUnderlay.js +71 -0
  59. package/lib/handlers/entity/pdfUnderlay.js.map +7 -0
  60. package/lib/handlers/entity/tolerance.cjs +90 -0
  61. package/lib/handlers/entity/tolerance.cjs.map +7 -0
  62. package/lib/handlers/entity/tolerance.js +55 -0
  63. package/lib/handlers/entity/tolerance.js.map +7 -0
  64. package/lib/handlers/objects.cjs +257 -136
  65. package/lib/handlers/objects.cjs.map +2 -2
  66. package/lib/handlers/objects.js +257 -136
  67. package/lib/handlers/objects.js.map +2 -2
  68. package/lib/toSVG.cjs +71 -8
  69. package/lib/toSVG.cjs.map +3 -3
  70. package/lib/toSVG.js +72 -9
  71. package/lib/toSVG.js.map +2 -2
  72. package/lib/types/dimension-entity.cjs.map +1 -1
  73. package/lib/types/entity.cjs.map +1 -1
  74. package/lib/types/image-entity.cjs +17 -0
  75. package/lib/types/image-entity.cjs.map +7 -0
  76. package/lib/types/image-entity.js +1 -0
  77. package/lib/types/image-entity.js.map +7 -0
  78. package/lib/types/index.cjs +8 -0
  79. package/lib/types/index.cjs.map +2 -2
  80. package/lib/types/index.js +4 -0
  81. package/lib/types/index.js.map +2 -2
  82. package/lib/types/leader-entity.cjs +17 -0
  83. package/lib/types/leader-entity.cjs.map +7 -0
  84. package/lib/types/leader-entity.js +1 -0
  85. package/lib/types/leader-entity.js.map +7 -0
  86. package/lib/types/options.cjs.map +1 -1
  87. package/lib/types/tables.cjs.map +1 -1
  88. package/lib/types/tolerance-entity.cjs +17 -0
  89. package/lib/types/tolerance-entity.cjs.map +7 -0
  90. package/lib/types/tolerance-entity.js +1 -0
  91. package/lib/types/tolerance-entity.js.map +7 -0
  92. package/lib/types/underlay-entity.cjs +17 -0
  93. package/lib/types/underlay-entity.cjs.map +7 -0
  94. package/lib/types/underlay-entity.js +1 -0
  95. package/lib/types/underlay-entity.js.map +7 -0
  96. package/lib/util/escapeXmlText.cjs +27 -0
  97. package/lib/util/escapeXmlText.cjs.map +7 -0
  98. package/lib/util/escapeXmlText.js +7 -0
  99. package/lib/util/escapeXmlText.js.map +7 -0
  100. package/package.json +13 -4
  101. package/playwright.config.cjs +20 -0
  102. package/src/Helper.ts +3 -3
  103. package/src/denormalise.ts +182 -116
  104. package/src/dimensionToSVG.ts +466 -54
  105. package/src/handlers/entities.ts +109 -34
  106. package/src/handlers/entity/dgnUnderlay.ts +94 -0
  107. package/src/handlers/entity/dimension.ts +27 -1
  108. package/src/handlers/entity/dwfUnderlay.ts +94 -0
  109. package/src/handlers/entity/image.ts +118 -0
  110. package/src/handlers/entity/leader.ts +153 -0
  111. package/src/handlers/entity/pdfUnderlay.ts +94 -0
  112. package/src/handlers/entity/tolerance.ts +75 -0
  113. package/src/handlers/objects.ts +323 -139
  114. package/src/toSVG.ts +98 -7
  115. package/src/types/dimension-entity.ts +11 -0
  116. package/src/types/entity.ts +10 -0
  117. package/src/types/image-entity.ts +35 -0
  118. package/src/types/index.ts +4 -0
  119. package/src/types/leader-entity.ts +40 -0
  120. package/src/types/options.ts +41 -0
  121. package/src/types/tables.ts +84 -0
  122. package/src/types/tolerance-entity.ts +20 -0
  123. package/src/types/underlay-entity.ts +35 -0
  124. package/src/util/escapeXmlText.ts +10 -0
  125. package/tools/browser_test_server.cjs +87 -0
  126. package/tools/ezdxf_generate_dimensions_all_types.py +246 -0
  127. package/tools/ezdxf_generate_dimensions_angular_3p.py +59 -0
  128. package/tools/ezdxf_generate_dimensions_large_scale.py +87 -0
  129. package/tools/ezdxf_regenerate_problem_fixtures.py +184 -0
  130. package/tools/ezdxf_validate_fixtures.py +165 -0
  131. package/docs/DIMENSION_SUMMARY.pt-BR.md +0 -248
  132. package/docs/IMPLEMENTED-2D-ENTITIES.pt-BR.md +0 -54
  133. package/docs/TEXT-MTEXT-DIMENSION-SUPPORT.pt-BR.md +0 -169
package/lib/toSVG.cjs CHANGED
@@ -37,6 +37,7 @@ var import_denormalise = __toESM(require("./denormalise"), 1);
37
37
  var import_dimensionToSVG = __toESM(require("./dimensionToSVG"), 1);
38
38
  var import_entityToPolyline = __toESM(require("./entityToPolyline"), 1);
39
39
  var import_getRGBForEntity = __toESM(require("./getRGBForEntity"), 1);
40
+ var import_escapeXmlText = __toESM(require("./util/escapeXmlText"), 1);
40
41
  var import_logger = __toESM(require("./util/logger"), 1);
41
42
  var import_rgbToColorAttribute = __toESM(require("./util/rgbToColorAttribute"), 1);
42
43
  var import_rotate = __toESM(require("./util/rotate"), 1);
@@ -93,6 +94,23 @@ const lwpolyline = (entity) => {
93
94
  entity.transforms ?? []
94
95
  );
95
96
  };
97
+ const leader = (entity) => {
98
+ if (!entity.vertices || entity.vertices.length < 2) return null;
99
+ const bbox0 = entity.vertices.reduce(
100
+ (acc, p) => acc.expandByPoint({ x: p.x, y: p.y }),
101
+ new import_vecks.Box2()
102
+ );
103
+ const d = entity.vertices.reduce((acc, p, i) => {
104
+ acc += i === 0 ? "M" : "L";
105
+ acc += p.x + "," + p.y;
106
+ return acc;
107
+ }, "");
108
+ return (0, import_transformBoundingBoxAndElement.default)(
109
+ bbox0,
110
+ `<path d="${d}" />`,
111
+ entity.transforms ?? []
112
+ );
113
+ };
96
114
  const circle = (entity) => {
97
115
  const bbox0 = new import_vecks.Box2().expandByPoint({
98
116
  x: entity.x + entity.r,
@@ -232,7 +250,7 @@ const text = (entity) => {
232
250
  const textWidth = content.length * height * 0.6;
233
251
  const bbox0 = new import_vecks.Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
234
252
  const rotationDegrees = rotation * 180 / Math.PI;
235
- const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${content}</text>`;
253
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${(0, import_escapeXmlText.default)(content)}</text>`;
236
254
  const { bbox, element } = addFlipXIfApplicable(entity, {
237
255
  bbox: bbox0,
238
256
  element: element0
@@ -248,15 +266,31 @@ const mtext = (entity) => {
248
266
  const bbox0 = new import_vecks.Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
249
267
  const rotation = entity.xAxisX !== void 0 && entity.xAxisY !== void 0 ? Math.atan2(entity.xAxisY, entity.xAxisX) : 0;
250
268
  const rotationDegrees = rotation * 180 / Math.PI;
251
- const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${content}</text>`;
269
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${(0, import_escapeXmlText.default)(content)}</text>`;
252
270
  const { bbox, element } = addFlipXIfApplicable(entity, {
253
271
  bbox: bbox0,
254
272
  element: element0
255
273
  });
256
274
  return (0, import_transformBoundingBoxAndElement.default)(bbox, element, entity.transforms ?? []);
257
275
  };
258
- const dimension = (entity, dimStyle) => {
259
- const result = (0, import_dimensionToSVG.default)(entity, dimStyle);
276
+ const tolerance = (entity) => {
277
+ const x = entity.insertionPoint?.x ?? 0;
278
+ const y = entity.insertionPoint?.y ?? 0;
279
+ const height = 1;
280
+ const content = entity.text ?? "";
281
+ const rotation = entity.xAxisDirection ? Math.atan2(entity.xAxisDirection.y, entity.xAxisDirection.x) : 0;
282
+ const rotationDegrees = rotation * 180 / Math.PI;
283
+ const textWidth = content.length * height * 0.6;
284
+ const bbox0 = new import_vecks.Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
285
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${(0, import_escapeXmlText.default)(content)}</text>`;
286
+ const { bbox, element } = addFlipXIfApplicable(entity, {
287
+ bbox: bbox0,
288
+ element: element0
289
+ });
290
+ return (0, import_transformBoundingBoxAndElement.default)(bbox, element, entity.transforms ?? []);
291
+ };
292
+ const dimension = (entity, dimStyle, options, viewport) => {
293
+ const result = (0, import_dimensionToSVG.default)(entity, dimStyle, options, viewport);
260
294
  return (0, import_transformBoundingBoxAndElement.default)(
261
295
  result.bbox,
262
296
  result.element,
@@ -295,7 +329,7 @@ const bezier = (entity) => {
295
329
  const element = `<g>${paths.join("")}</g>`;
296
330
  return (0, import_transformBoundingBoxAndElement.default)(bbox, element, entity.transforms ?? []);
297
331
  };
298
- const entityToBoundsAndElement = (entity, dimStyles) => {
332
+ const entityToBoundsAndElement = (entity, dimStyles, options, viewport) => {
299
333
  switch (entity.type) {
300
334
  case "CIRCLE":
301
335
  return circle(entity);
@@ -311,7 +345,7 @@ const entityToBoundsAndElement = (entity, dimStyles) => {
311
345
  const dimEntity = entity;
312
346
  const styleName = typeof dimEntity.styleName === "string" ? dimEntity.styleName : void 0;
313
347
  const dimStyle = styleName && dimStyles ? dimStyles[styleName] : void 0;
314
- return dimension(dimEntity, dimStyle);
348
+ return dimension(dimEntity, dimStyle, options, viewport);
315
349
  }
316
350
  case "SPLINE": {
317
351
  const splineEntity = entity;
@@ -335,18 +369,47 @@ const entityToBoundsAndElement = (entity, dimStyles) => {
335
369
  case "LWPOLYLINE": {
336
370
  return lwpolyline(entity);
337
371
  }
372
+ case "LEADER": {
373
+ return leader(entity);
374
+ }
375
+ case "TOLERANCE": {
376
+ return tolerance(entity);
377
+ }
338
378
  default:
339
379
  import_logger.default.warn("entity type not supported in SVG rendering:", entity.type);
340
380
  return null;
341
381
  }
342
382
  };
343
- function toSVG(parsed) {
383
+ function toSVG(parsed, options = {}) {
344
384
  const entities = (0, import_denormalise.default)(parsed);
345
385
  const dimStyles = parsed.tables.dimStyles;
386
+ const geometryBBox = entities.reduce((acc, entity) => {
387
+ if (entity.type === "DIMENSION") {
388
+ const bbox2 = (0, import_dimensionToSVG.getDimensionGeometryBBox)(entity);
389
+ if (bbox2.valid) {
390
+ acc.expandByPoint(bbox2.min);
391
+ acc.expandByPoint(bbox2.max);
392
+ }
393
+ return acc;
394
+ }
395
+ const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options);
396
+ if (boundsAndElement?.bbox.valid) {
397
+ acc.expandByPoint(boundsAndElement.bbox.min);
398
+ acc.expandByPoint(boundsAndElement.bbox.max);
399
+ }
400
+ return acc;
401
+ }, new import_vecks.Box2());
402
+ const viewport = geometryBBox.valid ? {
403
+ width: geometryBBox.max.x - geometryBBox.min.x,
404
+ height: geometryBBox.max.y - geometryBBox.min.y
405
+ } : {
406
+ width: 0,
407
+ height: 0
408
+ };
346
409
  const { bbox, elements } = entities.reduce(
347
410
  (acc, entity) => {
348
411
  const rgb = (0, import_getRGBForEntity.default)(parsed.tables.layers, entity);
349
- const boundsAndElement = entityToBoundsAndElement(entity, dimStyles);
412
+ const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options, viewport);
350
413
  if (boundsAndElement) {
351
414
  const { bbox: bbox2, element } = boundsAndElement;
352
415
  if (bbox2.valid) {
package/lib/toSVG.cjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/toSVG.ts"],
4
- "sourcesContent": ["import { Box2 } from 'vecks'\n\nimport denormalise from './denormalise'\nimport dimensionToSVG from './dimensionToSVG'\nimport entityToPolyline from './entityToPolyline'\nimport getRGBForEntity from './getRGBForEntity'\nimport logger from './util/logger'\nimport rgbToColorAttribute from './util/rgbToColorAttribute'\nimport rotate from './util/rotate'\nimport toPiecewiseBezier, { multiplicity } from './util/toPiecewiseBezier'\nimport transformBoundingBoxAndElement from './util/transformBoundingBoxAndElement'\n\nimport type {\n ArcEntity,\n CircleEntity,\n DimensionEntity,\n EllipseEntity,\n Entity,\n MTextEntity,\n ParsedDXF,\n SplineEntity,\n TextEntity,\n} from './types'\nimport type { BoundsAndElement } from './types/svg'\n\nconst addFlipXIfApplicable = (\n entity: Entity,\n { bbox, element }: BoundsAndElement,\n): BoundsAndElement => {\n if (entity.extrusionZ === -1) {\n return {\n bbox: new Box2()\n .expandByPoint({ x: -bbox.min.x, y: bbox.min.y })\n .expandByPoint({ x: -bbox.max.x, y: bbox.max.y }),\n element: `<g transform=\"matrix(-1 0 0 1 0 0)\">\n ${element}\n </g>`,\n }\n } else {\n return { bbox, element }\n }\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n */\nconst polyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n // Empirically it appears that flipping horizontally does not apply to polyline\n return transformBoundingBoxAndElement(\n bbox,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n * lwpolyline is the same as polyline but addFlipXIfApplicable does apply\n */\nconst lwpolyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox0 = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n const element0 = `<path d=\"${d}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(\n bbox,\n element,\n entity.transforms ?? [],\n )\n}\n\n\n/**\n * Create a <circle /> element for the CIRCLE entity.\n */\nconst circle = (entity: CircleEntity): BoundsAndElement => {\n const bbox0 = new Box2()\n .expandByPoint({\n x: entity.x + entity.r,\n y: entity.y + entity.r,\n })\n .expandByPoint({\n x: entity.x - entity.r,\n y: entity.y - entity.r,\n })\n const element0 = `<circle cx=\"${entity.x}\" cy=\"${entity.y}\" r=\"${entity.r}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\ninterface EllipticArcParams {\n cx: number\n cy: number\n majorX: number\n majorY: number\n axisRatio: number\n startAngle: number\n endAngle: number\n flipX?: boolean\n}\n\n/**\n * Create a a <path d=\"A...\" /> or <ellipse /> element for the ARC or ELLIPSE\n * DXF entity (<ellipse /> if start and end point are the same).\n */\nconst ellipseOrArc = (params: EllipticArcParams): BoundsAndElement => {\n const { cx, cy, majorX, majorY, axisRatio, startAngle, endAngle } = params\n const rx = Math.hypot(majorX, majorY)\n const ry = axisRatio * rx\n const rotationAngle = -Math.atan2(-majorY, majorX)\n\n const bbox = bboxEllipseOrArc(params)\n\n if (\n Math.abs(startAngle - endAngle) < 1e-9 ||\n Math.abs(startAngle - endAngle + Math.PI * 2) < 1e-9\n ) {\n // Use a native <ellipse> when start and end angles are the same, and\n // arc paths with same start and end points don't render (at least on Safari)\n const element = `<g transform=\"rotate(${\n (rotationAngle / Math.PI) * 180\n } ${cx}, ${cy})\">\n <ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" />\n </g>`\n return { bbox, element }\n } else {\n const startOffset = rotate(\n {\n x: Math.cos(startAngle) * rx,\n y: Math.sin(startAngle) * ry,\n },\n rotationAngle,\n )\n const startPoint = {\n x: cx + startOffset.x,\n y: cy + startOffset.y,\n }\n const endOffset = rotate(\n {\n x: Math.cos(endAngle) * rx,\n y: Math.sin(endAngle) * ry,\n },\n rotationAngle,\n )\n const endPoint = {\n x: cx + endOffset.x,\n y: cy + endOffset.y,\n }\n const adjustedEndAngle =\n endAngle < startAngle ? endAngle + Math.PI * 2 : endAngle\n const largeArcFlag = adjustedEndAngle - startAngle < Math.PI ? 0 : 1\n const d = `M ${startPoint.x} ${startPoint.y} A ${rx} ${ry} ${\n (rotationAngle / Math.PI) * 180\n } ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`\n const element = `<path d=\"${d}\" />`\n return { bbox, element }\n }\n}\n\n/**\n * Compute the bounding box of an elliptical arc, given the DXF entity parameters\n */\n\nconst bboxEllipseOrArc = (params: EllipticArcParams): Box2 => {\n const { cx, cy, majorX, majorY, axisRatio } = params\n let { startAngle, endAngle } = params\n\n // The bounding box will be defined by the starting point of the ellipse, and ending point,\n // and any extrema on the ellipse that are between startAngle and endAngle.\n // The extrema are found by setting either the x or y component of the ellipse's\n // tangent vector to zero and solving for the angle.\n\n // Ensure start and end angles are > 0 and well-ordered\n while (startAngle < 0) startAngle += Math.PI * 2\n while (endAngle <= startAngle) endAngle += Math.PI * 2\n\n // When rotated, the extrema of the ellipse will be found at these angles\n const angles = []\n\n if (Math.abs(majorX) < 1e-12 || Math.abs(majorY) < 1e-12) {\n // Special case for majorX or majorY = 0\n for (let i = 0; i < 4; i++) {\n angles.push((i / 2) * Math.PI)\n }\n } else {\n // reference https://github.com/bjnortier/dxf/issues/47#issuecomment-545915042\n angles[0] = Math.atan((-majorY * axisRatio) / majorX) - Math.PI // Ensure angles < 0\n angles[1] = Math.atan((majorX * axisRatio) / majorY) - Math.PI\n angles[2] = angles[0] - Math.PI\n angles[3] = angles[1] - Math.PI\n }\n\n // Remove angles not falling between start and end\n for (let i = 4; i >= 0; i--) {\n while (angles[i] < startAngle) angles[i] += Math.PI * 2\n if (angles[i] > endAngle) {\n angles.splice(i, 1)\n }\n }\n\n // Also to consider are the starting and ending points:\n angles.push(startAngle, endAngle)\n\n // Compute points lying on the unit circle at these angles\n const pts = angles.map((a) => ({\n x: Math.cos(a),\n y: Math.sin(a),\n }))\n\n // Transformation matrix, formed by the major and minor axes\n const M = [\n [majorX, -majorY * axisRatio],\n [majorY, majorX * axisRatio],\n ]\n\n // Rotate, scale, and translate points\n const rotatedPts = pts.map((p) => ({\n x: p.x * M[0][0] + p.y * M[0][1] + cx,\n y: p.x * M[1][0] + p.y * M[1][1] + cy,\n }))\n\n // Compute extents of bounding box\n const bbox = rotatedPts.reduce((acc, p) => {\n acc.expandByPoint(p)\n return acc\n }, new Box2())\n\n return bbox\n}\n\n/**\n * An ELLIPSE is defined by the major axis, convert to X and Y radius with\n * a rotation angle\n */\nconst ellipse = (entity: EllipseEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.majorX,\n majorY: entity.majorY,\n axisRatio: entity.axisRatio,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * An ARC is an ellipse with equal radii\n */\nconst arc = (entity: ArcEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.r,\n majorY: 0,\n axisRatio: 1,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n flipX: entity.extrusionZ === -1,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for TEXT entity\n */\nconst text = (entity: TextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.textHeight ?? 1\n const rotation = entity.rotation ?? 0\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${content}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for MTEXT entity\n */\nconst mtext = (entity: MTextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.nominalTextHeight ?? entity.textHeight ?? 1\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = (entity.refRectangleWidth ?? content.length * height * 0.6)\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n // Calculate rotation from x-axis direction\n const rotation = entity.xAxisX !== undefined && entity.xAxisY !== undefined\n ? Math.atan2(entity.xAxisY, entity.xAxisX)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${content}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create dimension visualization with DIMSTYLE support\n */\nconst dimension = (\n entity: DimensionEntity,\n dimStyle?: any,\n): BoundsAndElement => {\n const result = dimensionToSVG(entity, dimStyle)\n return transformBoundingBoxAndElement(\n result.bbox,\n result.element,\n entity.transforms ?? [],\n )\n}\n\nexport const piecewiseToPaths = (\n k: number,\n knots: number[],\n controlPoints: Array<{ x: number; y: number }>,\n): string[] => {\n const paths: string[] = []\n let controlPointIndex = 0\n let knotIndex = k\n while (knotIndex < knots.length - k + 1) {\n const m = multiplicity(knots, knotIndex)\n const cp = controlPoints.slice(controlPointIndex, controlPointIndex + k)\n if (k === 4) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} C ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y} ${cp[3].x} ${cp[3].y}\" />`,\n )\n } else if (k === 3) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} Q ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y}\" />`,\n )\n }\n controlPointIndex += m\n knotIndex += m\n }\n return paths\n}\n\nconst bezier = (entity: SplineEntity): BoundsAndElement => {\n let bbox = new Box2()\n for (const p of entity.controlPoints) {\n bbox = bbox.expandByPoint(p)\n }\n const k = entity.degree + 1\n const piecewise = toPiecewiseBezier(k, entity.controlPoints, entity.knots)\n const paths = piecewiseToPaths(k, piecewise.knots, piecewise.controlPoints)\n const element = `<g>${paths.join('')}</g>`\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Switch the appropriate function on entity type. CIRCLE, ARC and ELLIPSE\n * produce native SVG elements, the rest produce interpolated polylines.\n */\nconst entityToBoundsAndElement = (\n entity: Entity,\n dimStyles?: { [name: string]: any },\n): BoundsAndElement | null => {\n switch (entity.type) {\n case 'CIRCLE':\n return circle(entity as CircleEntity)\n case 'ELLIPSE':\n return ellipse(entity as EllipseEntity)\n case 'ARC':\n return arc(entity as ArcEntity)\n case 'TEXT':\n return text(entity as TextEntity)\n case 'MTEXT':\n return mtext(entity as MTextEntity)\n case 'DIMENSION': {\n const dimEntity = entity as DimensionEntity\n const styleName = typeof dimEntity.styleName === 'string'\n ? dimEntity.styleName\n : undefined\n const dimStyle = styleName && dimStyles\n ? dimStyles[styleName]\n : undefined\n return dimension(dimEntity, dimStyle)\n }\n case 'SPLINE': {\n const splineEntity = entity as SplineEntity\n const hasWeights = splineEntity.weights?.some((w: number) => w !== 1)\n if ((splineEntity.degree === 2 || splineEntity.degree === 3) && !hasWeights) {\n try {\n return bezier(splineEntity)\n } catch (err) {\n const error = err as Error\n logger.warn('bezier conversion failed, using polyline:', error.message)\n return polyline(entity)\n }\n } else {\n return polyline(entity)\n }\n }\n case 'LINE':\n case 'POLYLINE': {\n return polyline(entity)\n }\n case 'LWPOLYLINE': {\n return lwpolyline(entity)\n }\n default:\n logger.warn('entity type not supported in SVG rendering:', entity.type)\n return null\n }\n}\n\nexport default function toSVG(parsed: ParsedDXF): string {\n const entities = denormalise(parsed)\n const dimStyles = parsed.tables.dimStyles\n const { bbox, elements } = entities.reduce(\n (\n acc: { bbox: Box2; elements: string[] },\n entity: Entity,\n ): { bbox: Box2; elements: string[] } => {\n const rgb = getRGBForEntity(parsed.tables.layers, entity)\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles)\n // Ignore entities that don't produce SVG elements or have unsupported types\n if (boundsAndElement) {\n const { bbox, element } = boundsAndElement\n // Ignore invalid bounding boxes\n if (bbox.valid) {\n acc.bbox.expandByPoint(bbox.min)\n acc.bbox.expandByPoint(bbox.max)\n }\n acc.elements.push(\n `<g stroke=\"${rgbToColorAttribute(rgb)}\">${element}</g>`,\n )\n }\n return acc\n },\n {\n bbox: new Box2(),\n elements: [],\n },\n )\n\n const viewBox = bbox.valid\n ? {\n x: bbox.min.x,\n y: -bbox.max.y,\n width: bbox.max.x - bbox.min.x,\n height: bbox.max.y - bbox.min.y,\n }\n : {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n }\n return `<?xml version=\"1.0\"?>\n<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\"\n preserveAspectRatio=\"xMinYMin meet\"\n viewBox=\"${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}\"\n width=\"100%\" height=\"100%\"\n>\n <g stroke=\"#000000\" stroke-width=\"0.1%\" fill=\"none\" transform=\"matrix(1,0,0,-1,0,0)\">\n ${elements.join('\\n')}\n </g>\n</svg>`\n}\n"],
5
- "mappings": "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",
6
- "names": ["entityToPolyline", "transformBoundingBoxAndElement", "rotate", "dimensionToSVG", "toPiecewiseBezier", "logger", "denormalise", "getRGBForEntity", "bbox", "rgbToColorAttribute"]
4
+ "sourcesContent": ["import { Box2 } from 'vecks'\n\nimport denormalise from './denormalise'\nimport dimensionToSVG, { getDimensionGeometryBBox } from './dimensionToSVG'\nimport entityToPolyline from './entityToPolyline'\nimport getRGBForEntity from './getRGBForEntity'\nimport escapeXmlText from './util/escapeXmlText'\nimport logger from './util/logger'\nimport rgbToColorAttribute from './util/rgbToColorAttribute'\nimport rotate from './util/rotate'\nimport toPiecewiseBezier, { multiplicity } from './util/toPiecewiseBezier'\nimport transformBoundingBoxAndElement from './util/transformBoundingBoxAndElement'\n\nimport type {\n ArcEntity,\n CircleEntity,\n DimensionEntity,\n EllipseEntity,\n Entity,\n LeaderEntity,\n MTextEntity,\n ParsedDXF,\n SplineEntity,\n TextEntity,\n ToleranceEntity,\n ToSVGOptions,\n} from './types'\nimport type { BoundsAndElement } from './types/svg'\n\nconst addFlipXIfApplicable = (\n entity: Entity,\n { bbox, element }: BoundsAndElement,\n): BoundsAndElement => {\n if (entity.extrusionZ === -1) {\n return {\n bbox: new Box2()\n .expandByPoint({ x: -bbox.min.x, y: bbox.min.y })\n .expandByPoint({ x: -bbox.max.x, y: bbox.max.y }),\n element: `<g transform=\"matrix(-1 0 0 1 0 0)\">\n ${element}\n </g>`,\n }\n } else {\n return { bbox, element }\n }\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n */\nconst polyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n // Empirically it appears that flipping horizontally does not apply to polyline\n return transformBoundingBoxAndElement(\n bbox,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n * lwpolyline is the same as polyline but addFlipXIfApplicable does apply\n */\nconst lwpolyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox0 = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n const element0 = `<path d=\"${d}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(\n bbox,\n element,\n entity.transforms ?? [],\n )\n}\n\nconst leader = (entity: LeaderEntity): BoundsAndElement | null => {\n if (!entity.vertices || entity.vertices.length < 2) return null\n\n const bbox0 = entity.vertices.reduce(\n (acc, p) => acc.expandByPoint({ x: p.x, y: p.y }),\n new Box2(),\n )\n const d = entity.vertices.reduce((acc, p, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += p.x + ',' + p.y\n return acc\n }, '')\n\n return transformBoundingBoxAndElement(\n bbox0,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n\n/**\n * Create a <circle /> element for the CIRCLE entity.\n */\nconst circle = (entity: CircleEntity): BoundsAndElement => {\n const bbox0 = new Box2()\n .expandByPoint({\n x: entity.x + entity.r,\n y: entity.y + entity.r,\n })\n .expandByPoint({\n x: entity.x - entity.r,\n y: entity.y - entity.r,\n })\n const element0 = `<circle cx=\"${entity.x}\" cy=\"${entity.y}\" r=\"${entity.r}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\ninterface EllipticArcParams {\n cx: number\n cy: number\n majorX: number\n majorY: number\n axisRatio: number\n startAngle: number\n endAngle: number\n flipX?: boolean\n}\n\n/**\n * Create a a <path d=\"A...\" /> or <ellipse /> element for the ARC or ELLIPSE\n * DXF entity (<ellipse /> if start and end point are the same).\n */\nconst ellipseOrArc = (params: EllipticArcParams): BoundsAndElement => {\n const { cx, cy, majorX, majorY, axisRatio, startAngle, endAngle } = params\n const rx = Math.hypot(majorX, majorY)\n const ry = axisRatio * rx\n const rotationAngle = -Math.atan2(-majorY, majorX)\n\n const bbox = bboxEllipseOrArc(params)\n\n if (\n Math.abs(startAngle - endAngle) < 1e-9 ||\n Math.abs(startAngle - endAngle + Math.PI * 2) < 1e-9\n ) {\n // Use a native <ellipse> when start and end angles are the same, and\n // arc paths with same start and end points don't render (at least on Safari)\n const element = `<g transform=\"rotate(${\n (rotationAngle / Math.PI) * 180\n } ${cx}, ${cy})\">\n <ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" />\n </g>`\n return { bbox, element }\n } else {\n const startOffset = rotate(\n {\n x: Math.cos(startAngle) * rx,\n y: Math.sin(startAngle) * ry,\n },\n rotationAngle,\n )\n const startPoint = {\n x: cx + startOffset.x,\n y: cy + startOffset.y,\n }\n const endOffset = rotate(\n {\n x: Math.cos(endAngle) * rx,\n y: Math.sin(endAngle) * ry,\n },\n rotationAngle,\n )\n const endPoint = {\n x: cx + endOffset.x,\n y: cy + endOffset.y,\n }\n const adjustedEndAngle =\n endAngle < startAngle ? endAngle + Math.PI * 2 : endAngle\n const largeArcFlag = adjustedEndAngle - startAngle < Math.PI ? 0 : 1\n const d = `M ${startPoint.x} ${startPoint.y} A ${rx} ${ry} ${\n (rotationAngle / Math.PI) * 180\n } ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`\n const element = `<path d=\"${d}\" />`\n return { bbox, element }\n }\n}\n\n/**\n * Compute the bounding box of an elliptical arc, given the DXF entity parameters\n */\n\nconst bboxEllipseOrArc = (params: EllipticArcParams): Box2 => {\n const { cx, cy, majorX, majorY, axisRatio } = params\n let { startAngle, endAngle } = params\n\n // The bounding box will be defined by the starting point of the ellipse, and ending point,\n // and any extrema on the ellipse that are between startAngle and endAngle.\n // The extrema are found by setting either the x or y component of the ellipse's\n // tangent vector to zero and solving for the angle.\n\n // Ensure start and end angles are > 0 and well-ordered\n while (startAngle < 0) startAngle += Math.PI * 2\n while (endAngle <= startAngle) endAngle += Math.PI * 2\n\n // When rotated, the extrema of the ellipse will be found at these angles\n const angles = []\n\n if (Math.abs(majorX) < 1e-12 || Math.abs(majorY) < 1e-12) {\n // Special case for majorX or majorY = 0\n for (let i = 0; i < 4; i++) {\n angles.push((i / 2) * Math.PI)\n }\n } else {\n // reference https://github.com/bjnortier/dxf/issues/47#issuecomment-545915042\n angles[0] = Math.atan((-majorY * axisRatio) / majorX) - Math.PI // Ensure angles < 0\n angles[1] = Math.atan((majorX * axisRatio) / majorY) - Math.PI\n angles[2] = angles[0] - Math.PI\n angles[3] = angles[1] - Math.PI\n }\n\n // Remove angles not falling between start and end\n for (let i = 4; i >= 0; i--) {\n while (angles[i] < startAngle) angles[i] += Math.PI * 2\n if (angles[i] > endAngle) {\n angles.splice(i, 1)\n }\n }\n\n // Also to consider are the starting and ending points:\n angles.push(startAngle, endAngle)\n\n // Compute points lying on the unit circle at these angles\n const pts = angles.map((a) => ({\n x: Math.cos(a),\n y: Math.sin(a),\n }))\n\n // Transformation matrix, formed by the major and minor axes\n const M = [\n [majorX, -majorY * axisRatio],\n [majorY, majorX * axisRatio],\n ]\n\n // Rotate, scale, and translate points\n const rotatedPts = pts.map((p) => ({\n x: p.x * M[0][0] + p.y * M[0][1] + cx,\n y: p.x * M[1][0] + p.y * M[1][1] + cy,\n }))\n\n // Compute extents of bounding box\n const bbox = rotatedPts.reduce((acc, p) => {\n acc.expandByPoint(p)\n return acc\n }, new Box2())\n\n return bbox\n}\n\n/**\n * An ELLIPSE is defined by the major axis, convert to X and Y radius with\n * a rotation angle\n */\nconst ellipse = (entity: EllipseEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.majorX,\n majorY: entity.majorY,\n axisRatio: entity.axisRatio,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * An ARC is an ellipse with equal radii\n */\nconst arc = (entity: ArcEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.r,\n majorY: 0,\n axisRatio: 1,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n flipX: entity.extrusionZ === -1,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for TEXT entity\n */\nconst text = (entity: TextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.textHeight ?? 1\n const rotation = entity.rotation ?? 0\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for MTEXT entity\n */\nconst mtext = (entity: MTextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.nominalTextHeight ?? entity.textHeight ?? 1\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = (entity.refRectangleWidth ?? content.length * height * 0.6)\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n // Calculate rotation from x-axis direction\n const rotation = entity.xAxisX !== undefined && entity.xAxisY !== undefined\n ? Math.atan2(entity.xAxisY, entity.xAxisX)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Minimal <text /> fallback for TOLERANCE entities.\n * DXF uses special control codes; we preserve the raw string.\n */\nconst tolerance = (entity: ToleranceEntity): BoundsAndElement => {\n const x = entity.insertionPoint?.x ?? 0\n const y = entity.insertionPoint?.y ?? 0\n const height = 1\n const content = entity.text ?? ''\n\n const rotation = entity.xAxisDirection\n ? Math.atan2(entity.xAxisDirection.y, entity.xAxisDirection.x)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create dimension visualization with DIMSTYLE support\n */\nconst dimension = (\n entity: DimensionEntity,\n dimStyle?: any,\n options?: ToSVGOptions,\n viewport?: { width: number; height: number },\n): BoundsAndElement => {\n const result = dimensionToSVG(entity, dimStyle, options, viewport)\n return transformBoundingBoxAndElement(\n result.bbox,\n result.element,\n entity.transforms ?? [],\n )\n}\n\nexport const piecewiseToPaths = (\n k: number,\n knots: number[],\n controlPoints: Array<{ x: number; y: number }>,\n): string[] => {\n const paths: string[] = []\n let controlPointIndex = 0\n let knotIndex = k\n while (knotIndex < knots.length - k + 1) {\n const m = multiplicity(knots, knotIndex)\n const cp = controlPoints.slice(controlPointIndex, controlPointIndex + k)\n if (k === 4) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} C ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y} ${cp[3].x} ${cp[3].y}\" />`,\n )\n } else if (k === 3) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} Q ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y}\" />`,\n )\n }\n controlPointIndex += m\n knotIndex += m\n }\n return paths\n}\n\nconst bezier = (entity: SplineEntity): BoundsAndElement => {\n let bbox = new Box2()\n for (const p of entity.controlPoints) {\n bbox = bbox.expandByPoint(p)\n }\n const k = entity.degree + 1\n const piecewise = toPiecewiseBezier(k, entity.controlPoints, entity.knots)\n const paths = piecewiseToPaths(k, piecewise.knots, piecewise.controlPoints)\n const element = `<g>${paths.join('')}</g>`\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Switch the appropriate function on entity type. CIRCLE, ARC and ELLIPSE\n * produce native SVG elements, the rest produce interpolated polylines.\n */\nconst entityToBoundsAndElement = (\n entity: Entity,\n dimStyles?: { [name: string]: any },\n options?: ToSVGOptions,\n viewport?: { width: number; height: number },\n): BoundsAndElement | null => {\n switch (entity.type) {\n case 'CIRCLE':\n return circle(entity as CircleEntity)\n case 'ELLIPSE':\n return ellipse(entity as EllipseEntity)\n case 'ARC':\n return arc(entity as ArcEntity)\n case 'TEXT':\n return text(entity as TextEntity)\n case 'MTEXT':\n return mtext(entity as MTextEntity)\n case 'DIMENSION': {\n const dimEntity = entity as DimensionEntity\n const styleName = typeof dimEntity.styleName === 'string'\n ? dimEntity.styleName\n : undefined\n const dimStyle = styleName && dimStyles\n ? dimStyles[styleName]\n : undefined\n return dimension(dimEntity, dimStyle, options, viewport)\n }\n case 'SPLINE': {\n const splineEntity = entity as SplineEntity\n const hasWeights = splineEntity.weights?.some((w: number) => w !== 1)\n if ((splineEntity.degree === 2 || splineEntity.degree === 3) && !hasWeights) {\n try {\n return bezier(splineEntity)\n } catch (err) {\n const error = err as Error\n logger.warn('bezier conversion failed, using polyline:', error.message)\n return polyline(entity)\n }\n } else {\n return polyline(entity)\n }\n }\n case 'LINE':\n case 'POLYLINE': {\n return polyline(entity)\n }\n case 'LWPOLYLINE': {\n return lwpolyline(entity)\n }\n case 'LEADER': {\n return leader(entity as LeaderEntity)\n }\n case 'TOLERANCE': {\n return tolerance(entity as ToleranceEntity)\n }\n default:\n logger.warn('entity type not supported in SVG rendering:', entity.type)\n return null\n }\n}\n\nexport default function toSVG(parsed: ParsedDXF, options: ToSVGOptions = {}): string {\n const entities = denormalise(parsed)\n const dimStyles = parsed.tables.dimStyles\n\n const geometryBBox = entities.reduce((acc: Box2, entity: Entity): Box2 => {\n if (entity.type === 'DIMENSION') {\n const bbox = getDimensionGeometryBBox(entity as DimensionEntity)\n if (bbox.valid) {\n acc.expandByPoint(bbox.min)\n acc.expandByPoint(bbox.max)\n }\n return acc\n }\n\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options)\n if (boundsAndElement?.bbox.valid) {\n acc.expandByPoint(boundsAndElement.bbox.min)\n acc.expandByPoint(boundsAndElement.bbox.max)\n }\n return acc\n }, new Box2())\n\n const viewport = geometryBBox.valid\n ? {\n width: geometryBBox.max.x - geometryBBox.min.x,\n height: geometryBBox.max.y - geometryBBox.min.y,\n }\n : {\n width: 0,\n height: 0,\n }\n\n const { bbox, elements } = entities.reduce(\n (\n acc: { bbox: Box2; elements: string[] },\n entity: Entity,\n ): { bbox: Box2; elements: string[] } => {\n const rgb = getRGBForEntity(parsed.tables.layers, entity)\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options, viewport)\n // Ignore entities that don't produce SVG elements or have unsupported types\n if (boundsAndElement) {\n const { bbox, element } = boundsAndElement\n // Ignore invalid bounding boxes\n if (bbox.valid) {\n acc.bbox.expandByPoint(bbox.min)\n acc.bbox.expandByPoint(bbox.max)\n }\n acc.elements.push(\n `<g stroke=\"${rgbToColorAttribute(rgb)}\">${element}</g>`,\n )\n }\n return acc\n },\n {\n bbox: new Box2(),\n elements: [],\n },\n )\n\n const viewBox = bbox.valid\n ? {\n x: bbox.min.x,\n y: -bbox.max.y,\n width: bbox.max.x - bbox.min.x,\n height: bbox.max.y - bbox.min.y,\n }\n : {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n }\n return `<?xml version=\"1.0\"?>\n<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\"\n preserveAspectRatio=\"xMinYMin meet\"\n viewBox=\"${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}\"\n width=\"100%\" height=\"100%\"\n>\n <g stroke=\"#000000\" stroke-width=\"0.1%\" fill=\"none\" transform=\"matrix(1,0,0,-1,0,0)\">\n ${elements.join('\\n')}\n </g>\n</svg>`\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["entityToPolyline", "transformBoundingBoxAndElement", "rotate", "escapeXmlText", "dimensionToSVG", "toPiecewiseBezier", "logger", "denormalise", "bbox", "getRGBForEntity", "rgbToColorAttribute"]
7
7
  }
package/lib/toSVG.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Box2 } from "vecks";
2
2
  import denormalise from "./denormalise";
3
- import dimensionToSVG from "./dimensionToSVG";
3
+ import dimensionToSVG, { getDimensionGeometryBBox } from "./dimensionToSVG";
4
4
  import entityToPolyline from "./entityToPolyline";
5
5
  import getRGBForEntity from "./getRGBForEntity";
6
+ import escapeXmlText from "./util/escapeXmlText";
6
7
  import logger from "./util/logger";
7
8
  import rgbToColorAttribute from "./util/rgbToColorAttribute";
8
9
  import rotate from "./util/rotate";
@@ -59,6 +60,23 @@ const lwpolyline = (entity) => {
59
60
  entity.transforms ?? []
60
61
  );
61
62
  };
63
+ const leader = (entity) => {
64
+ if (!entity.vertices || entity.vertices.length < 2) return null;
65
+ const bbox0 = entity.vertices.reduce(
66
+ (acc, p) => acc.expandByPoint({ x: p.x, y: p.y }),
67
+ new Box2()
68
+ );
69
+ const d = entity.vertices.reduce((acc, p, i) => {
70
+ acc += i === 0 ? "M" : "L";
71
+ acc += p.x + "," + p.y;
72
+ return acc;
73
+ }, "");
74
+ return transformBoundingBoxAndElement(
75
+ bbox0,
76
+ `<path d="${d}" />`,
77
+ entity.transforms ?? []
78
+ );
79
+ };
62
80
  const circle = (entity) => {
63
81
  const bbox0 = new Box2().expandByPoint({
64
82
  x: entity.x + entity.r,
@@ -198,7 +216,7 @@ const text = (entity) => {
198
216
  const textWidth = content.length * height * 0.6;
199
217
  const bbox0 = new Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
200
218
  const rotationDegrees = rotation * 180 / Math.PI;
201
- const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${content}</text>`;
219
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${escapeXmlText(content)}</text>`;
202
220
  const { bbox, element } = addFlipXIfApplicable(entity, {
203
221
  bbox: bbox0,
204
222
  element: element0
@@ -214,15 +232,31 @@ const mtext = (entity) => {
214
232
  const bbox0 = new Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
215
233
  const rotation = entity.xAxisX !== void 0 && entity.xAxisY !== void 0 ? Math.atan2(entity.xAxisY, entity.xAxisX) : 0;
216
234
  const rotationDegrees = rotation * 180 / Math.PI;
217
- const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${content}</text>`;
235
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${escapeXmlText(content)}</text>`;
218
236
  const { bbox, element } = addFlipXIfApplicable(entity, {
219
237
  bbox: bbox0,
220
238
  element: element0
221
239
  });
222
240
  return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? []);
223
241
  };
224
- const dimension = (entity, dimStyle) => {
225
- const result = dimensionToSVG(entity, dimStyle);
242
+ const tolerance = (entity) => {
243
+ const x = entity.insertionPoint?.x ?? 0;
244
+ const y = entity.insertionPoint?.y ?? 0;
245
+ const height = 1;
246
+ const content = entity.text ?? "";
247
+ const rotation = entity.xAxisDirection ? Math.atan2(entity.xAxisDirection.y, entity.xAxisDirection.x) : 0;
248
+ const rotationDegrees = rotation * 180 / Math.PI;
249
+ const textWidth = content.length * height * 0.6;
250
+ const bbox0 = new Box2().expandByPoint({ x, y }).expandByPoint({ x: x + textWidth, y: y + height });
251
+ const element0 = `<text x="${x}" y="${y}" font-size="${height}" transform="rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})">${escapeXmlText(content)}</text>`;
252
+ const { bbox, element } = addFlipXIfApplicable(entity, {
253
+ bbox: bbox0,
254
+ element: element0
255
+ });
256
+ return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? []);
257
+ };
258
+ const dimension = (entity, dimStyle, options, viewport) => {
259
+ const result = dimensionToSVG(entity, dimStyle, options, viewport);
226
260
  return transformBoundingBoxAndElement(
227
261
  result.bbox,
228
262
  result.element,
@@ -261,7 +295,7 @@ const bezier = (entity) => {
261
295
  const element = `<g>${paths.join("")}</g>`;
262
296
  return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? []);
263
297
  };
264
- const entityToBoundsAndElement = (entity, dimStyles) => {
298
+ const entityToBoundsAndElement = (entity, dimStyles, options, viewport) => {
265
299
  switch (entity.type) {
266
300
  case "CIRCLE":
267
301
  return circle(entity);
@@ -277,7 +311,7 @@ const entityToBoundsAndElement = (entity, dimStyles) => {
277
311
  const dimEntity = entity;
278
312
  const styleName = typeof dimEntity.styleName === "string" ? dimEntity.styleName : void 0;
279
313
  const dimStyle = styleName && dimStyles ? dimStyles[styleName] : void 0;
280
- return dimension(dimEntity, dimStyle);
314
+ return dimension(dimEntity, dimStyle, options, viewport);
281
315
  }
282
316
  case "SPLINE": {
283
317
  const splineEntity = entity;
@@ -301,18 +335,47 @@ const entityToBoundsAndElement = (entity, dimStyles) => {
301
335
  case "LWPOLYLINE": {
302
336
  return lwpolyline(entity);
303
337
  }
338
+ case "LEADER": {
339
+ return leader(entity);
340
+ }
341
+ case "TOLERANCE": {
342
+ return tolerance(entity);
343
+ }
304
344
  default:
305
345
  logger.warn("entity type not supported in SVG rendering:", entity.type);
306
346
  return null;
307
347
  }
308
348
  };
309
- function toSVG(parsed) {
349
+ function toSVG(parsed, options = {}) {
310
350
  const entities = denormalise(parsed);
311
351
  const dimStyles = parsed.tables.dimStyles;
352
+ const geometryBBox = entities.reduce((acc, entity) => {
353
+ if (entity.type === "DIMENSION") {
354
+ const bbox2 = getDimensionGeometryBBox(entity);
355
+ if (bbox2.valid) {
356
+ acc.expandByPoint(bbox2.min);
357
+ acc.expandByPoint(bbox2.max);
358
+ }
359
+ return acc;
360
+ }
361
+ const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options);
362
+ if (boundsAndElement?.bbox.valid) {
363
+ acc.expandByPoint(boundsAndElement.bbox.min);
364
+ acc.expandByPoint(boundsAndElement.bbox.max);
365
+ }
366
+ return acc;
367
+ }, new Box2());
368
+ const viewport = geometryBBox.valid ? {
369
+ width: geometryBBox.max.x - geometryBBox.min.x,
370
+ height: geometryBBox.max.y - geometryBBox.min.y
371
+ } : {
372
+ width: 0,
373
+ height: 0
374
+ };
312
375
  const { bbox, elements } = entities.reduce(
313
376
  (acc, entity) => {
314
377
  const rgb = getRGBForEntity(parsed.tables.layers, entity);
315
- const boundsAndElement = entityToBoundsAndElement(entity, dimStyles);
378
+ const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options, viewport);
316
379
  if (boundsAndElement) {
317
380
  const { bbox: bbox2, element } = boundsAndElement;
318
381
  if (bbox2.valid) {
package/lib/toSVG.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/toSVG.ts"],
4
- "sourcesContent": ["import { Box2 } from 'vecks'\n\nimport denormalise from './denormalise'\nimport dimensionToSVG from './dimensionToSVG'\nimport entityToPolyline from './entityToPolyline'\nimport getRGBForEntity from './getRGBForEntity'\nimport logger from './util/logger'\nimport rgbToColorAttribute from './util/rgbToColorAttribute'\nimport rotate from './util/rotate'\nimport toPiecewiseBezier, { multiplicity } from './util/toPiecewiseBezier'\nimport transformBoundingBoxAndElement from './util/transformBoundingBoxAndElement'\n\nimport type {\n ArcEntity,\n CircleEntity,\n DimensionEntity,\n EllipseEntity,\n Entity,\n MTextEntity,\n ParsedDXF,\n SplineEntity,\n TextEntity,\n} from './types'\nimport type { BoundsAndElement } from './types/svg'\n\nconst addFlipXIfApplicable = (\n entity: Entity,\n { bbox, element }: BoundsAndElement,\n): BoundsAndElement => {\n if (entity.extrusionZ === -1) {\n return {\n bbox: new Box2()\n .expandByPoint({ x: -bbox.min.x, y: bbox.min.y })\n .expandByPoint({ x: -bbox.max.x, y: bbox.max.y }),\n element: `<g transform=\"matrix(-1 0 0 1 0 0)\">\n ${element}\n </g>`,\n }\n } else {\n return { bbox, element }\n }\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n */\nconst polyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n // Empirically it appears that flipping horizontally does not apply to polyline\n return transformBoundingBoxAndElement(\n bbox,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n * lwpolyline is the same as polyline but addFlipXIfApplicable does apply\n */\nconst lwpolyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox0 = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n const element0 = `<path d=\"${d}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(\n bbox,\n element,\n entity.transforms ?? [],\n )\n}\n\n\n/**\n * Create a <circle /> element for the CIRCLE entity.\n */\nconst circle = (entity: CircleEntity): BoundsAndElement => {\n const bbox0 = new Box2()\n .expandByPoint({\n x: entity.x + entity.r,\n y: entity.y + entity.r,\n })\n .expandByPoint({\n x: entity.x - entity.r,\n y: entity.y - entity.r,\n })\n const element0 = `<circle cx=\"${entity.x}\" cy=\"${entity.y}\" r=\"${entity.r}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\ninterface EllipticArcParams {\n cx: number\n cy: number\n majorX: number\n majorY: number\n axisRatio: number\n startAngle: number\n endAngle: number\n flipX?: boolean\n}\n\n/**\n * Create a a <path d=\"A...\" /> or <ellipse /> element for the ARC or ELLIPSE\n * DXF entity (<ellipse /> if start and end point are the same).\n */\nconst ellipseOrArc = (params: EllipticArcParams): BoundsAndElement => {\n const { cx, cy, majorX, majorY, axisRatio, startAngle, endAngle } = params\n const rx = Math.hypot(majorX, majorY)\n const ry = axisRatio * rx\n const rotationAngle = -Math.atan2(-majorY, majorX)\n\n const bbox = bboxEllipseOrArc(params)\n\n if (\n Math.abs(startAngle - endAngle) < 1e-9 ||\n Math.abs(startAngle - endAngle + Math.PI * 2) < 1e-9\n ) {\n // Use a native <ellipse> when start and end angles are the same, and\n // arc paths with same start and end points don't render (at least on Safari)\n const element = `<g transform=\"rotate(${\n (rotationAngle / Math.PI) * 180\n } ${cx}, ${cy})\">\n <ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" />\n </g>`\n return { bbox, element }\n } else {\n const startOffset = rotate(\n {\n x: Math.cos(startAngle) * rx,\n y: Math.sin(startAngle) * ry,\n },\n rotationAngle,\n )\n const startPoint = {\n x: cx + startOffset.x,\n y: cy + startOffset.y,\n }\n const endOffset = rotate(\n {\n x: Math.cos(endAngle) * rx,\n y: Math.sin(endAngle) * ry,\n },\n rotationAngle,\n )\n const endPoint = {\n x: cx + endOffset.x,\n y: cy + endOffset.y,\n }\n const adjustedEndAngle =\n endAngle < startAngle ? endAngle + Math.PI * 2 : endAngle\n const largeArcFlag = adjustedEndAngle - startAngle < Math.PI ? 0 : 1\n const d = `M ${startPoint.x} ${startPoint.y} A ${rx} ${ry} ${\n (rotationAngle / Math.PI) * 180\n } ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`\n const element = `<path d=\"${d}\" />`\n return { bbox, element }\n }\n}\n\n/**\n * Compute the bounding box of an elliptical arc, given the DXF entity parameters\n */\n\nconst bboxEllipseOrArc = (params: EllipticArcParams): Box2 => {\n const { cx, cy, majorX, majorY, axisRatio } = params\n let { startAngle, endAngle } = params\n\n // The bounding box will be defined by the starting point of the ellipse, and ending point,\n // and any extrema on the ellipse that are between startAngle and endAngle.\n // The extrema are found by setting either the x or y component of the ellipse's\n // tangent vector to zero and solving for the angle.\n\n // Ensure start and end angles are > 0 and well-ordered\n while (startAngle < 0) startAngle += Math.PI * 2\n while (endAngle <= startAngle) endAngle += Math.PI * 2\n\n // When rotated, the extrema of the ellipse will be found at these angles\n const angles = []\n\n if (Math.abs(majorX) < 1e-12 || Math.abs(majorY) < 1e-12) {\n // Special case for majorX or majorY = 0\n for (let i = 0; i < 4; i++) {\n angles.push((i / 2) * Math.PI)\n }\n } else {\n // reference https://github.com/bjnortier/dxf/issues/47#issuecomment-545915042\n angles[0] = Math.atan((-majorY * axisRatio) / majorX) - Math.PI // Ensure angles < 0\n angles[1] = Math.atan((majorX * axisRatio) / majorY) - Math.PI\n angles[2] = angles[0] - Math.PI\n angles[3] = angles[1] - Math.PI\n }\n\n // Remove angles not falling between start and end\n for (let i = 4; i >= 0; i--) {\n while (angles[i] < startAngle) angles[i] += Math.PI * 2\n if (angles[i] > endAngle) {\n angles.splice(i, 1)\n }\n }\n\n // Also to consider are the starting and ending points:\n angles.push(startAngle, endAngle)\n\n // Compute points lying on the unit circle at these angles\n const pts = angles.map((a) => ({\n x: Math.cos(a),\n y: Math.sin(a),\n }))\n\n // Transformation matrix, formed by the major and minor axes\n const M = [\n [majorX, -majorY * axisRatio],\n [majorY, majorX * axisRatio],\n ]\n\n // Rotate, scale, and translate points\n const rotatedPts = pts.map((p) => ({\n x: p.x * M[0][0] + p.y * M[0][1] + cx,\n y: p.x * M[1][0] + p.y * M[1][1] + cy,\n }))\n\n // Compute extents of bounding box\n const bbox = rotatedPts.reduce((acc, p) => {\n acc.expandByPoint(p)\n return acc\n }, new Box2())\n\n return bbox\n}\n\n/**\n * An ELLIPSE is defined by the major axis, convert to X and Y radius with\n * a rotation angle\n */\nconst ellipse = (entity: EllipseEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.majorX,\n majorY: entity.majorY,\n axisRatio: entity.axisRatio,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * An ARC is an ellipse with equal radii\n */\nconst arc = (entity: ArcEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.r,\n majorY: 0,\n axisRatio: 1,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n flipX: entity.extrusionZ === -1,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for TEXT entity\n */\nconst text = (entity: TextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.textHeight ?? 1\n const rotation = entity.rotation ?? 0\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${content}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for MTEXT entity\n */\nconst mtext = (entity: MTextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.nominalTextHeight ?? entity.textHeight ?? 1\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = (entity.refRectangleWidth ?? content.length * height * 0.6)\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n // Calculate rotation from x-axis direction\n const rotation = entity.xAxisX !== undefined && entity.xAxisY !== undefined\n ? Math.atan2(entity.xAxisY, entity.xAxisX)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${content}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create dimension visualization with DIMSTYLE support\n */\nconst dimension = (\n entity: DimensionEntity,\n dimStyle?: any,\n): BoundsAndElement => {\n const result = dimensionToSVG(entity, dimStyle)\n return transformBoundingBoxAndElement(\n result.bbox,\n result.element,\n entity.transforms ?? [],\n )\n}\n\nexport const piecewiseToPaths = (\n k: number,\n knots: number[],\n controlPoints: Array<{ x: number; y: number }>,\n): string[] => {\n const paths: string[] = []\n let controlPointIndex = 0\n let knotIndex = k\n while (knotIndex < knots.length - k + 1) {\n const m = multiplicity(knots, knotIndex)\n const cp = controlPoints.slice(controlPointIndex, controlPointIndex + k)\n if (k === 4) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} C ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y} ${cp[3].x} ${cp[3].y}\" />`,\n )\n } else if (k === 3) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} Q ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y}\" />`,\n )\n }\n controlPointIndex += m\n knotIndex += m\n }\n return paths\n}\n\nconst bezier = (entity: SplineEntity): BoundsAndElement => {\n let bbox = new Box2()\n for (const p of entity.controlPoints) {\n bbox = bbox.expandByPoint(p)\n }\n const k = entity.degree + 1\n const piecewise = toPiecewiseBezier(k, entity.controlPoints, entity.knots)\n const paths = piecewiseToPaths(k, piecewise.knots, piecewise.controlPoints)\n const element = `<g>${paths.join('')}</g>`\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Switch the appropriate function on entity type. CIRCLE, ARC and ELLIPSE\n * produce native SVG elements, the rest produce interpolated polylines.\n */\nconst entityToBoundsAndElement = (\n entity: Entity,\n dimStyles?: { [name: string]: any },\n): BoundsAndElement | null => {\n switch (entity.type) {\n case 'CIRCLE':\n return circle(entity as CircleEntity)\n case 'ELLIPSE':\n return ellipse(entity as EllipseEntity)\n case 'ARC':\n return arc(entity as ArcEntity)\n case 'TEXT':\n return text(entity as TextEntity)\n case 'MTEXT':\n return mtext(entity as MTextEntity)\n case 'DIMENSION': {\n const dimEntity = entity as DimensionEntity\n const styleName = typeof dimEntity.styleName === 'string'\n ? dimEntity.styleName\n : undefined\n const dimStyle = styleName && dimStyles\n ? dimStyles[styleName]\n : undefined\n return dimension(dimEntity, dimStyle)\n }\n case 'SPLINE': {\n const splineEntity = entity as SplineEntity\n const hasWeights = splineEntity.weights?.some((w: number) => w !== 1)\n if ((splineEntity.degree === 2 || splineEntity.degree === 3) && !hasWeights) {\n try {\n return bezier(splineEntity)\n } catch (err) {\n const error = err as Error\n logger.warn('bezier conversion failed, using polyline:', error.message)\n return polyline(entity)\n }\n } else {\n return polyline(entity)\n }\n }\n case 'LINE':\n case 'POLYLINE': {\n return polyline(entity)\n }\n case 'LWPOLYLINE': {\n return lwpolyline(entity)\n }\n default:\n logger.warn('entity type not supported in SVG rendering:', entity.type)\n return null\n }\n}\n\nexport default function toSVG(parsed: ParsedDXF): string {\n const entities = denormalise(parsed)\n const dimStyles = parsed.tables.dimStyles\n const { bbox, elements } = entities.reduce(\n (\n acc: { bbox: Box2; elements: string[] },\n entity: Entity,\n ): { bbox: Box2; elements: string[] } => {\n const rgb = getRGBForEntity(parsed.tables.layers, entity)\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles)\n // Ignore entities that don't produce SVG elements or have unsupported types\n if (boundsAndElement) {\n const { bbox, element } = boundsAndElement\n // Ignore invalid bounding boxes\n if (bbox.valid) {\n acc.bbox.expandByPoint(bbox.min)\n acc.bbox.expandByPoint(bbox.max)\n }\n acc.elements.push(\n `<g stroke=\"${rgbToColorAttribute(rgb)}\">${element}</g>`,\n )\n }\n return acc\n },\n {\n bbox: new Box2(),\n elements: [],\n },\n )\n\n const viewBox = bbox.valid\n ? {\n x: bbox.min.x,\n y: -bbox.max.y,\n width: bbox.max.x - bbox.min.x,\n height: bbox.max.y - bbox.min.y,\n }\n : {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n }\n return `<?xml version=\"1.0\"?>\n<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\"\n preserveAspectRatio=\"xMinYMin meet\"\n viewBox=\"${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}\"\n width=\"100%\" height=\"100%\"\n>\n <g stroke=\"#000000\" stroke-width=\"0.1%\" fill=\"none\" transform=\"matrix(1,0,0,-1,0,0)\">\n ${elements.join('\\n')}\n </g>\n</svg>`\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box2 } from 'vecks'\n\nimport denormalise from './denormalise'\nimport dimensionToSVG, { getDimensionGeometryBBox } from './dimensionToSVG'\nimport entityToPolyline from './entityToPolyline'\nimport getRGBForEntity from './getRGBForEntity'\nimport escapeXmlText from './util/escapeXmlText'\nimport logger from './util/logger'\nimport rgbToColorAttribute from './util/rgbToColorAttribute'\nimport rotate from './util/rotate'\nimport toPiecewiseBezier, { multiplicity } from './util/toPiecewiseBezier'\nimport transformBoundingBoxAndElement from './util/transformBoundingBoxAndElement'\n\nimport type {\n ArcEntity,\n CircleEntity,\n DimensionEntity,\n EllipseEntity,\n Entity,\n LeaderEntity,\n MTextEntity,\n ParsedDXF,\n SplineEntity,\n TextEntity,\n ToleranceEntity,\n ToSVGOptions,\n} from './types'\nimport type { BoundsAndElement } from './types/svg'\n\nconst addFlipXIfApplicable = (\n entity: Entity,\n { bbox, element }: BoundsAndElement,\n): BoundsAndElement => {\n if (entity.extrusionZ === -1) {\n return {\n bbox: new Box2()\n .expandByPoint({ x: -bbox.min.x, y: bbox.min.y })\n .expandByPoint({ x: -bbox.max.x, y: bbox.max.y }),\n element: `<g transform=\"matrix(-1 0 0 1 0 0)\">\n ${element}\n </g>`,\n }\n } else {\n return { bbox, element }\n }\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n */\nconst polyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n // Empirically it appears that flipping horizontally does not apply to polyline\n return transformBoundingBoxAndElement(\n bbox,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n/**\n * Create a <path /> element. Interpolates curved entities.\n * lwpolyline is the same as polyline but addFlipXIfApplicable does apply\n */\nconst lwpolyline = (entity: Entity): BoundsAndElement => {\n const vertices = entityToPolyline(entity as any)\n const bbox0 = vertices.reduce(\n (acc, [x, y]) => acc.expandByPoint({ x, y }),\n new Box2(),\n )\n const d = vertices.reduce((acc, point, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += point[0] + ',' + point[1]\n return acc\n }, '')\n const element0 = `<path d=\"${d}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(\n bbox,\n element,\n entity.transforms ?? [],\n )\n}\n\nconst leader = (entity: LeaderEntity): BoundsAndElement | null => {\n if (!entity.vertices || entity.vertices.length < 2) return null\n\n const bbox0 = entity.vertices.reduce(\n (acc, p) => acc.expandByPoint({ x: p.x, y: p.y }),\n new Box2(),\n )\n const d = entity.vertices.reduce((acc, p, i) => {\n acc += i === 0 ? 'M' : 'L'\n acc += p.x + ',' + p.y\n return acc\n }, '')\n\n return transformBoundingBoxAndElement(\n bbox0,\n `<path d=\"${d}\" />`,\n entity.transforms ?? [],\n )\n}\n\n\n/**\n * Create a <circle /> element for the CIRCLE entity.\n */\nconst circle = (entity: CircleEntity): BoundsAndElement => {\n const bbox0 = new Box2()\n .expandByPoint({\n x: entity.x + entity.r,\n y: entity.y + entity.r,\n })\n .expandByPoint({\n x: entity.x - entity.r,\n y: entity.y - entity.r,\n })\n const element0 = `<circle cx=\"${entity.x}\" cy=\"${entity.y}\" r=\"${entity.r}\" />`\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\ninterface EllipticArcParams {\n cx: number\n cy: number\n majorX: number\n majorY: number\n axisRatio: number\n startAngle: number\n endAngle: number\n flipX?: boolean\n}\n\n/**\n * Create a a <path d=\"A...\" /> or <ellipse /> element for the ARC or ELLIPSE\n * DXF entity (<ellipse /> if start and end point are the same).\n */\nconst ellipseOrArc = (params: EllipticArcParams): BoundsAndElement => {\n const { cx, cy, majorX, majorY, axisRatio, startAngle, endAngle } = params\n const rx = Math.hypot(majorX, majorY)\n const ry = axisRatio * rx\n const rotationAngle = -Math.atan2(-majorY, majorX)\n\n const bbox = bboxEllipseOrArc(params)\n\n if (\n Math.abs(startAngle - endAngle) < 1e-9 ||\n Math.abs(startAngle - endAngle + Math.PI * 2) < 1e-9\n ) {\n // Use a native <ellipse> when start and end angles are the same, and\n // arc paths with same start and end points don't render (at least on Safari)\n const element = `<g transform=\"rotate(${\n (rotationAngle / Math.PI) * 180\n } ${cx}, ${cy})\">\n <ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" />\n </g>`\n return { bbox, element }\n } else {\n const startOffset = rotate(\n {\n x: Math.cos(startAngle) * rx,\n y: Math.sin(startAngle) * ry,\n },\n rotationAngle,\n )\n const startPoint = {\n x: cx + startOffset.x,\n y: cy + startOffset.y,\n }\n const endOffset = rotate(\n {\n x: Math.cos(endAngle) * rx,\n y: Math.sin(endAngle) * ry,\n },\n rotationAngle,\n )\n const endPoint = {\n x: cx + endOffset.x,\n y: cy + endOffset.y,\n }\n const adjustedEndAngle =\n endAngle < startAngle ? endAngle + Math.PI * 2 : endAngle\n const largeArcFlag = adjustedEndAngle - startAngle < Math.PI ? 0 : 1\n const d = `M ${startPoint.x} ${startPoint.y} A ${rx} ${ry} ${\n (rotationAngle / Math.PI) * 180\n } ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`\n const element = `<path d=\"${d}\" />`\n return { bbox, element }\n }\n}\n\n/**\n * Compute the bounding box of an elliptical arc, given the DXF entity parameters\n */\n\nconst bboxEllipseOrArc = (params: EllipticArcParams): Box2 => {\n const { cx, cy, majorX, majorY, axisRatio } = params\n let { startAngle, endAngle } = params\n\n // The bounding box will be defined by the starting point of the ellipse, and ending point,\n // and any extrema on the ellipse that are between startAngle and endAngle.\n // The extrema are found by setting either the x or y component of the ellipse's\n // tangent vector to zero and solving for the angle.\n\n // Ensure start and end angles are > 0 and well-ordered\n while (startAngle < 0) startAngle += Math.PI * 2\n while (endAngle <= startAngle) endAngle += Math.PI * 2\n\n // When rotated, the extrema of the ellipse will be found at these angles\n const angles = []\n\n if (Math.abs(majorX) < 1e-12 || Math.abs(majorY) < 1e-12) {\n // Special case for majorX or majorY = 0\n for (let i = 0; i < 4; i++) {\n angles.push((i / 2) * Math.PI)\n }\n } else {\n // reference https://github.com/bjnortier/dxf/issues/47#issuecomment-545915042\n angles[0] = Math.atan((-majorY * axisRatio) / majorX) - Math.PI // Ensure angles < 0\n angles[1] = Math.atan((majorX * axisRatio) / majorY) - Math.PI\n angles[2] = angles[0] - Math.PI\n angles[3] = angles[1] - Math.PI\n }\n\n // Remove angles not falling between start and end\n for (let i = 4; i >= 0; i--) {\n while (angles[i] < startAngle) angles[i] += Math.PI * 2\n if (angles[i] > endAngle) {\n angles.splice(i, 1)\n }\n }\n\n // Also to consider are the starting and ending points:\n angles.push(startAngle, endAngle)\n\n // Compute points lying on the unit circle at these angles\n const pts = angles.map((a) => ({\n x: Math.cos(a),\n y: Math.sin(a),\n }))\n\n // Transformation matrix, formed by the major and minor axes\n const M = [\n [majorX, -majorY * axisRatio],\n [majorY, majorX * axisRatio],\n ]\n\n // Rotate, scale, and translate points\n const rotatedPts = pts.map((p) => ({\n x: p.x * M[0][0] + p.y * M[0][1] + cx,\n y: p.x * M[1][0] + p.y * M[1][1] + cy,\n }))\n\n // Compute extents of bounding box\n const bbox = rotatedPts.reduce((acc, p) => {\n acc.expandByPoint(p)\n return acc\n }, new Box2())\n\n return bbox\n}\n\n/**\n * An ELLIPSE is defined by the major axis, convert to X and Y radius with\n * a rotation angle\n */\nconst ellipse = (entity: EllipseEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.majorX,\n majorY: entity.majorY,\n axisRatio: entity.axisRatio,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * An ARC is an ellipse with equal radii\n */\nconst arc = (entity: ArcEntity): BoundsAndElement => {\n const { bbox: bbox0, element: element0 } = ellipseOrArc({\n cx: entity.x,\n cy: entity.y,\n majorX: entity.r,\n majorY: 0,\n axisRatio: 1,\n startAngle: entity.startAngle,\n endAngle: entity.endAngle,\n flipX: entity.extrusionZ === -1,\n })\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for TEXT entity\n */\nconst text = (entity: TextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.textHeight ?? 1\n const rotation = entity.rotation ?? 0\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create a <text /> element for MTEXT entity\n */\nconst mtext = (entity: MTextEntity): BoundsAndElement => {\n const x = entity.x ?? 0\n const y = entity.y ?? 0\n const height = entity.nominalTextHeight ?? entity.textHeight ?? 1\n const content = entity.string ?? ''\n\n // Estimate text bounding box (approximate)\n const textWidth = (entity.refRectangleWidth ?? content.length * height * 0.6)\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n // Calculate rotation from x-axis direction\n const rotation = entity.xAxisX !== undefined && entity.xAxisY !== undefined\n ? Math.atan2(entity.xAxisY, entity.xAxisX)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Minimal <text /> fallback for TOLERANCE entities.\n * DXF uses special control codes; we preserve the raw string.\n */\nconst tolerance = (entity: ToleranceEntity): BoundsAndElement => {\n const x = entity.insertionPoint?.x ?? 0\n const y = entity.insertionPoint?.y ?? 0\n const height = 1\n const content = entity.text ?? ''\n\n const rotation = entity.xAxisDirection\n ? Math.atan2(entity.xAxisDirection.y, entity.xAxisDirection.x)\n : 0\n const rotationDegrees = (rotation * 180) / Math.PI\n\n const textWidth = content.length * height * 0.6\n const bbox0 = new Box2()\n .expandByPoint({ x, y })\n .expandByPoint({ x: x + textWidth, y: y + height })\n\n const element0 = `<text x=\"${x}\" y=\"${y}\" font-size=\"${height}\" transform=\"rotate(${-rotationDegrees} ${x} ${y}) scale(1,-1) translate(0 ${-2 * y})\">${escapeXmlText(content)}</text>`\n\n const { bbox, element } = addFlipXIfApplicable(entity, {\n bbox: bbox0,\n element: element0,\n })\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Create dimension visualization with DIMSTYLE support\n */\nconst dimension = (\n entity: DimensionEntity,\n dimStyle?: any,\n options?: ToSVGOptions,\n viewport?: { width: number; height: number },\n): BoundsAndElement => {\n const result = dimensionToSVG(entity, dimStyle, options, viewport)\n return transformBoundingBoxAndElement(\n result.bbox,\n result.element,\n entity.transforms ?? [],\n )\n}\n\nexport const piecewiseToPaths = (\n k: number,\n knots: number[],\n controlPoints: Array<{ x: number; y: number }>,\n): string[] => {\n const paths: string[] = []\n let controlPointIndex = 0\n let knotIndex = k\n while (knotIndex < knots.length - k + 1) {\n const m = multiplicity(knots, knotIndex)\n const cp = controlPoints.slice(controlPointIndex, controlPointIndex + k)\n if (k === 4) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} C ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y} ${cp[3].x} ${cp[3].y}\" />`,\n )\n } else if (k === 3) {\n paths.push(\n `<path d=\"M ${cp[0].x} ${cp[0].y} Q ${cp[1].x} ${cp[1].y} ${cp[2].x} ${cp[2].y}\" />`,\n )\n }\n controlPointIndex += m\n knotIndex += m\n }\n return paths\n}\n\nconst bezier = (entity: SplineEntity): BoundsAndElement => {\n let bbox = new Box2()\n for (const p of entity.controlPoints) {\n bbox = bbox.expandByPoint(p)\n }\n const k = entity.degree + 1\n const piecewise = toPiecewiseBezier(k, entity.controlPoints, entity.knots)\n const paths = piecewiseToPaths(k, piecewise.knots, piecewise.controlPoints)\n const element = `<g>${paths.join('')}</g>`\n return transformBoundingBoxAndElement(bbox, element, entity.transforms ?? [])\n}\n\n/**\n * Switch the appropriate function on entity type. CIRCLE, ARC and ELLIPSE\n * produce native SVG elements, the rest produce interpolated polylines.\n */\nconst entityToBoundsAndElement = (\n entity: Entity,\n dimStyles?: { [name: string]: any },\n options?: ToSVGOptions,\n viewport?: { width: number; height: number },\n): BoundsAndElement | null => {\n switch (entity.type) {\n case 'CIRCLE':\n return circle(entity as CircleEntity)\n case 'ELLIPSE':\n return ellipse(entity as EllipseEntity)\n case 'ARC':\n return arc(entity as ArcEntity)\n case 'TEXT':\n return text(entity as TextEntity)\n case 'MTEXT':\n return mtext(entity as MTextEntity)\n case 'DIMENSION': {\n const dimEntity = entity as DimensionEntity\n const styleName = typeof dimEntity.styleName === 'string'\n ? dimEntity.styleName\n : undefined\n const dimStyle = styleName && dimStyles\n ? dimStyles[styleName]\n : undefined\n return dimension(dimEntity, dimStyle, options, viewport)\n }\n case 'SPLINE': {\n const splineEntity = entity as SplineEntity\n const hasWeights = splineEntity.weights?.some((w: number) => w !== 1)\n if ((splineEntity.degree === 2 || splineEntity.degree === 3) && !hasWeights) {\n try {\n return bezier(splineEntity)\n } catch (err) {\n const error = err as Error\n logger.warn('bezier conversion failed, using polyline:', error.message)\n return polyline(entity)\n }\n } else {\n return polyline(entity)\n }\n }\n case 'LINE':\n case 'POLYLINE': {\n return polyline(entity)\n }\n case 'LWPOLYLINE': {\n return lwpolyline(entity)\n }\n case 'LEADER': {\n return leader(entity as LeaderEntity)\n }\n case 'TOLERANCE': {\n return tolerance(entity as ToleranceEntity)\n }\n default:\n logger.warn('entity type not supported in SVG rendering:', entity.type)\n return null\n }\n}\n\nexport default function toSVG(parsed: ParsedDXF, options: ToSVGOptions = {}): string {\n const entities = denormalise(parsed)\n const dimStyles = parsed.tables.dimStyles\n\n const geometryBBox = entities.reduce((acc: Box2, entity: Entity): Box2 => {\n if (entity.type === 'DIMENSION') {\n const bbox = getDimensionGeometryBBox(entity as DimensionEntity)\n if (bbox.valid) {\n acc.expandByPoint(bbox.min)\n acc.expandByPoint(bbox.max)\n }\n return acc\n }\n\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options)\n if (boundsAndElement?.bbox.valid) {\n acc.expandByPoint(boundsAndElement.bbox.min)\n acc.expandByPoint(boundsAndElement.bbox.max)\n }\n return acc\n }, new Box2())\n\n const viewport = geometryBBox.valid\n ? {\n width: geometryBBox.max.x - geometryBBox.min.x,\n height: geometryBBox.max.y - geometryBBox.min.y,\n }\n : {\n width: 0,\n height: 0,\n }\n\n const { bbox, elements } = entities.reduce(\n (\n acc: { bbox: Box2; elements: string[] },\n entity: Entity,\n ): { bbox: Box2; elements: string[] } => {\n const rgb = getRGBForEntity(parsed.tables.layers, entity)\n const boundsAndElement = entityToBoundsAndElement(entity, dimStyles, options, viewport)\n // Ignore entities that don't produce SVG elements or have unsupported types\n if (boundsAndElement) {\n const { bbox, element } = boundsAndElement\n // Ignore invalid bounding boxes\n if (bbox.valid) {\n acc.bbox.expandByPoint(bbox.min)\n acc.bbox.expandByPoint(bbox.max)\n }\n acc.elements.push(\n `<g stroke=\"${rgbToColorAttribute(rgb)}\">${element}</g>`,\n )\n }\n return acc\n },\n {\n bbox: new Box2(),\n elements: [],\n },\n )\n\n const viewBox = bbox.valid\n ? {\n x: bbox.min.x,\n y: -bbox.max.y,\n width: bbox.max.x - bbox.min.x,\n height: bbox.max.y - bbox.min.y,\n }\n : {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n }\n return `<?xml version=\"1.0\"?>\n<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\"\n preserveAspectRatio=\"xMinYMin meet\"\n viewBox=\"${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}\"\n width=\"100%\" height=\"100%\"\n>\n <g stroke=\"#000000\" stroke-width=\"0.1%\" fill=\"none\" transform=\"matrix(1,0,0,-1,0,0)\">\n ${elements.join('\\n')}\n </g>\n</svg>`\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["bbox"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/types/dimension-entity.ts"],
4
- "sourcesContent": ["// DIMENSION entity type\n\nimport type { BaseEntity } from './base-entity'\nimport type { Point3D } from './common'\n\nexport interface DimensionEntity extends BaseEntity {\n type: 'DIMENSION'\n block?: string\n start: Point3D\n measureStart: Point3D\n measureEnd: Point3D\n textMidpoint: Point3D\n rotation?: number\n horizonRotation?: number\n extensionRotation?: number\n textRotation?: number\n attachementPoint: number\n dimensionType: number\n extrudeDirection?: Point3D\n text?: string\n styleName?: string\n [key: string]: unknown\n}\n"],
4
+ "sourcesContent": ["// DIMENSION entity type\n\nimport type { BaseEntity } from './base-entity'\nimport type { Point3D } from './common'\n\nexport interface DimensionEntity extends BaseEntity {\n type: 'DIMENSION'\n block?: string\n start: Point3D\n /**\n * Angular vertex for DIMENSION type 5 (Angular 3-point).\n * This is parsed from group codes 15/25/35.\n */\n angleVertex?: Point3D\n\n /**\n * Angular arc location point for DIMENSION angular types.\n * This is parsed from group codes 16/26/36 (OCS in the DXF reference).\n */\n arcPoint?: Point3D\n measureStart: Point3D\n measureEnd: Point3D\n textMidpoint: Point3D\n rotation?: number\n horizonRotation?: number\n extensionRotation?: number\n textRotation?: number\n attachementPoint: number\n dimensionType: number\n extrudeDirection?: Point3D\n text?: string\n styleName?: string\n [key: string]: unknown\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/types/entity.ts"],
4
- "sourcesContent": ["// Union type for all entity types\n\nimport type { ArcEntity } from './arc-entity'\nimport type { BaseEntity } from './base-entity'\nimport type { CircleEntity } from './circle-entity'\nimport type { DimensionEntity } from './dimension-entity'\nimport type { EllipseEntity } from './ellipse-entity'\nimport type { HatchEntity } from './hatch-entity'\nimport type { InsertEntity } from './insert-entity'\nimport type { LineEntity } from './line-entity'\nimport type { MTextEntity } from './mtext-entity'\nimport type { PointEntity } from './point-entity'\nimport type { PolylineEntity } from './polyline-entity'\nimport type { SolidEntity } from './solid-entity'\nimport type { SplineEntity } from './spline-entity'\nimport type { TextEntity } from './text-entity'\n\nexport type Entity =\n | LineEntity\n | CircleEntity\n | ArcEntity\n | EllipseEntity\n | TextEntity\n | MTextEntity\n | PointEntity\n | PolylineEntity\n | SplineEntity\n | DimensionEntity\n | SolidEntity\n | InsertEntity\n | HatchEntity\n | BaseEntity\n"],
4
+ "sourcesContent": ["// Union type for all entity types\n\nimport type { ArcEntity } from './arc-entity'\nimport type { BaseEntity } from './base-entity'\nimport type { CircleEntity } from './circle-entity'\nimport type { DimensionEntity } from './dimension-entity'\nimport type { EllipseEntity } from './ellipse-entity'\nimport type { HatchEntity } from './hatch-entity'\nimport type { ImageEntity } from './image-entity'\nimport type { InsertEntity } from './insert-entity'\nimport type { LeaderEntity } from './leader-entity'\nimport type { LineEntity } from './line-entity'\nimport type { MTextEntity } from './mtext-entity'\nimport type { PointEntity } from './point-entity'\nimport type { PolylineEntity } from './polyline-entity'\nimport type { SolidEntity } from './solid-entity'\nimport type { SplineEntity } from './spline-entity'\nimport type { TextEntity } from './text-entity'\nimport type { ToleranceEntity } from './tolerance-entity'\nimport type { DgnUnderlayEntity, DwfUnderlayEntity, PdfUnderlayEntity } from './underlay-entity'\n\nexport type Entity =\n | LineEntity\n | CircleEntity\n | ArcEntity\n | EllipseEntity\n | TextEntity\n | MTextEntity\n | PointEntity\n | PolylineEntity\n | SplineEntity\n | DimensionEntity\n | SolidEntity\n | InsertEntity\n | ImageEntity\n | LeaderEntity\n | ToleranceEntity\n | DwfUnderlayEntity\n | DgnUnderlayEntity\n | PdfUnderlayEntity\n | HatchEntity\n | BaseEntity\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var image_entity_exports = {};
16
+ module.exports = __toCommonJS(image_entity_exports);
17
+ //# sourceMappingURL=image-entity.cjs.map