@ifc-lite/renderer 1.41.1 → 1.44.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 (120) hide show
  1. package/dist/camera-animation.d.ts +20 -32
  2. package/dist/camera-animation.d.ts.map +1 -1
  3. package/dist/camera-animation.js +71 -358
  4. package/dist/camera-animation.js.map +1 -1
  5. package/dist/camera-controls.d.ts +11 -51
  6. package/dist/camera-controls.d.ts.map +1 -1
  7. package/dist/camera-controls.js +140 -12
  8. package/dist/camera-controls.js.map +1 -1
  9. package/dist/camera-first-person.d.ts +52 -0
  10. package/dist/camera-first-person.d.ts.map +1 -0
  11. package/dist/camera-first-person.js +119 -0
  12. package/dist/camera-first-person.js.map +1 -0
  13. package/dist/camera-fit-policy.d.ts.map +1 -1
  14. package/dist/camera-fit-policy.js +18 -7
  15. package/dist/camera-fit-policy.js.map +1 -1
  16. package/dist/camera-framing.d.ts +86 -0
  17. package/dist/camera-framing.d.ts.map +1 -0
  18. package/dist/camera-framing.js +230 -0
  19. package/dist/camera-framing.js.map +1 -0
  20. package/dist/camera-guards.d.ts +148 -0
  21. package/dist/camera-guards.d.ts.map +1 -0
  22. package/dist/camera-guards.js +150 -0
  23. package/dist/camera-guards.js.map +1 -0
  24. package/dist/camera-matrices.d.ts +14 -0
  25. package/dist/camera-matrices.d.ts.map +1 -0
  26. package/dist/camera-matrices.js +146 -0
  27. package/dist/camera-matrices.js.map +1 -0
  28. package/dist/camera-preset-view.d.ts +56 -0
  29. package/dist/camera-preset-view.d.ts.map +1 -0
  30. package/dist/camera-preset-view.js +180 -0
  31. package/dist/camera-preset-view.js.map +1 -0
  32. package/dist/camera-projection.d.ts +1 -1
  33. package/dist/camera-projection.d.ts.map +1 -1
  34. package/dist/camera-projection.js +83 -30
  35. package/dist/camera-projection.js.map +1 -1
  36. package/dist/camera-state.d.ts +62 -0
  37. package/dist/camera-state.d.ts.map +1 -0
  38. package/dist/camera-state.js +5 -0
  39. package/dist/camera-state.js.map +1 -0
  40. package/dist/camera.d.ts +22 -11
  41. package/dist/camera.d.ts.map +1 -1
  42. package/dist/camera.js +110 -85
  43. package/dist/camera.js.map +1 -1
  44. package/dist/deviation/deviation-pipeline.d.ts.map +1 -1
  45. package/dist/deviation/deviation-pipeline.js +21 -4
  46. package/dist/deviation/deviation-pipeline.js.map +1 -1
  47. package/dist/environment.d.ts.map +1 -1
  48. package/dist/environment.js +23 -1
  49. package/dist/environment.js.map +1 -1
  50. package/dist/index.d.ts +333 -43
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +753 -704
  53. package/dist/index.js.map +1 -1
  54. package/dist/math.d.ts +59 -2
  55. package/dist/math.d.ts.map +1 -1
  56. package/dist/math.js +173 -23
  57. package/dist/math.js.map +1 -1
  58. package/dist/model-bounds-tracker.d.ts +96 -0
  59. package/dist/model-bounds-tracker.d.ts.map +1 -0
  60. package/dist/model-bounds-tracker.js +147 -0
  61. package/dist/model-bounds-tracker.js.map +1 -0
  62. package/dist/pointcloud/point-cloud-node.d.ts.map +1 -1
  63. package/dist/pointcloud/point-cloud-node.js +24 -4
  64. package/dist/pointcloud/point-cloud-node.js.map +1 -1
  65. package/dist/render-degradation.d.ts +77 -0
  66. package/dist/render-degradation.d.ts.map +1 -0
  67. package/dist/render-degradation.js +52 -0
  68. package/dist/render-degradation.js.map +1 -0
  69. package/dist/render-section-draw.d.ts +51 -0
  70. package/dist/render-section-draw.d.ts.map +1 -0
  71. package/dist/render-section-draw.js +66 -0
  72. package/dist/render-section-draw.js.map +1 -0
  73. package/dist/render-section-plane.d.ts +128 -0
  74. package/dist/render-section-plane.d.ts.map +1 -0
  75. package/dist/render-section-plane.js +298 -0
  76. package/dist/render-section-plane.js.map +1 -0
  77. package/dist/renderer-overlays.d.ts +144 -0
  78. package/dist/renderer-overlays.d.ts.map +1 -0
  79. package/dist/renderer-overlays.js +257 -0
  80. package/dist/renderer-overlays.js.map +1 -0
  81. package/dist/renderer-symbolic-overlays.d.ts +52 -0
  82. package/dist/renderer-symbolic-overlays.d.ts.map +1 -0
  83. package/dist/renderer-symbolic-overlays.js +115 -0
  84. package/dist/renderer-symbolic-overlays.js.map +1 -0
  85. package/dist/scene-geometry.d.ts +32 -0
  86. package/dist/scene-geometry.d.ts.map +1 -1
  87. package/dist/scene-geometry.js +66 -0
  88. package/dist/scene-geometry.js.map +1 -1
  89. package/dist/scene.d.ts +86 -1
  90. package/dist/scene.d.ts.map +1 -1
  91. package/dist/scene.js +391 -201
  92. package/dist/scene.js.map +1 -1
  93. package/dist/section-2d-lift.d.ts +105 -0
  94. package/dist/section-2d-lift.d.ts.map +1 -0
  95. package/dist/section-2d-lift.js +162 -0
  96. package/dist/section-2d-lift.js.map +1 -0
  97. package/dist/section-2d-line-buffer.d.ts +58 -0
  98. package/dist/section-2d-line-buffer.d.ts.map +1 -0
  99. package/dist/section-2d-line-buffer.js +109 -0
  100. package/dist/section-2d-line-buffer.js.map +1 -0
  101. package/dist/section-2d-overlay.d.ts +43 -75
  102. package/dist/section-2d-overlay.d.ts.map +1 -1
  103. package/dist/section-2d-overlay.js +189 -559
  104. package/dist/section-2d-overlay.js.map +1 -1
  105. package/dist/section-plane-basis.d.ts +22 -3
  106. package/dist/section-plane-basis.d.ts.map +1 -1
  107. package/dist/section-plane-basis.js +51 -10
  108. package/dist/section-plane-basis.js.map +1 -1
  109. package/dist/section-plane.d.ts.map +1 -1
  110. package/dist/section-plane.js +10 -1
  111. package/dist/section-plane.js.map +1 -1
  112. package/dist/shaders/section-2d-overlay.wgsl.d.ts +102 -0
  113. package/dist/shaders/section-2d-overlay.wgsl.d.ts.map +1 -0
  114. package/dist/shaders/section-2d-overlay.wgsl.js +281 -0
  115. package/dist/shaders/section-2d-overlay.wgsl.js.map +1 -0
  116. package/dist/visual-enhancement.d.ts +33 -0
  117. package/dist/visual-enhancement.d.ts.map +1 -0
  118. package/dist/visual-enhancement.js +46 -0
  119. package/dist/visual-enhancement.js.map +1 -0
  120. package/package.json +4 -3
@@ -0,0 +1,105 @@
1
+ /** Semantic cardinal section axis: down (Y), front (Z), side (X). */
2
+ export type SectionAxis = 'down' | 'front' | 'side';
3
+ /**
4
+ * Arbitrary (face-picked) section plane, issue #243. The same basis is used by
5
+ * `SectionCutter` to project triangle-plane intersections to 2D, so the
6
+ * round-trip through {@link createSectionLift} is exact.
7
+ */
8
+ export interface SectionCustomPlane {
9
+ origin: [number, number, number];
10
+ tangent: [number, number, number];
11
+ bitangent: [number, number, number];
12
+ }
13
+ export interface CutPolygon2D {
14
+ polygon: {
15
+ outer: Array<{
16
+ x: number;
17
+ y: number;
18
+ }>;
19
+ holes: Array<Array<{
20
+ x: number;
21
+ y: number;
22
+ }>>;
23
+ };
24
+ ifcType: string;
25
+ expressId: number;
26
+ /** Optional per-polygon RGBA (0–1). When present, this cap polygon fills with
27
+ * this colour (an `IfcMaterialLayerSet` wall/slab layer, or a frame+glass
28
+ * window part) instead of the uniform cap fill. Absent ⇒ uniform cap style +
29
+ * per-`ifcType` fallback, unchanged. */
30
+ color?: [number, number, number, number];
31
+ }
32
+ export interface DrawingLine2D {
33
+ line: {
34
+ start: {
35
+ x: number;
36
+ y: number;
37
+ };
38
+ end: {
39
+ x: number;
40
+ y: number;
41
+ };
42
+ };
43
+ category: string;
44
+ /**
45
+ * Express ID of the entity that authored this segment. Optional — only the
46
+ * IfcAnnotation / IfcGridAxis symbolic overlay sets it (so per-entity hide
47
+ * can drop an annotation's curves without a mesh). The section-cut and
48
+ * drawing-2d cutters leave it undefined.
49
+ */
50
+ ownerId?: number;
51
+ }
52
+ /** A 2D drawing point lifted onto the section plane in world space. */
53
+ export type SectionLift = (x2d: number, y2d: number) => [number, number, number];
54
+ /**
55
+ * Transform 2D coordinates to 3D coordinates on the section plane.
56
+ *
57
+ * Cardinal axis path (legacy, unchanged):
58
+ * - Y axis (down): 2D (x, y) = 3D (x, z) - looking down at XZ plane
59
+ * - Z axis (front): 2D (x, y) = 3D (x, y) - looking along Z at XY plane
60
+ * - X axis (side): 2D (x, y) = 3D (z, y) - looking along X at ZY plane
61
+ * When flipped, the 2D x coordinate is negated.
62
+ *
63
+ * Custom-plane path (issue #243): when `customPlane` is supplied, the
64
+ * 3D point is `origin + tangent*x2d + bitangent*y2d`. The same basis
65
+ * is used by `SectionCutter` to project triangle-plane intersections
66
+ * to 2D, so the round-trip is exact and the cap polygons land
67
+ * precisely on the user's tilted plane.
68
+ */
69
+ export declare function transform2Dto3D(x2d: number, y2d: number, axis: SectionAxis, planePosition: number, flipped?: boolean, customPlane?: SectionCustomPlane): [number, number, number];
70
+ /**
71
+ * Bind a lift ONCE per upload rather than re-resolving the axis/custom-plane
72
+ * branch per vertex. `uploadDrawing` runs over every cut polygon on each
73
+ * section-slider commit, so the branch is hoisted out of the inner loop; the
74
+ * returned closure allocates exactly the same one tuple per point that
75
+ * {@link transform2Dto3D} does.
76
+ */
77
+ export declare function createSectionLift(axis: SectionAxis, planePosition: number, flipped?: boolean, customPlane?: SectionCustomPlane): SectionLift;
78
+ /** Interleaved `[x, y, z, r, g, b, a]` cap vertices plus their triangle indices. */
79
+ export interface CapFillGeometry {
80
+ vertices: Float32Array;
81
+ indices: Uint32Array;
82
+ }
83
+ /**
84
+ * Triangulate the cut polygons and lift them onto the section plane.
85
+ *
86
+ * Hole-aware ear-clipping (reused from the IfcAnnotationFillArea fill path)
87
+ * replaces the old convex fan. The fan ignored holes and inverted on the
88
+ * CONCAVE cross-sections that arbitrary IFC profiles (and material-layer
89
+ * slabs) cut into, leaving the cut face uncovered — it read as a hollow
90
+ * shell. Section 2D points are (x, y); the triangulator works in (x, z),
91
+ * so y maps to z.
92
+ *
93
+ * Returns `null` when nothing survives (no polygon had three usable points),
94
+ * so the caller can skip buffer creation entirely.
95
+ */
96
+ export declare function buildCapFillGeometry(polygons: readonly CutPolygon2D[], lift: SectionLift): CapFillGeometry | null;
97
+ /**
98
+ * Enumerate the cut outline as a line-list: every polygon's outer ring, every
99
+ * hole ring, then the extra drawing lines (hatching etc.), each lifted onto the
100
+ * section plane. Rings close back onto their first point.
101
+ *
102
+ * Returns `null` when there is nothing to draw.
103
+ */
104
+ export declare function buildDrawingOutlineVertices(polygons: readonly CutPolygon2D[], lines: readonly DrawingLine2D[], lift: SectionLift): Float32Array | null;
105
+ //# sourceMappingURL=section-2d-lift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-2d-lift.d.ts","sourceRoot":"","sources":["../src/section-2d-lift.ts"],"names":[],"mappings":"AAkBA,qEAAqE;AACrE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE;QACP,KAAK,EAAE,KAAK,CAAC;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACvC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC,CAAC;KAC/C,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB;;;6CAGyC;IACzC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE;QACJ,KAAK,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAChC,GAAG,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/B,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,OAAe,EACxB,WAAW,CAAC,EAAE,kBAAkB,GAC/B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CA8B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,OAAe,EACxB,WAAW,CAAC,EAAE,kBAAkB,GAC/B,WAAW,CAEb;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,IAAI,EAAE,WAAW,GAChB,eAAe,GAAG,IAAI,CAwCxB;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,IAAI,EAAE,WAAW,GAChB,YAAY,GAAG,IAAI,CAmCrB"}
@@ -0,0 +1,162 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Section 2D → 3D lift and cap geometry building.
6
+ *
7
+ * Pure array maths, no GPU state: "what shape does the drawing have on the
8
+ * plane". `Section2DOverlayRenderer` owns the buffers and calls in here for the
9
+ * vertex data to put in them, which is why nothing in this file touches a
10
+ * `GPUDevice`. Its failure stories are geometric (the cap lands off a tilted
11
+ * plane, a concave cross-section triangulates inside-out, holes are not
12
+ * stitched, a flipped axis is mirrored the wrong way) and are all testable with
13
+ * plain numbers.
14
+ */
15
+ import { earClip, joinHoles } from './symbolic-overlay-pipelines.js';
16
+ /**
17
+ * Transform 2D coordinates to 3D coordinates on the section plane.
18
+ *
19
+ * Cardinal axis path (legacy, unchanged):
20
+ * - Y axis (down): 2D (x, y) = 3D (x, z) - looking down at XZ plane
21
+ * - Z axis (front): 2D (x, y) = 3D (x, y) - looking along Z at XY plane
22
+ * - X axis (side): 2D (x, y) = 3D (z, y) - looking along X at ZY plane
23
+ * When flipped, the 2D x coordinate is negated.
24
+ *
25
+ * Custom-plane path (issue #243): when `customPlane` is supplied, the
26
+ * 3D point is `origin + tangent*x2d + bitangent*y2d`. The same basis
27
+ * is used by `SectionCutter` to project triangle-plane intersections
28
+ * to 2D, so the round-trip is exact and the cap polygons land
29
+ * precisely on the user's tilted plane.
30
+ */
31
+ export function transform2Dto3D(x2d, y2d, axis, planePosition, flipped = false, customPlane) {
32
+ if (customPlane) {
33
+ // Custom plane: bypass the cardinal-axis swap. `flipped` is
34
+ // intentionally ignored because for arbitrary planes the cutter
35
+ // does not mirror its 2D output (mirroring only makes sense for
36
+ // cardinal projections that have a consistent "view direction").
37
+ const o = customPlane.origin;
38
+ const t = customPlane.tangent;
39
+ const b = customPlane.bitangent;
40
+ return [
41
+ o[0] + t[0] * x2d + b[0] * y2d,
42
+ o[1] + t[1] * x2d + b[1] * y2d,
43
+ o[2] + t[2] * x2d + b[2] * y2d,
44
+ ];
45
+ }
46
+ // Handle flipped - the 2D x coordinate was negated during projection
47
+ const x = flipped ? -x2d : x2d;
48
+ switch (axis) {
49
+ case 'down': // Y axis - horizontal cut (floor plan)
50
+ // 2D.x = 3D.x, 2D.y = 3D.z -> 3D (x, planeY, y)
51
+ return [x, planePosition, y2d];
52
+ case 'front': // Z axis - vertical cut (section view)
53
+ // 2D.x = 3D.x, 2D.y = 3D.y -> 3D (x, y, planeZ)
54
+ return [x, y2d, planePosition];
55
+ case 'side': // X axis - vertical cut (side elevation)
56
+ // 2D.x = 3D.z, 2D.y = 3D.y -> 3D (planeX, y, x)
57
+ return [planePosition, y2d, x];
58
+ }
59
+ }
60
+ /**
61
+ * Bind a lift ONCE per upload rather than re-resolving the axis/custom-plane
62
+ * branch per vertex. `uploadDrawing` runs over every cut polygon on each
63
+ * section-slider commit, so the branch is hoisted out of the inner loop; the
64
+ * returned closure allocates exactly the same one tuple per point that
65
+ * {@link transform2Dto3D} does.
66
+ */
67
+ export function createSectionLift(axis, planePosition, flipped = false, customPlane) {
68
+ return (x2d, y2d) => transform2Dto3D(x2d, y2d, axis, planePosition, flipped, customPlane);
69
+ }
70
+ /**
71
+ * Triangulate the cut polygons and lift them onto the section plane.
72
+ *
73
+ * Hole-aware ear-clipping (reused from the IfcAnnotationFillArea fill path)
74
+ * replaces the old convex fan. The fan ignored holes and inverted on the
75
+ * CONCAVE cross-sections that arbitrary IFC profiles (and material-layer
76
+ * slabs) cut into, leaving the cut face uncovered — it read as a hollow
77
+ * shell. Section 2D points are (x, y); the triangulator works in (x, z),
78
+ * so y maps to z.
79
+ *
80
+ * Returns `null` when nothing survives (no polygon had three usable points),
81
+ * so the caller can skip buffer creation entirely.
82
+ */
83
+ export function buildCapFillGeometry(polygons, lift) {
84
+ const fillVertices = [];
85
+ const fillIndices = [];
86
+ let vertexOffset = 0;
87
+ for (const polygon of polygons) {
88
+ const outer = polygon.polygon.outer;
89
+ if (outer.length < 3)
90
+ continue;
91
+ // Per-polygon fill colour. A material-layer wall/slab delivers one polygon
92
+ // per layer, each carrying its IfcMaterial RGBA (window frame/glass parts
93
+ // likewise). Polygons WITHOUT a colour use the sentinel alpha −1 so the
94
+ // fill shader falls back to the uniform cap style (architectural fill +
95
+ // hatch) byte-identically — see fs_main.
96
+ const color = polygon.color ?? [0, 0, 0, -1];
97
+ const outerRing = outer.map((p) => ({ x: p.x, z: p.y }));
98
+ const holeRings = polygon.polygon.holes
99
+ .filter((h) => h.length >= 3)
100
+ .map((h) => h.map((p) => ({ x: p.x, z: p.y })));
101
+ const stitched = holeRings.length > 0 ? joinHoles(outerRing, holeRings) : outerRing;
102
+ const tris = earClip(stitched);
103
+ if (tris.length === 0)
104
+ continue;
105
+ const baseVertex = vertexOffset;
106
+ for (const pt of stitched) {
107
+ const [x3d, y3d, z3d] = lift(pt.x, pt.z);
108
+ fillVertices.push(x3d, y3d, z3d, color[0], color[1], color[2], color[3]);
109
+ vertexOffset++;
110
+ }
111
+ for (const [a, b, c] of tris) {
112
+ fillIndices.push(baseVertex + a, baseVertex + b, baseVertex + c);
113
+ }
114
+ }
115
+ if (fillVertices.length === 0)
116
+ return null;
117
+ return {
118
+ vertices: new Float32Array(fillVertices),
119
+ indices: new Uint32Array(fillIndices),
120
+ };
121
+ }
122
+ /**
123
+ * Enumerate the cut outline as a line-list: every polygon's outer ring, every
124
+ * hole ring, then the extra drawing lines (hatching etc.), each lifted onto the
125
+ * section plane. Rings close back onto their first point.
126
+ *
127
+ * Returns `null` when there is nothing to draw.
128
+ */
129
+ export function buildDrawingOutlineVertices(polygons, lines, lift) {
130
+ const lineVertices = [];
131
+ // Polygon outlines
132
+ for (const polygon of polygons) {
133
+ const outer = polygon.polygon.outer;
134
+ for (let i = 0; i < outer.length; i++) {
135
+ const p1 = outer[i];
136
+ const p2 = outer[(i + 1) % outer.length];
137
+ const [x1, y1, z1] = lift(p1.x, p1.y);
138
+ const [x2, y2, z2] = lift(p2.x, p2.y);
139
+ lineVertices.push(x1, y1, z1, x2, y2, z2);
140
+ }
141
+ // Hole outlines
142
+ for (const hole of polygon.polygon.holes) {
143
+ for (let i = 0; i < hole.length; i++) {
144
+ const p1 = hole[i];
145
+ const p2 = hole[(i + 1) % hole.length];
146
+ const [x1, y1, z1] = lift(p1.x, p1.y);
147
+ const [x2, y2, z2] = lift(p2.x, p2.y);
148
+ lineVertices.push(x1, y1, z1, x2, y2, z2);
149
+ }
150
+ }
151
+ }
152
+ // Additional drawing lines (hatching, etc.)
153
+ for (const line of lines) {
154
+ const [x1, y1, z1] = lift(line.line.start.x, line.line.start.y);
155
+ const [x2, y2, z2] = lift(line.line.end.x, line.line.end.y);
156
+ lineVertices.push(x1, y1, z1, x2, y2, z2);
157
+ }
158
+ if (lineVertices.length === 0)
159
+ return null;
160
+ return new Float32Array(lineVertices);
161
+ }
162
+ //# sourceMappingURL=section-2d-lift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-2d-lift.js","sourceRoot":"","sources":["../src/section-2d-lift.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,MAAM,iCAAiC,CAAC;AAgD9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAW,EACX,GAAW,EACX,IAAiB,EACjB,aAAqB,EACrB,UAAmB,KAAK,EACxB,WAAgC;IAEhC,IAAI,WAAW,EAAE,CAAC;QAChB,4DAA4D;QAC5D,gEAAgE;QAChE,gEAAgE;QAChE,iEAAiE;QACjE,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC;QAC7B,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC;QAC9B,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC;QAChC,OAAO;YACL,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;YAC9B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;YAC9B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;SAC/B,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE/B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM,EAAE,uCAAuC;YAClD,gDAAgD;YAChD,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;QACjC,KAAK,OAAO,EAAE,uCAAuC;YACnD,gDAAgD;YAChD,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;QACjC,KAAK,MAAM,EAAE,yCAAyC;YACpD,gDAAgD;YAChD,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAiB,EACjB,aAAqB,EACrB,UAAmB,KAAK,EACxB,WAAgC;IAEhC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAC5F,CAAC;AAQD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAiC,EACjC,IAAiB;IAEjB,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAE/B,2EAA2E;QAC3E,0EAA0E;QAC1E,wEAAwE;QACxE,wEAAwE;QACxE,yCAAyC;QACzC,MAAM,KAAK,GAAqC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/E,MAAM,SAAS,GAAS,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAW,OAAO,CAAC,OAAO,CAAC,KAAK;aAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACpF,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEhC,MAAM,UAAU,GAAG,YAAY,CAAC;QAChC,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACzC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,YAAY,EAAE,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,WAAW,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO;QACL,QAAQ,EAAE,IAAI,YAAY,CAAC,YAAY,CAAC;QACxC,OAAO,EAAE,IAAI,WAAW,CAAC,WAAW,CAAC;KACtC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAiC,EACjC,KAA+B,EAC/B,IAAiB;IAEjB,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,mBAAmB;IACnB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACtC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,gBAAgB;QAChB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBACnB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;gBACtC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;gBACtC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,4CAA4C;IAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5D,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,58 @@
1
+ /** Shared GPU resources a {@link WorldLineBuffer} borrows for the duration of a draw. */
2
+ export interface SectionLinePipelineResources {
3
+ device: GPUDevice;
4
+ pipeline: GPURenderPipeline;
5
+ bindGroup: GPUBindGroup;
6
+ uniformBuffer: GPUBuffer;
7
+ /** Byte stride between the uniform slots in `uniformBuffer`. */
8
+ uniformStride: number;
9
+ }
10
+ export declare class WorldLineBuffer {
11
+ private readonly uniformSlot;
12
+ private buffer;
13
+ private count;
14
+ /**
15
+ * @param uniformSlot Index of this family's record in the shared uniform
16
+ * buffer. Every family needs its own: the six overlay draws are encoded
17
+ * into one pass and `queue.writeBuffer` lands before the pass runs, so a
18
+ * shared record means the last family's colour is the one all six get.
19
+ * See `SECTION_2D_UNIFORM_SLOT_INDEX`.
20
+ */
21
+ constructor(uniformSlot: number);
22
+ /**
23
+ * Replace the buffer's contents with a flat `[x,y,z, x,y,z, …]` line-list in
24
+ * world space. Anything shorter than one full segment clears instead, which
25
+ * is how every caller passes "no lines".
26
+ *
27
+ * Only **whole** segments are uploaded. The vertex count went straight to
28
+ * `pass.draw()` as `vertices.length / 3`, so a length that was not a multiple
29
+ * of 3 produced a *fractional* vertex count — a WebGPU validation error that
30
+ * kills the whole command buffer, taking every other overlay in the pass down
31
+ * with it — and an odd whole vertex count left a dangling half-segment the
32
+ * line-list topology would discard anyway. Both are reachable: these arrays
33
+ * are assembled by upstream polyline/arc flatteners, not written by hand.
34
+ *
35
+ * Truncating rather than rejecting the whole array is deliberate. One stray
36
+ * float from a flattener should cost the caller the incomplete tail segment,
37
+ * not the entire grid / DXF / annotation layer.
38
+ */
39
+ upload(device: GPUDevice, vertices: Float32Array): void;
40
+ /** Destroy the buffer and reset the count. Safe to call repeatedly. */
41
+ clear(): void;
42
+ has(): boolean;
43
+ /** Vertex count, for tests and for the caller's own bookkeeping. */
44
+ get vertexCount(): number;
45
+ /**
46
+ * Draw the buffer in `color`. `planeOffset` is left zeroed — these vertices
47
+ * are already in world space, so unlike the section-cut outline they do not
48
+ * ride the section plane.
49
+ *
50
+ * Writes into — and binds — **this family's own** uniform slot. Sharing one
51
+ * record across the pass's six draws meant the last write before submit was
52
+ * what every draw read.
53
+ *
54
+ * No-ops when the buffer is empty, so callers do not need their own guard.
55
+ */
56
+ draw(pass: GPURenderPassEncoder, resources: SectionLinePipelineResources, viewProj: Float32Array, color: readonly [number, number, number, number]): void;
57
+ }
58
+ //# sourceMappingURL=section-2d-line-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-2d-line-buffer.d.ts","sourceRoot":"","sources":["../src/section-2d-line-buffer.ts"],"names":[],"mappings":"AA2BA,yFAAyF;AACzF,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC;IACxB,aAAa,EAAE,SAAS,CAAC;IACzB,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;CACvB;AAKD,qBAAa,eAAe;IAWd,OAAO,CAAC,QAAQ,CAAC,WAAW;IAVxC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,KAAK,CAAK;IAElB;;;;;;OAMG;gBAC0B,WAAW,EAAE,MAAM;IAEhD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAcvD,uEAAuE;IACvE,KAAK,IAAI,IAAI;IAQb,GAAG,IAAI,OAAO;IAId,oEAAoE;IACpE,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;;;;;;;;;OAUG;IACH,IAAI,CACF,IAAI,EAAE,oBAAoB,EAC1B,SAAS,EAAE,4BAA4B,EACvC,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC/C,IAAI;CAeR"}
@@ -0,0 +1,109 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * One world-space line-list vertex buffer.
6
+ *
7
+ * `Section2DOverlayRenderer` backs five standalone line overlays (annotation
8
+ * #653, alignment, grid #967, DXF #2043, clash box #1277) that are byte-for-byte
9
+ * identical apart from which buffer they read and which colour they draw in.
10
+ * This is the ONLY thing those families genuinely own on their own: a vertex
11
+ * buffer and its vertex count.
12
+ *
13
+ * Deliberately NOT an owner of anything shared. The line pipeline, the
14
+ * bind-group layout, the bind group and the 160-byte uniform buffer stay owned
15
+ * solely by `Section2DOverlayRenderer` and are handed in per draw as
16
+ * {@link SectionLinePipelineResources}. That keeps the renderer's single
17
+ * `init()`/`dispose()` lifecycle the one place those resources are created and
18
+ * destroyed — giving each family its own pipeline handle is the split that
19
+ * would put one GPU object under six owners (issue #2456).
20
+ */
21
+ import { SECTION_2D_UNIFORM_FLOATS, SECTION_2D_UNIFORM_SLOTS, } from './shaders/section-2d-overlay.wgsl.js';
22
+ /** Minimum floats for one line segment: two 3-float vertices. */
23
+ const FLOATS_PER_SEGMENT = 6;
24
+ export class WorldLineBuffer {
25
+ uniformSlot;
26
+ buffer = null;
27
+ count = 0;
28
+ /**
29
+ * @param uniformSlot Index of this family's record in the shared uniform
30
+ * buffer. Every family needs its own: the six overlay draws are encoded
31
+ * into one pass and `queue.writeBuffer` lands before the pass runs, so a
32
+ * shared record means the last family's colour is the one all six get.
33
+ * See `SECTION_2D_UNIFORM_SLOT_INDEX`.
34
+ */
35
+ constructor(uniformSlot) {
36
+ this.uniformSlot = uniformSlot;
37
+ }
38
+ /**
39
+ * Replace the buffer's contents with a flat `[x,y,z, x,y,z, …]` line-list in
40
+ * world space. Anything shorter than one full segment clears instead, which
41
+ * is how every caller passes "no lines".
42
+ *
43
+ * Only **whole** segments are uploaded. The vertex count went straight to
44
+ * `pass.draw()` as `vertices.length / 3`, so a length that was not a multiple
45
+ * of 3 produced a *fractional* vertex count — a WebGPU validation error that
46
+ * kills the whole command buffer, taking every other overlay in the pass down
47
+ * with it — and an odd whole vertex count left a dangling half-segment the
48
+ * line-list topology would discard anyway. Both are reachable: these arrays
49
+ * are assembled by upstream polyline/arc flatteners, not written by hand.
50
+ *
51
+ * Truncating rather than rejecting the whole array is deliberate. One stray
52
+ * float from a flattener should cost the caller the incomplete tail segment,
53
+ * not the entire grid / DXF / annotation layer.
54
+ */
55
+ upload(device, vertices) {
56
+ this.clear();
57
+ const usableFloats = Math.floor(vertices.length / FLOATS_PER_SEGMENT) * FLOATS_PER_SEGMENT;
58
+ if (usableFloats === 0)
59
+ return;
60
+ const data = usableFloats === vertices.length ? vertices : vertices.subarray(0, usableFloats);
61
+ this.buffer = device.createBuffer({
62
+ size: data.byteLength,
63
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
64
+ });
65
+ device.queue.writeBuffer(this.buffer, 0, data);
66
+ this.count = usableFloats / 3;
67
+ }
68
+ /** Destroy the buffer and reset the count. Safe to call repeatedly. */
69
+ clear() {
70
+ if (this.buffer) {
71
+ this.buffer.destroy();
72
+ this.buffer = null;
73
+ }
74
+ this.count = 0;
75
+ }
76
+ has() {
77
+ return this.count > 0;
78
+ }
79
+ /** Vertex count, for tests and for the caller's own bookkeeping. */
80
+ get vertexCount() {
81
+ return this.count;
82
+ }
83
+ /**
84
+ * Draw the buffer in `color`. `planeOffset` is left zeroed — these vertices
85
+ * are already in world space, so unlike the section-cut outline they do not
86
+ * ride the section plane.
87
+ *
88
+ * Writes into — and binds — **this family's own** uniform slot. Sharing one
89
+ * record across the pass's six draws meant the last write before submit was
90
+ * what every draw read.
91
+ *
92
+ * No-ops when the buffer is empty, so callers do not need their own guard.
93
+ */
94
+ draw(pass, resources, viewProj, color) {
95
+ if (!this.buffer || this.count === 0)
96
+ return;
97
+ const byteOffset = this.uniformSlot * resources.uniformStride;
98
+ const uniforms = new Float32Array(SECTION_2D_UNIFORM_FLOATS);
99
+ uniforms.set(viewProj, SECTION_2D_UNIFORM_SLOTS.viewProj);
100
+ // planeOffset stays 0 — vertices are already in world space.
101
+ uniforms.set(color, SECTION_2D_UNIFORM_SLOTS.lineColor);
102
+ resources.device.queue.writeBuffer(resources.uniformBuffer, byteOffset, uniforms);
103
+ pass.setPipeline(resources.pipeline);
104
+ pass.setBindGroup(0, resources.bindGroup, [byteOffset]);
105
+ pass.setVertexBuffer(0, this.buffer);
106
+ pass.draw(this.count);
107
+ }
108
+ }
109
+ //# sourceMappingURL=section-2d-line-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-2d-line-buffer.js","sourceRoot":"","sources":["../src/section-2d-line-buffer.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAY9C,iEAAiE;AACjE,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAE7B,MAAM,OAAO,eAAe;IAWG;IAVrB,MAAM,GAAqB,IAAI,CAAC;IAChC,KAAK,GAAG,CAAC,CAAC;IAElB;;;;;;OAMG;IACH,YAA6B,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;IAAG,CAAC;IAEpD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,MAAiB,EAAE,QAAsB;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;QAC3F,IAAI,YAAY,KAAK,CAAC;YAAE,OAAO;QAE/B,MAAM,IAAI,GAAG,YAAY,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAC9F,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,UAAU;YACrB,KAAK,EAAE,cAAc,CAAC,MAAM,GAAG,cAAc,CAAC,QAAQ;SACvD,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG,YAAY,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,uEAAuE;IACvE,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,oEAAoE;IACpE,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;;;;;;;;OAUG;IACH,IAAI,CACF,IAA0B,EAC1B,SAAuC,EACvC,QAAsB,EACtB,KAAgD;QAEhD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO;QAE7C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,aAAa,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,yBAAyB,CAAC,CAAC;QAC7D,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;QAC1D,6DAA6D;QAC7D,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC;QACxD,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;CACF"}
@@ -1,3 +1,5 @@
1
+ import { type CutPolygon2D, type DrawingLine2D, type SectionAxis, type SectionCustomPlane } from './section-2d-lift.js';
2
+ export type { CutPolygon2D, DrawingLine2D, SectionCustomPlane } from './section-2d-lift.js';
1
3
  export interface Section2DOverlayCapStyle {
2
4
  fillColor: [number, number, number, number];
3
5
  strokeColor: [number, number, number, number];
@@ -40,45 +42,6 @@ export interface Section2DOverlayOptions {
40
42
  */
41
43
  showOutlines?: boolean;
42
44
  }
43
- export interface CutPolygon2D {
44
- polygon: {
45
- outer: Array<{
46
- x: number;
47
- y: number;
48
- }>;
49
- holes: Array<Array<{
50
- x: number;
51
- y: number;
52
- }>>;
53
- };
54
- ifcType: string;
55
- expressId: number;
56
- /** Optional per-polygon RGBA (0–1). When present, this cap polygon fills with
57
- * this colour (an `IfcMaterialLayerSet` wall/slab layer, or a frame+glass
58
- * window part) instead of the uniform cap fill. Absent ⇒ uniform cap style +
59
- * per-`ifcType` fallback, unchanged. */
60
- color?: [number, number, number, number];
61
- }
62
- export interface DrawingLine2D {
63
- line: {
64
- start: {
65
- x: number;
66
- y: number;
67
- };
68
- end: {
69
- x: number;
70
- y: number;
71
- };
72
- };
73
- category: string;
74
- /**
75
- * Express ID of the entity that authored this segment. Optional — only the
76
- * IfcAnnotation / IfcGridAxis symbolic overlay sets it (so per-entity hide
77
- * can drop an annotation's curves without a mesh). The section-cut and
78
- * drawing-2d cutters leave it undefined.
79
- */
80
- ownerId?: number;
81
- }
82
45
  export declare class Section2DOverlayRenderer {
83
46
  private device;
84
47
  private fillPipeline;
@@ -86,6 +49,8 @@ export declare class Section2DOverlayRenderer {
86
49
  private bindGroupLayout;
87
50
  private uniformBuffer;
88
51
  private bindGroup;
52
+ /** Byte stride between the uniform slots in {@link uniformBuffer}. Set by `init()`. */
53
+ private uniformStride;
89
54
  private format;
90
55
  private sampleCount;
91
56
  private initialized;
@@ -95,33 +60,20 @@ export declare class Section2DOverlayRenderer {
95
60
  private fillIndexCount;
96
61
  private lineVertexBuffer;
97
62
  private lineVertexCount;
98
- private annotationLineVertexBuffer;
99
- private annotationLineVertexCount;
100
- private alignmentLineVertexBuffer;
101
- private alignmentLineVertexCount;
102
- private gridLineVertexBuffer;
103
- private gridLineVertexCount;
104
- private clashBoxLineVertexBuffer;
105
- private clashBoxLineVertexCount;
63
+ private annotationLines;
64
+ private alignmentLines;
65
+ private gridLines;
66
+ private dxfLines;
67
+ private clashBoxLines;
106
68
  private clashBoxLineColor;
107
69
  constructor(device: GPUDevice, format: GPUTextureFormat, sampleCount?: number);
108
70
  private init;
109
71
  /**
110
- * Transform 2D coordinates to 3D coordinates on the section plane.
111
- *
112
- * Cardinal axis path (legacy, unchanged):
113
- * - Y axis (down): 2D (x, y) = 3D (x, z) - looking down at XZ plane
114
- * - Z axis (front): 2D (x, y) = 3D (x, y) - looking along Z at XY plane
115
- * - X axis (side): 2D (x, y) = 3D (z, y) - looking along X at ZY plane
116
- * When flipped, the 2D x coordinate is negated.
117
- *
118
- * Custom-plane path (issue #243): when `customPlane` is supplied, the
119
- * 3D point is `origin + tangent*x2d + bitangent*y2d`. The same basis
120
- * is used by `SectionCutter` to project triangle-plane intersections
121
- * to 2D, so the round-trip is exact and the cap polygons land
122
- * precisely on the user's tilted plane.
72
+ * The shared line-pipeline resources a WorldLineBuffer borrows for a draw.
73
+ * Returns null before `init()` has produced them (or after `dispose()`), so
74
+ * every `draw*Lines3D` bails on the same condition it always did.
123
75
  */
124
- private transform2Dto3D;
76
+ private lineResources;
125
77
  /**
126
78
  * Upload 2D drawing data to GPU buffers.
127
79
  *
@@ -135,11 +87,7 @@ export declare class Section2DOverlayRenderer {
135
87
  * would land off the actual cutting plane (the bug PR #581 hid by
136
88
  * suppressing the cap entirely for non-cardinal planes).
137
89
  */
138
- uploadDrawing(polygons: CutPolygon2D[], lines: DrawingLine2D[], axis: 'down' | 'front' | 'side', planePosition: number, flipped?: boolean, customPlane?: {
139
- origin: [number, number, number];
140
- tangent: [number, number, number];
141
- bitangent: [number, number, number];
142
- }): void;
90
+ uploadDrawing(polygons: CutPolygon2D[], lines: DrawingLine2D[], axis: SectionAxis, planePosition: number, flipped?: boolean, customPlane?: SectionCustomPlane): void;
143
91
  /**
144
92
  * Clear uploaded geometry
145
93
  */
@@ -162,6 +110,14 @@ export declare class Section2DOverlayRenderer {
162
110
  uploadAnnotationLines3D(vertices: Float32Array): void;
163
111
  clearAnnotationLines3D(): void;
164
112
  hasAnnotationLines3D(): boolean;
113
+ /**
114
+ * Draw the standalone annotation line overlay. Uses the same line pipeline
115
+ * as the section cut outlines (vertex format: 3 floats per vertex, line-list
116
+ * topology) but reads from a separate vertex buffer. The pipeline's
117
+ * `planeOffset` uniform is zeroed so vertices render at their authored
118
+ * world position.
119
+ */
120
+ drawAnnotationLines3D(pass: GPURenderPassEncoder, viewProj: Float32Array): void;
165
121
  /**
166
122
  * Upload a flat Float32Array of 3D line-list vertices for the alignment
167
123
  * centerline overlay. Same format/pipeline as the annotation lines, kept in
@@ -171,14 +127,6 @@ export declare class Section2DOverlayRenderer {
171
127
  uploadAlignmentLines3D(vertices: Float32Array): void;
172
128
  clearAlignmentLines3D(): void;
173
129
  hasAlignmentLines3D(): boolean;
174
- /**
175
- * Draw the standalone annotation line overlay. Uses the same line pipeline
176
- * as the section cut outlines (vertex format: 3 floats per vertex, line-list
177
- * topology) but reads from a separate vertex buffer. The pipeline's
178
- * `planeOffset` uniform is zeroed so vertices render at their authored
179
- * world position.
180
- */
181
- drawAnnotationLines3D(pass: GPURenderPassEncoder, viewProj: Float32Array): void;
182
130
  /**
183
131
  * Draw the alignment centerline overlay. Identical pipeline/uniform setup as
184
132
  * `drawAnnotationLines3D`, reading from the separate alignment buffer.
@@ -198,6 +146,21 @@ export declare class Section2DOverlayRenderer {
198
146
  * `drawAlignmentLines3D`, reading from the separate grid buffer.
199
147
  */
200
148
  drawGridLines3D(pass: GPURenderPassEncoder, viewProj: Float32Array): void;
149
+ /**
150
+ * Upload the DXF reference-layer's line paths as a flat `[x,y,z, x,y,z, …]`
151
+ * line-list in world space (issue #2043). Mirrors `uploadGridLines3D` with
152
+ * a separate buffer so 3D DXF visibility is independent of the 2D
153
+ * underlay and the other overlays above. Pass an empty array (or omit)
154
+ * to clear.
155
+ */
156
+ uploadDxfLines3D(vertices: Float32Array): void;
157
+ clearDxfLines3D(): void;
158
+ hasDxfLines3D(): boolean;
159
+ /**
160
+ * Draw the 3D DXF reference-layer overlay. Identical pipeline/uniform
161
+ * setup as `drawGridLines3D`, reading from the separate DXF buffer.
162
+ */
163
+ drawDxfLines3D(pass: GPURenderPassEncoder, viewProj: Float32Array): void;
201
164
  /** Colour for the clash-overlap box (its own, not the shared overlay colour). */
202
165
  setClashBoxLineColor(color: readonly [number, number, number, number]): void;
203
166
  /**
@@ -219,7 +182,12 @@ export declare class Section2DOverlayRenderer {
219
182
  */
220
183
  draw(pass: GPURenderPassEncoder, options: Section2DOverlayOptions): void;
221
184
  /**
222
- * Dispose of GPU resources
185
+ * Dispose of GPU resources.
186
+ *
187
+ * Every family's buffer must be released here. The clash box (#1277) was the
188
+ * sixth family added and was missing from this list, leaking its vertex
189
+ * buffer on every teardown — `section-2d-overlay-lifecycle.test.ts` now counts
190
+ * destroys against uploads so a seventh family cannot repeat it.
223
191
  */
224
192
  dispose(): void;
225
193
  }