@twinfinity/printing 5.0.3-ci.28538-beta

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 (209) hide show
  1. package/README.md +208 -0
  2. package/dist/BuildInfo.d.ts +25 -0
  3. package/dist/BuildInfo.d.ts.map +1 -0
  4. package/dist/BuildInfo.js +15 -0
  5. package/dist/BuildInfo.js.map +1 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +9 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/layout/analyzeTemplate.d.ts +29 -0
  11. package/dist/layout/analyzeTemplate.d.ts.map +1 -0
  12. package/dist/layout/analyzeTemplate.js +168 -0
  13. package/dist/layout/analyzeTemplate.js.map +1 -0
  14. package/dist/layout/clipUtils.d.ts +18 -0
  15. package/dist/layout/clipUtils.d.ts.map +1 -0
  16. package/dist/layout/clipUtils.js +165 -0
  17. package/dist/layout/clipUtils.js.map +1 -0
  18. package/dist/layout/colorConstants.d.ts +11 -0
  19. package/dist/layout/colorConstants.d.ts.map +1 -0
  20. package/dist/layout/colorConstants.js +14 -0
  21. package/dist/layout/colorConstants.js.map +1 -0
  22. package/dist/layout/elementKinds.d.ts +21 -0
  23. package/dist/layout/elementKinds.d.ts.map +1 -0
  24. package/dist/layout/elementKinds.js +17 -0
  25. package/dist/layout/elementKinds.js.map +1 -0
  26. package/dist/layout/exportDrawing.d.ts +143 -0
  27. package/dist/layout/exportDrawing.d.ts.map +1 -0
  28. package/dist/layout/exportDrawing.js +146 -0
  29. package/dist/layout/exportDrawing.js.map +1 -0
  30. package/dist/layout/filters.d.ts +33 -0
  31. package/dist/layout/filters.d.ts.map +1 -0
  32. package/dist/layout/filters.js +77 -0
  33. package/dist/layout/filters.js.map +1 -0
  34. package/dist/layout/geometryConstants.d.ts +8 -0
  35. package/dist/layout/geometryConstants.d.ts.map +1 -0
  36. package/dist/layout/geometryConstants.js +10 -0
  37. package/dist/layout/geometryConstants.js.map +1 -0
  38. package/dist/layout/index.d.ts +86 -0
  39. package/dist/layout/index.d.ts.map +1 -0
  40. package/dist/layout/index.js +363 -0
  41. package/dist/layout/index.js.map +1 -0
  42. package/dist/layout/itemBuilders.d.ts +29 -0
  43. package/dist/layout/itemBuilders.d.ts.map +1 -0
  44. package/dist/layout/itemBuilders.js +135 -0
  45. package/dist/layout/itemBuilders.js.map +1 -0
  46. package/dist/layout/labelsRender.d.ts +29 -0
  47. package/dist/layout/labelsRender.d.ts.map +1 -0
  48. package/dist/layout/labelsRender.js +109 -0
  49. package/dist/layout/labelsRender.js.map +1 -0
  50. package/dist/layout/legendConstants.d.ts +12 -0
  51. package/dist/layout/legendConstants.d.ts.map +1 -0
  52. package/dist/layout/legendConstants.js +12 -0
  53. package/dist/layout/legendConstants.js.map +1 -0
  54. package/dist/layout/legendRender.d.ts +13 -0
  55. package/dist/layout/legendRender.d.ts.map +1 -0
  56. package/dist/layout/legendRender.js +424 -0
  57. package/dist/layout/legendRender.js.map +1 -0
  58. package/dist/layout/legendRows.d.ts +26 -0
  59. package/dist/layout/legendRows.d.ts.map +1 -0
  60. package/dist/layout/legendRows.js +45 -0
  61. package/dist/layout/legendRows.js.map +1 -0
  62. package/dist/layout/legendUtils.d.ts +21 -0
  63. package/dist/layout/legendUtils.d.ts.map +1 -0
  64. package/dist/layout/legendUtils.js +110 -0
  65. package/dist/layout/legendUtils.js.map +1 -0
  66. package/dist/layout/metadata.d.ts +43 -0
  67. package/dist/layout/metadata.d.ts.map +1 -0
  68. package/dist/layout/metadata.js +191 -0
  69. package/dist/layout/metadata.js.map +1 -0
  70. package/dist/layout/model.d.ts +15 -0
  71. package/dist/layout/model.d.ts.map +1 -0
  72. package/dist/layout/model.js +310 -0
  73. package/dist/layout/model.js.map +1 -0
  74. package/dist/layout/options.d.ts +17 -0
  75. package/dist/layout/options.d.ts.map +1 -0
  76. package/dist/layout/options.js +2 -0
  77. package/dist/layout/options.js.map +1 -0
  78. package/dist/layout/presets.d.ts +23 -0
  79. package/dist/layout/presets.d.ts.map +1 -0
  80. package/dist/layout/presets.js +41 -0
  81. package/dist/layout/presets.js.map +1 -0
  82. package/dist/layout/qrRender.d.ts +13 -0
  83. package/dist/layout/qrRender.d.ts.map +1 -0
  84. package/dist/layout/qrRender.js +97 -0
  85. package/dist/layout/qrRender.js.map +1 -0
  86. package/dist/layout/renderDrawing.d.ts +62 -0
  87. package/dist/layout/renderDrawing.d.ts.map +1 -0
  88. package/dist/layout/renderDrawing.js +555 -0
  89. package/dist/layout/renderDrawing.js.map +1 -0
  90. package/dist/layout/renderUtils.d.ts +36 -0
  91. package/dist/layout/renderUtils.d.ts.map +1 -0
  92. package/dist/layout/renderUtils.js +117 -0
  93. package/dist/layout/renderUtils.js.map +1 -0
  94. package/dist/layout/sectionValidation.d.ts +3 -0
  95. package/dist/layout/sectionValidation.d.ts.map +1 -0
  96. package/dist/layout/sectionValidation.js +2 -0
  97. package/dist/layout/sectionValidation.js.map +1 -0
  98. package/dist/layout/templateVariables.d.ts +137 -0
  99. package/dist/layout/templateVariables.d.ts.map +1 -0
  100. package/dist/layout/templateVariables.js +295 -0
  101. package/dist/layout/templateVariables.js.map +1 -0
  102. package/dist/layout/typeGuards.d.ts +5 -0
  103. package/dist/layout/typeGuards.d.ts.map +1 -0
  104. package/dist/layout/typeGuards.js +9 -0
  105. package/dist/layout/typeGuards.js.map +1 -0
  106. package/dist/layout/types.d.ts +816 -0
  107. package/dist/layout/types.d.ts.map +1 -0
  108. package/dist/layout/types.js +2 -0
  109. package/dist/layout/types.js.map +1 -0
  110. package/dist/layout/utils.d.ts +9 -0
  111. package/dist/layout/utils.d.ts.map +1 -0
  112. package/dist/layout/utils.js +84 -0
  113. package/dist/layout/utils.js.map +1 -0
  114. package/dist/layout/validation.d.ts +7 -0
  115. package/dist/layout/validation.d.ts.map +1 -0
  116. package/dist/layout/validation.js +352 -0
  117. package/dist/layout/validation.js.map +1 -0
  118. package/dist/layout/validationHelpers.d.ts +15 -0
  119. package/dist/layout/validationHelpers.d.ts.map +1 -0
  120. package/dist/layout/validationHelpers.js +43 -0
  121. package/dist/layout/validationHelpers.js.map +1 -0
  122. package/dist/layout/validationUtils.d.ts +5 -0
  123. package/dist/layout/validationUtils.d.ts.map +1 -0
  124. package/dist/layout/validationUtils.js +5 -0
  125. package/dist/layout/validationUtils.js.map +1 -0
  126. package/dist/layout/viewportPrep.d.ts +47 -0
  127. package/dist/layout/viewportPrep.d.ts.map +1 -0
  128. package/dist/layout/viewportPrep.js +275 -0
  129. package/dist/layout/viewportPrep.js.map +1 -0
  130. package/dist/layout/viewportRender.d.ts +42 -0
  131. package/dist/layout/viewportRender.d.ts.map +1 -0
  132. package/dist/layout/viewportRender.js +337 -0
  133. package/dist/layout/viewportRender.js.map +1 -0
  134. package/dist/layout/viewportUtils.d.ts +9 -0
  135. package/dist/layout/viewportUtils.d.ts.map +1 -0
  136. package/dist/layout/viewportUtils.js +40 -0
  137. package/dist/layout/viewportUtils.js.map +1 -0
  138. package/dist/layout/warnings.d.ts +2 -0
  139. package/dist/layout/warnings.d.ts.map +1 -0
  140. package/dist/layout/warnings.js +4 -0
  141. package/dist/layout/warnings.js.map +1 -0
  142. package/dist/printToPdf.d.ts +38 -0
  143. package/dist/printToPdf.d.ts.map +1 -0
  144. package/dist/printToPdf.js +79 -0
  145. package/dist/printToPdf.js.map +1 -0
  146. package/dist/printToSvg.d.ts +11 -0
  147. package/dist/printToSvg.d.ts.map +1 -0
  148. package/dist/printToSvg.js +168 -0
  149. package/dist/printToSvg.js.map +1 -0
  150. package/dist/sections.d.ts +118 -0
  151. package/dist/sections.d.ts.map +1 -0
  152. package/dist/sections.js +839 -0
  153. package/dist/sections.js.map +1 -0
  154. package/dist/templates/default-template.json +137 -0
  155. package/dist/types.d.ts +54 -0
  156. package/dist/types.d.ts.map +1 -0
  157. package/dist/types.js +11 -0
  158. package/dist/types.js.map +1 -0
  159. package/package.json +47 -0
  160. package/src/BuildInfo.ts +41 -0
  161. package/src/index.ts +10 -0
  162. package/src/layout/analyzeTemplate.ts +218 -0
  163. package/src/layout/clipUtils.ts +193 -0
  164. package/src/layout/colorConstants.ts +16 -0
  165. package/src/layout/elementKinds.ts +35 -0
  166. package/src/layout/exportDrawing.ts +206 -0
  167. package/src/layout/filters.ts +80 -0
  168. package/src/layout/geometryConstants.ts +11 -0
  169. package/src/layout/index.ts +671 -0
  170. package/src/layout/itemBuilders.ts +159 -0
  171. package/src/layout/labelsRender.ts +170 -0
  172. package/src/layout/legendConstants.ts +11 -0
  173. package/src/layout/legendRender.ts +543 -0
  174. package/src/layout/legendRows.ts +62 -0
  175. package/src/layout/legendUtils.ts +144 -0
  176. package/src/layout/metadata.ts +210 -0
  177. package/src/layout/model.ts +372 -0
  178. package/src/layout/options.ts +17 -0
  179. package/src/layout/presets.ts +51 -0
  180. package/src/layout/qrRender.ts +126 -0
  181. package/src/layout/qrcode.d.ts +2 -0
  182. package/src/layout/renderDrawing.ts +710 -0
  183. package/src/layout/renderUtils.ts +138 -0
  184. package/src/layout/sectionValidation.ts +2 -0
  185. package/src/layout/templateVariables.ts +317 -0
  186. package/src/layout/typeGuards.ts +9 -0
  187. package/src/layout/types.ts +835 -0
  188. package/src/layout/utils.ts +85 -0
  189. package/src/layout/validation.ts +392 -0
  190. package/src/layout/validationHelpers.ts +59 -0
  191. package/src/layout/validationUtils.ts +6 -0
  192. package/src/layout/viewportPrep.ts +351 -0
  193. package/src/layout/viewportRender.ts +442 -0
  194. package/src/layout/viewportUtils.ts +50 -0
  195. package/src/layout/warnings.ts +3 -0
  196. package/src/printToPdf.ts +108 -0
  197. package/src/printToSvg.ts +188 -0
  198. package/src/sections.ts +1019 -0
  199. package/src/templates/default-template.json +137 -0
  200. package/src/types.ts +49 -0
  201. package/templates/default-a0-landscape.json +209 -0
  202. package/templates/default-a0-portrait.json +195 -0
  203. package/templates/default-a1-landscape.json +167 -0
  204. package/templates/default-a1-portrait.json +153 -0
  205. package/templates/default-a3-landscape.json +111 -0
  206. package/templates/default-a3-portrait.json +125 -0
  207. package/templates/default-a4-landscape.json +97 -0
  208. package/templates/default-a4-portrait.json +97 -0
  209. package/templates/template-schema.json +1395 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printToPdf.js","sourceRoot":"/","sources":["printToPdf.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * PDF export via jsPDF + svg2pdf.js\r\n *\r\n * These are optional peer dependencies. Functions will throw at runtime if not installed.\r\n */\r\n\r\nexport interface PrintToPdfOptions {\r\n svgMarkup: string;\r\n fileName?: string;\r\n pageFormat?: 'a0' | 'a1' | 'a2' | 'a3' | 'a4';\r\n orientation?: 'portrait' | 'landscape';\r\n marginMm?: number;\r\n}\r\n\r\n/**\r\n * Export an SVG string to a PDF file.\r\n * Requires jspdf and svg2pdf.js as peer dependencies.\r\n */\r\nexport async function printToPdf(options: PrintToPdfOptions): Promise<Blob> {\r\n // Dynamic imports for optional peer dependencies (installed by consumer, not this package)\r\n let jspdfModule: any;\r\n try {\r\n // @ts-expect-error — optional peer dependency resolved at runtime\r\n jspdfModule = await import('jspdf');\r\n } catch {\r\n throw new Error('jspdf is required for PDF export. Install it: bun add jspdf');\r\n }\r\n try {\r\n // @ts-expect-error — optional peer dependency resolved at runtime\r\n await import('svg2pdf.js');\r\n } catch {\r\n throw new Error('svg2pdf.js is required for PDF export. Install it: bun add svg2pdf.js');\r\n }\r\n\r\n const { jsPDF } = jspdfModule;\r\n const format = options.pageFormat ?? 'a3';\r\n const orientation = options.orientation ?? 'landscape';\r\n const margin = options.marginMm ?? 10;\r\n\r\n const doc = new jsPDF({ format, orientation, unit: 'mm' });\r\n const pageWidth = doc.internal.pageSize.getWidth();\r\n const pageHeight = doc.internal.pageSize.getHeight();\r\n\r\n const parser = new DOMParser();\r\n const svgDoc = parser.parseFromString(options.svgMarkup, 'image/svg+xml');\r\n const svgElement = svgDoc.documentElement;\r\n\r\n await doc.svg(svgElement, {\r\n x: margin,\r\n y: margin,\r\n width: pageWidth - margin * 2,\r\n height: pageHeight - margin * 2\r\n });\r\n\r\n const blob = doc.output('blob');\r\n\r\n if (options.fileName) {\r\n doc.save(options.fileName);\r\n }\r\n\r\n return blob;\r\n}\r\n\r\n/**\r\n * Export an SVG string directly as a downloadable SVG file.\r\n */\r\nexport function printToSvgFile(svgMarkup: string, fileName: string): void {\r\n const blob = new Blob([svgMarkup], { type: 'image/svg+xml' });\r\n const url = URL.createObjectURL(blob);\r\n const link = document.createElement('a');\r\n link.href = url;\r\n link.download = fileName;\r\n link.click();\r\n URL.revokeObjectURL(url);\r\n}\r\n\r\n// Compatibility wrappers for print-layout module\r\nexport interface ExportSectionToPdfOptions {\r\n svgMarkup: string;\r\n fileName: string;\r\n pageSizeMm?: { width: number; height: number };\r\n openInNewTab?: boolean;\r\n}\r\n\r\nexport async function exportSectionToPdf(options: ExportSectionToPdfOptions): Promise<void> {\r\n await printToPdf({\r\n svgMarkup: options.svgMarkup,\r\n fileName: options.fileName\r\n });\r\n}\r\n\r\nexport interface ExportSectionToSvgOptions {\r\n svgMarkup: string;\r\n fileName: string;\r\n openInNewTab?: boolean;\r\n}\r\n\r\nexport function exportSectionToSvg(options: ExportSectionToSvgOptions): void {\r\n if (options.openInNewTab) {\r\n const blob = new Blob([options.svgMarkup], { type: 'image/svg+xml' });\r\n const url = URL.createObjectURL(blob);\r\n window.open(url, '_blank');\r\n // Revoke after a delay to allow the new tab to load the blob\r\n setTimeout(() => URL.revokeObjectURL(url), 60_000);\r\n } else {\r\n printToSvgFile(options.svgMarkup, options.fileName);\r\n }\r\n}\r\n"]}
@@ -0,0 +1,11 @@
1
+ import type { SlabSectionGeometry } from '@twinfinity/geometry';
2
+ import type { PrintToSvgOptions } from './types';
3
+ /**
4
+ * Render SlabSectionGeometry to an SVG string.
5
+ *
6
+ * @param geometry The computed slab section geometry
7
+ * @param options Rendering options (viewBox, styles, planeBasis, etc.)
8
+ * @returns Complete SVG string
9
+ */
10
+ export declare function printToSvg(geometry: SlabSectionGeometry, options?: PrintToSvgOptions): string;
11
+ //# sourceMappingURL=printToSvg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printToSvg.d.ts","sourceRoot":"/","sources":["printToSvg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAQ,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAkC,MAAM,SAAS,CAAC;AAMjF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,mBAAmB,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CA6EjG"}
@@ -0,0 +1,168 @@
1
+ import { DEFAULT_SVG_STYLES } from './types';
2
+ /**
3
+ * Render SlabSectionGeometry to an SVG string.
4
+ *
5
+ * @param geometry The computed slab section geometry
6
+ * @param options Rendering options (viewBox, styles, planeBasis, etc.)
7
+ * @returns Complete SVG string
8
+ */
9
+ export function printToSvg(geometry, options = {}) {
10
+ if (!geometry)
11
+ throw new Error('geometry is required');
12
+ if (options.boundsPadding !== undefined &&
13
+ (typeof options.boundsPadding !== 'number' || options.boundsPadding < 0)) {
14
+ throw new Error('boundsPadding must be a non-negative number');
15
+ }
16
+ if (options.viewBox) {
17
+ if (!Array.isArray(options.viewBox) || options.viewBox.length !== 4) {
18
+ throw new Error('viewBox must be an array of 4 numbers [minX, minY, width, height]');
19
+ }
20
+ for (let i = 0; i < 4; i++) {
21
+ if (typeof options.viewBox[i] !== 'number' || !Number.isFinite(options.viewBox[i])) {
22
+ throw new Error(`viewBox[${i}] must be a finite number`);
23
+ }
24
+ }
25
+ }
26
+ const styles = mergeStyles(options.styles);
27
+ const includeXml = options.includeXmlDeclaration ?? true;
28
+ // Project all polylines to 2D once
29
+ const proj = {
30
+ hiddenLines: projectPolylines(geometry.hiddenLines, options.planeBasis),
31
+ outlineHidden: projectPolylines(geometry.outlineHidden, options.planeBasis),
32
+ visibleLines: projectPolylines(geometry.visibleLines, options.planeBasis),
33
+ outlineVisible: projectPolylines(geometry.outlineVisible, options.planeBasis),
34
+ silhouettes: projectPolylines(geometry.silhouettes, options.planeBasis),
35
+ featureEdges: projectPolylines(geometry.featureEdges, options.planeBasis),
36
+ cutLines: projectPolylines(geometry.cutLines, options.planeBasis),
37
+ stairArrows: projectPolylines(geometry.stairArrows, options.planeBasis)
38
+ };
39
+ const bounds = options.bounds ?? computeBoundsFromProjected(proj);
40
+ const viewBox = options.viewBox ?? boundsToViewBox(bounds, options.boundsPadding ?? 0.05);
41
+ const parts = [];
42
+ if (includeXml)
43
+ parts.push('<?xml version="1.0" encoding="UTF-8"?>');
44
+ const [minX, minY, width, height] = viewBox;
45
+ parts.push(`<svg xmlns="http://www.w3.org/2000/svg" ` +
46
+ `viewBox="${minX} ${minY} ${width} ${height}" ` +
47
+ `width="${width}" height="${height}">`);
48
+ if (options.backgroundColor) {
49
+ parts.push(`<rect x="${minX}" y="${minY}" width="${width}" height="${height}" fill="${options.backgroundColor}"/>`);
50
+ }
51
+ parts.push('<g fill="none" stroke-linecap="round" stroke-linejoin="round">');
52
+ const categories = [
53
+ ['hiddenLines', 'hiddenLines'],
54
+ ['outlineHidden', 'outlineHidden'],
55
+ ['visibleLines', 'visibleLines'],
56
+ ['outlineVisible', 'outlineVisible'],
57
+ ['silhouettes', 'silhouettes'],
58
+ ['featureEdges', 'featureEdges'],
59
+ ['cutLines', 'cutLines'],
60
+ ['stairArrows', 'stairArrows']
61
+ ];
62
+ for (const [key, styleKey] of categories) {
63
+ const style = styles[styleKey];
64
+ if (style.enabled)
65
+ renderProjectedCategory(parts, proj[key], style, bounds);
66
+ }
67
+ parts.push('</g>');
68
+ parts.push('</svg>');
69
+ return parts.join('\n');
70
+ }
71
+ function projectPolylines(polylines, planeBasis) {
72
+ const result = [];
73
+ for (const polyline of polylines) {
74
+ if (polyline.length === 0)
75
+ continue;
76
+ const projected = [];
77
+ for (const point of polyline) {
78
+ if (!Number.isFinite(point[0]) || !Number.isFinite(point[1]) || !Number.isFinite(point[2]))
79
+ continue;
80
+ if (planeBasis) {
81
+ const dx = point[0] - planeBasis.origin.x;
82
+ const dy = point[1] - planeBasis.origin.y;
83
+ const dz = point[2] - planeBasis.origin.z;
84
+ projected.push({
85
+ x: dx * planeBasis.right.x + dy * planeBasis.right.y + dz * planeBasis.right.z,
86
+ y: dx * planeBasis.up.x + dy * planeBasis.up.y + dz * planeBasis.up.z
87
+ });
88
+ }
89
+ else {
90
+ projected.push({ x: point[0], y: -point[2] });
91
+ }
92
+ }
93
+ if (projected.length > 0)
94
+ result.push(projected);
95
+ }
96
+ return result;
97
+ }
98
+ function computeBoundsFromProjected(categories) {
99
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
100
+ for (const polylines of Object.values(categories)) {
101
+ for (const polyline of polylines) {
102
+ for (const pt of polyline) {
103
+ if (pt.x < minX)
104
+ minX = pt.x;
105
+ if (pt.x > maxX)
106
+ maxX = pt.x;
107
+ if (pt.y < minY)
108
+ minY = pt.y;
109
+ if (pt.y > maxY)
110
+ maxY = pt.y;
111
+ }
112
+ }
113
+ }
114
+ if (!Number.isFinite(minX))
115
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
116
+ return { minX, maxX, minY, maxY };
117
+ }
118
+ function renderProjectedCategory(parts, polylines, style, bounds) {
119
+ if (!polylines.length)
120
+ return;
121
+ const pathData = projectedToPathData(polylines, bounds);
122
+ if (!pathData)
123
+ return;
124
+ let pathElement = `<path d="${pathData}"`;
125
+ if (style.stroke)
126
+ pathElement += ` stroke="${style.stroke}"`;
127
+ if (style.strokeWidth !== undefined)
128
+ pathElement += ` stroke-width="${style.strokeWidth}"`;
129
+ if (style.strokeDasharray)
130
+ pathElement += ` stroke-dasharray="${style.strokeDasharray}"`;
131
+ if (style.opacity !== undefined && style.opacity !== 1)
132
+ pathElement += ` opacity="${style.opacity}"`;
133
+ pathElement += '/>';
134
+ parts.push(pathElement);
135
+ }
136
+ function projectedToPathData(polylines, bounds) {
137
+ const parts = [];
138
+ const ox = bounds.minX;
139
+ const oy = bounds.maxY;
140
+ for (const polyline of polylines) {
141
+ if (polyline.length === 0)
142
+ continue;
143
+ parts.push(`M ${(polyline[0].x - ox).toFixed(6)} ${(oy - polyline[0].y).toFixed(6)}`);
144
+ for (let i = 1; i < polyline.length; i++) {
145
+ parts.push(`L ${(polyline[i].x - ox).toFixed(6)} ${(oy - polyline[i].y).toFixed(6)}`);
146
+ }
147
+ }
148
+ return parts.join(' ');
149
+ }
150
+ function boundsToViewBox(bounds, padding) {
151
+ const width = bounds.maxX - bounds.minX;
152
+ const height = bounds.maxY - bounds.minY;
153
+ const padAmount = Math.max(width, height) * padding;
154
+ return [-padAmount, -padAmount, width + padAmount * 2, height + padAmount * 2];
155
+ }
156
+ function mergeStyles(userStyles) {
157
+ return {
158
+ cutLines: { ...DEFAULT_SVG_STYLES.cutLines, ...userStyles?.cutLines },
159
+ visibleLines: { ...DEFAULT_SVG_STYLES.visibleLines, ...userStyles?.visibleLines },
160
+ hiddenLines: { ...DEFAULT_SVG_STYLES.hiddenLines, ...userStyles?.hiddenLines },
161
+ silhouettes: { ...DEFAULT_SVG_STYLES.silhouettes, ...userStyles?.silhouettes },
162
+ featureEdges: { ...DEFAULT_SVG_STYLES.featureEdges, ...userStyles?.featureEdges },
163
+ stairArrows: { ...DEFAULT_SVG_STYLES.stairArrows, ...userStyles?.stairArrows },
164
+ outlineVisible: { ...DEFAULT_SVG_STYLES.outlineVisible, ...userStyles?.outlineVisible },
165
+ outlineHidden: { ...DEFAULT_SVG_STYLES.outlineHidden, ...userStyles?.outlineHidden }
166
+ };
167
+ }
168
+ //# sourceMappingURL=printToSvg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printToSvg.js","sourceRoot":"/","sources":["printToSvg.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SlabSectionGeometry, Vec3 } from '@twinfinity/geometry';\r\nimport type { PrintToSvgOptions, SvgRenderStyles, SvgPlaneBasis } from './types';\r\nimport { DEFAULT_SVG_STYLES } from './types';\r\n\r\ntype Pt2 = { x: number; y: number };\r\ntype Bounds = { minX: number; maxX: number; minY: number; maxY: number };\r\n\r\n/**\r\n * Render SlabSectionGeometry to an SVG string.\r\n *\r\n * @param geometry The computed slab section geometry\r\n * @param options Rendering options (viewBox, styles, planeBasis, etc.)\r\n * @returns Complete SVG string\r\n */\r\nexport function printToSvg(geometry: SlabSectionGeometry, options: PrintToSvgOptions = {}): string {\r\n if (!geometry) throw new Error('geometry is required');\r\n\r\n if (\r\n options.boundsPadding !== undefined &&\r\n (typeof options.boundsPadding !== 'number' || options.boundsPadding < 0)\r\n ) {\r\n throw new Error('boundsPadding must be a non-negative number');\r\n }\r\n\r\n if (options.viewBox) {\r\n if (!Array.isArray(options.viewBox) || options.viewBox.length !== 4) {\r\n throw new Error('viewBox must be an array of 4 numbers [minX, minY, width, height]');\r\n }\r\n for (let i = 0; i < 4; i++) {\r\n if (typeof options.viewBox[i] !== 'number' || !Number.isFinite(options.viewBox[i])) {\r\n throw new Error(`viewBox[${i}] must be a finite number`);\r\n }\r\n }\r\n }\r\n\r\n const styles = mergeStyles(options.styles);\r\n const includeXml = options.includeXmlDeclaration ?? true;\r\n\r\n // Project all polylines to 2D once\r\n const proj = {\r\n hiddenLines: projectPolylines(geometry.hiddenLines, options.planeBasis),\r\n outlineHidden: projectPolylines(geometry.outlineHidden, options.planeBasis),\r\n visibleLines: projectPolylines(geometry.visibleLines, options.planeBasis),\r\n outlineVisible: projectPolylines(geometry.outlineVisible, options.planeBasis),\r\n silhouettes: projectPolylines(geometry.silhouettes, options.planeBasis),\r\n featureEdges: projectPolylines(geometry.featureEdges, options.planeBasis),\r\n cutLines: projectPolylines(geometry.cutLines, options.planeBasis),\r\n stairArrows: projectPolylines(geometry.stairArrows, options.planeBasis)\r\n };\r\n\r\n const bounds = options.bounds ?? computeBoundsFromProjected(proj);\r\n const viewBox = options.viewBox ?? boundsToViewBox(bounds, options.boundsPadding ?? 0.05);\r\n\r\n const parts: string[] = [];\r\n\r\n if (includeXml) parts.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\r\n\r\n const [minX, minY, width, height] = viewBox;\r\n parts.push(\r\n `<svg xmlns=\"http://www.w3.org/2000/svg\" ` +\r\n `viewBox=\"${minX} ${minY} ${width} ${height}\" ` +\r\n `width=\"${width}\" height=\"${height}\">`\r\n );\r\n\r\n if (options.backgroundColor) {\r\n parts.push(\r\n `<rect x=\"${minX}\" y=\"${minY}\" width=\"${width}\" height=\"${height}\" fill=\"${options.backgroundColor}\"/>`\r\n );\r\n }\r\n\r\n parts.push('<g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">');\r\n\r\n const categories: Array<[keyof typeof proj, keyof Required<SvgRenderStyles>]> = [\r\n ['hiddenLines', 'hiddenLines'],\r\n ['outlineHidden', 'outlineHidden'],\r\n ['visibleLines', 'visibleLines'],\r\n ['outlineVisible', 'outlineVisible'],\r\n ['silhouettes', 'silhouettes'],\r\n ['featureEdges', 'featureEdges'],\r\n ['cutLines', 'cutLines'],\r\n ['stairArrows', 'stairArrows']\r\n ];\r\n\r\n for (const [key, styleKey] of categories) {\r\n const style = styles[styleKey];\r\n if (style.enabled) renderProjectedCategory(parts, proj[key], style, bounds);\r\n }\r\n\r\n parts.push('</g>');\r\n parts.push('</svg>');\r\n return parts.join('\\n');\r\n}\r\n\r\nfunction projectPolylines(polylines: Vec3[][], planeBasis?: SvgPlaneBasis): Pt2[][] {\r\n const result: Pt2[][] = [];\r\n for (const polyline of polylines) {\r\n if (polyline.length === 0) continue;\r\n const projected: Pt2[] = [];\r\n for (const point of polyline) {\r\n if (!Number.isFinite(point[0]) || !Number.isFinite(point[1]) || !Number.isFinite(point[2])) continue;\r\n if (planeBasis) {\r\n const dx = point[0] - planeBasis.origin.x;\r\n const dy = point[1] - planeBasis.origin.y;\r\n const dz = point[2] - planeBasis.origin.z;\r\n projected.push({\r\n x: dx * planeBasis.right.x + dy * planeBasis.right.y + dz * planeBasis.right.z,\r\n y: dx * planeBasis.up.x + dy * planeBasis.up.y + dz * planeBasis.up.z\r\n });\r\n } else {\r\n projected.push({ x: point[0], y: -point[2] });\r\n }\r\n }\r\n if (projected.length > 0) result.push(projected);\r\n }\r\n return result;\r\n}\r\n\r\nfunction computeBoundsFromProjected(categories: Record<string, Pt2[][]>): Bounds {\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const polylines of Object.values(categories)) {\r\n for (const polyline of polylines) {\r\n for (const pt of polyline) {\r\n if (pt.x < minX) minX = pt.x;\r\n if (pt.x > maxX) maxX = pt.x;\r\n if (pt.y < minY) minY = pt.y;\r\n if (pt.y > maxY) maxY = pt.y;\r\n }\r\n }\r\n }\r\n if (!Number.isFinite(minX)) return { minX: 0, maxX: 1, minY: 0, maxY: 1 };\r\n return { minX, maxX, minY, maxY };\r\n}\r\n\r\nfunction renderProjectedCategory(\r\n parts: string[],\r\n polylines: Pt2[][],\r\n style: { stroke?: string; strokeWidth?: number; strokeDasharray?: string; opacity?: number },\r\n bounds: Bounds\r\n): void {\r\n if (!polylines.length) return;\r\n const pathData = projectedToPathData(polylines, bounds);\r\n if (!pathData) return;\r\n\r\n let pathElement = `<path d=\"${pathData}\"`;\r\n if (style.stroke) pathElement += ` stroke=\"${style.stroke}\"`;\r\n if (style.strokeWidth !== undefined) pathElement += ` stroke-width=\"${style.strokeWidth}\"`;\r\n if (style.strokeDasharray) pathElement += ` stroke-dasharray=\"${style.strokeDasharray}\"`;\r\n if (style.opacity !== undefined && style.opacity !== 1) pathElement += ` opacity=\"${style.opacity}\"`;\r\n pathElement += '/>';\r\n parts.push(pathElement);\r\n}\r\n\r\nfunction projectedToPathData(polylines: Pt2[][], bounds: Bounds): string {\r\n const parts: string[] = [];\r\n const ox = bounds.minX;\r\n const oy = bounds.maxY;\r\n for (const polyline of polylines) {\r\n if (polyline.length === 0) continue;\r\n parts.push(`M ${(polyline[0].x - ox).toFixed(6)} ${(oy - polyline[0].y).toFixed(6)}`);\r\n for (let i = 1; i < polyline.length; i++) {\r\n parts.push(`L ${(polyline[i].x - ox).toFixed(6)} ${(oy - polyline[i].y).toFixed(6)}`);\r\n }\r\n }\r\n return parts.join(' ');\r\n}\r\n\r\nfunction boundsToViewBox(bounds: Bounds, padding: number): [number, number, number, number] {\r\n const width = bounds.maxX - bounds.minX;\r\n const height = bounds.maxY - bounds.minY;\r\n const padAmount = Math.max(width, height) * padding;\r\n return [-padAmount, -padAmount, width + padAmount * 2, height + padAmount * 2];\r\n}\r\n\r\nfunction mergeStyles(userStyles?: SvgRenderStyles): Required<SvgRenderStyles> {\r\n return {\r\n cutLines: { ...DEFAULT_SVG_STYLES.cutLines, ...userStyles?.cutLines },\r\n visibleLines: { ...DEFAULT_SVG_STYLES.visibleLines, ...userStyles?.visibleLines },\r\n hiddenLines: { ...DEFAULT_SVG_STYLES.hiddenLines, ...userStyles?.hiddenLines },\r\n silhouettes: { ...DEFAULT_SVG_STYLES.silhouettes, ...userStyles?.silhouettes },\r\n featureEdges: { ...DEFAULT_SVG_STYLES.featureEdges, ...userStyles?.featureEdges },\r\n stairArrows: { ...DEFAULT_SVG_STYLES.stairArrows, ...userStyles?.stairArrows },\r\n outlineVisible: { ...DEFAULT_SVG_STYLES.outlineVisible, ...userStyles?.outlineVisible },\r\n outlineHidden: { ...DEFAULT_SVG_STYLES.outlineHidden, ...userStyles?.outlineHidden }\r\n };\r\n}\r\n"]}
@@ -0,0 +1,118 @@
1
+ import type { Vec3, SectionLabel, SectionPath, SectionRenderState, TransformInfo, ViewWindow } from '@twinfinity/geometry';
2
+ export type { SectionLabel, SectionPath, SectionRenderState, TransformInfo, ViewWindow } from '@twinfinity/geometry';
3
+ /** Minimal product interface for section fill matching. */
4
+ interface SectionProduct {
5
+ class?: {
6
+ is(c: unknown): boolean;
7
+ type?: string;
8
+ id?: string;
9
+ };
10
+ className?: string;
11
+ propertySets?: Record<string, unknown>;
12
+ properties?: {
13
+ data?: Record<string, unknown>;
14
+ sets?: Record<string, unknown>;
15
+ };
16
+ }
17
+ /** Local replacement for PlaneSectionEntry (not available in @twinfinity/geometry). */
18
+ type PlaneSectionEntry<TProduct extends SectionProduct = SectionProduct> = {
19
+ product: TProduct;
20
+ segments: [Vec3, Vec3][];
21
+ polylines: {
22
+ points: Vec3[];
23
+ closed: boolean;
24
+ }[];
25
+ };
26
+ /**
27
+ * Resolve a dotted property path (e.g. "BIP.spacetype") against a product.
28
+ * Handles both the new T8 API (propertySets → .properties → .value) and
29
+ * legacy BimIfcObject (properties.sets / properties.data).
30
+ *
31
+ * Returns the resolved value, or undefined if not found.
32
+ */
33
+ export declare function resolveProductProperty(product: SectionProduct | unknown, path: string): unknown;
34
+ /** Base SVG display width in layout units. */
35
+ export declare const BASE_WIDTH = 240;
36
+ /** Minimum SVG display height in layout units. */
37
+ export declare const MIN_HEIGHT = 140;
38
+ /** Margin ratio applied around section bounds (fraction of world extent). */
39
+ export declare const SECTION_MARGIN_RATIO = 0.05;
40
+ /** Maximum zoom factor for viewport clamping. */
41
+ export declare const MAX_ZOOM_FACTOR = 12;
42
+ /** Multiplicative step for zooming in. */
43
+ export declare const ZOOM_IN_STEP = 0.8;
44
+ /** Multiplicative step for zooming out. */
45
+ export declare const ZOOM_OUT_STEP: number;
46
+ /** Clamp a number to a min/max range. */
47
+ export declare function clampValue(value: number, min: number, max: number): number;
48
+ export interface SectionBuildOptions {
49
+ /** If true, attach source product metadata to paths/labels for downstream filtering */
50
+ includeMeta?: boolean;
51
+ /** When true, create fill paths for closed polygons. When false, create only stroke/outline paths. Defaults to true for backward compatibility. */
52
+ createFills?: boolean;
53
+ /** Plane normal vector for determining 2D projection axes. If omitted, defaults to horizontal plan (Y-up). */
54
+ planeNormal?: Vec3;
55
+ }
56
+ /** Default fill opacity when a fill rule omits `fillOpacity`. */
57
+ export declare const DEFAULT_FILL_OPACITY = 0.35;
58
+ /**
59
+ * Fill rule controlling which products get visible fills and at what opacity.
60
+ * Mirrors the template-level FillRule but kept minimal to avoid circular deps.
61
+ */
62
+ export interface SectionFillRule {
63
+ /** IFC class filter. When omitted, matches all products. */
64
+ class?: string | string[];
65
+ /** Property-based filter (e.g. { "BIP.spacetype": "ROOM" }). */
66
+ where?: Record<string, string | number | boolean | Array<string | number>>;
67
+ /** Fill opacity (0–1). Default: {@link DEFAULT_FILL_OPACITY}. */
68
+ fillOpacity?: number;
69
+ /** When true, only apply fill to products whose centroid is inside the clip polygon. @default false */
70
+ matchClipFilter?: boolean;
71
+ }
72
+ export interface BuildSectionStateOptions {
73
+ viewport?: ViewWindow;
74
+ strokeWidth?: number;
75
+ labelFontSize?: number;
76
+ /**
77
+ * Fill rules controlling which products get visible fills and at what opacity.
78
+ * Products matching a fill rule are rendered below non-matching products.
79
+ * When absent or empty, all products render uniformly (no fill-based reordering).
80
+ */
81
+ fills?: SectionFillRule[];
82
+ includeMeta?: boolean;
83
+ /** Enable labels. Requires buildLabels callback. */
84
+ includeLabels?: boolean;
85
+ /** Callback to build labels for matching products. Required when includeLabels is true. */
86
+ buildLabels?: (products: any[], fontSize: number) => SectionLabel[];
87
+ /** Clip polygon in world coordinates (x, z). Used when fill.matchClipFilter is true for spatial filtering. */
88
+ clipPolygon?: Array<Array<{
89
+ x: number;
90
+ z: number;
91
+ }>>;
92
+ /** When true, create fill paths for closed polygons. When false, create only stroke/outline paths. Defaults to true for backward compatibility. */
93
+ createFills?: boolean;
94
+ /** Plane normal vector for determining 2D projection axes. If omitted, defaults to horizontal plan (Y-up). */
95
+ planeNormal?: Vec3;
96
+ }
97
+ /** Convert plane section polylines to SVG path data with fill colors and stroke styles. */
98
+ export declare function createSectionSvg(perProduct: PlaneSectionEntry[], viewport?: ViewWindow, strokeWidthHint?: number, labels?: SectionLabel[], options?: SectionBuildOptions): SectionRenderState | null;
99
+ /**
100
+ * Build a complete SectionRenderState from plane section entries, with optional
101
+ * fill-rule-based separation, ordering, and label generation.
102
+ *
103
+ * When `fills` rules are provided, entries matching a fill rule are rendered
104
+ * below non-matching entries, with their fill opacity set by the matching rule.
105
+ */
106
+ export declare function buildSectionStateForEntries(perProduct: PlaneSectionEntry[], options: BuildSectionStateOptions): (SectionRenderState & {
107
+ rawPaths?: SectionPath[];
108
+ rawLabels?: SectionLabel[];
109
+ }) | null;
110
+ /** Extract the viewport bounding box from a TransformInfo. */
111
+ export declare function extractViewWindow(transform: TransformInfo): ViewWindow;
112
+ /** Compare two viewport windows for equality within a tolerance. */
113
+ export declare function windowsEqual(a: ViewWindow, b: ViewWindow, epsilon?: number): boolean;
114
+ /** Constrain a viewport window within base bounds, preserving aspect ratio. */
115
+ export declare function clampViewWindow(base: TransformInfo, candidate: ViewWindow): ViewWindow;
116
+ /** Adjust stroke width proportionally to zoom level. */
117
+ export declare function strokeWidthForWindow(baseStroke: number, baseTransform: TransformInfo, window: ViewWindow): number;
118
+ //# sourceMappingURL=sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.d.ts","sourceRoot":"/","sources":["sections.ts"],"names":[],"mappings":"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"}