@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.
- package/dist/camera-animation.d.ts +20 -32
- package/dist/camera-animation.d.ts.map +1 -1
- package/dist/camera-animation.js +71 -358
- package/dist/camera-animation.js.map +1 -1
- package/dist/camera-controls.d.ts +11 -51
- package/dist/camera-controls.d.ts.map +1 -1
- package/dist/camera-controls.js +140 -12
- package/dist/camera-controls.js.map +1 -1
- package/dist/camera-first-person.d.ts +52 -0
- package/dist/camera-first-person.d.ts.map +1 -0
- package/dist/camera-first-person.js +119 -0
- package/dist/camera-first-person.js.map +1 -0
- package/dist/camera-fit-policy.d.ts.map +1 -1
- package/dist/camera-fit-policy.js +18 -7
- package/dist/camera-fit-policy.js.map +1 -1
- package/dist/camera-framing.d.ts +86 -0
- package/dist/camera-framing.d.ts.map +1 -0
- package/dist/camera-framing.js +230 -0
- package/dist/camera-framing.js.map +1 -0
- package/dist/camera-guards.d.ts +148 -0
- package/dist/camera-guards.d.ts.map +1 -0
- package/dist/camera-guards.js +150 -0
- package/dist/camera-guards.js.map +1 -0
- package/dist/camera-matrices.d.ts +14 -0
- package/dist/camera-matrices.d.ts.map +1 -0
- package/dist/camera-matrices.js +146 -0
- package/dist/camera-matrices.js.map +1 -0
- package/dist/camera-preset-view.d.ts +56 -0
- package/dist/camera-preset-view.d.ts.map +1 -0
- package/dist/camera-preset-view.js +180 -0
- package/dist/camera-preset-view.js.map +1 -0
- package/dist/camera-projection.d.ts +1 -1
- package/dist/camera-projection.d.ts.map +1 -1
- package/dist/camera-projection.js +83 -30
- package/dist/camera-projection.js.map +1 -1
- package/dist/camera-state.d.ts +62 -0
- package/dist/camera-state.d.ts.map +1 -0
- package/dist/camera-state.js +5 -0
- package/dist/camera-state.js.map +1 -0
- package/dist/camera.d.ts +22 -11
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +110 -85
- package/dist/camera.js.map +1 -1
- package/dist/deviation/deviation-pipeline.d.ts.map +1 -1
- package/dist/deviation/deviation-pipeline.js +21 -4
- package/dist/deviation/deviation-pipeline.js.map +1 -1
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +23 -1
- package/dist/environment.js.map +1 -1
- package/dist/index.d.ts +333 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +753 -704
- package/dist/index.js.map +1 -1
- package/dist/math.d.ts +59 -2
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +173 -23
- package/dist/math.js.map +1 -1
- package/dist/model-bounds-tracker.d.ts +96 -0
- package/dist/model-bounds-tracker.d.ts.map +1 -0
- package/dist/model-bounds-tracker.js +147 -0
- package/dist/model-bounds-tracker.js.map +1 -0
- package/dist/pointcloud/point-cloud-node.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-node.js +24 -4
- package/dist/pointcloud/point-cloud-node.js.map +1 -1
- package/dist/render-degradation.d.ts +77 -0
- package/dist/render-degradation.d.ts.map +1 -0
- package/dist/render-degradation.js +52 -0
- package/dist/render-degradation.js.map +1 -0
- package/dist/render-section-draw.d.ts +51 -0
- package/dist/render-section-draw.d.ts.map +1 -0
- package/dist/render-section-draw.js +66 -0
- package/dist/render-section-draw.js.map +1 -0
- package/dist/render-section-plane.d.ts +128 -0
- package/dist/render-section-plane.d.ts.map +1 -0
- package/dist/render-section-plane.js +298 -0
- package/dist/render-section-plane.js.map +1 -0
- package/dist/renderer-overlays.d.ts +144 -0
- package/dist/renderer-overlays.d.ts.map +1 -0
- package/dist/renderer-overlays.js +257 -0
- package/dist/renderer-overlays.js.map +1 -0
- package/dist/renderer-symbolic-overlays.d.ts +52 -0
- package/dist/renderer-symbolic-overlays.d.ts.map +1 -0
- package/dist/renderer-symbolic-overlays.js +115 -0
- package/dist/renderer-symbolic-overlays.js.map +1 -0
- package/dist/scene-geometry.d.ts +32 -0
- package/dist/scene-geometry.d.ts.map +1 -1
- package/dist/scene-geometry.js +66 -0
- package/dist/scene-geometry.js.map +1 -1
- package/dist/scene.d.ts +86 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +391 -201
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-lift.d.ts +105 -0
- package/dist/section-2d-lift.d.ts.map +1 -0
- package/dist/section-2d-lift.js +162 -0
- package/dist/section-2d-lift.js.map +1 -0
- package/dist/section-2d-line-buffer.d.ts +58 -0
- package/dist/section-2d-line-buffer.d.ts.map +1 -0
- package/dist/section-2d-line-buffer.js +109 -0
- package/dist/section-2d-line-buffer.js.map +1 -0
- package/dist/section-2d-overlay.d.ts +43 -75
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +189 -559
- package/dist/section-2d-overlay.js.map +1 -1
- package/dist/section-plane-basis.d.ts +22 -3
- package/dist/section-plane-basis.d.ts.map +1 -1
- package/dist/section-plane-basis.js +51 -10
- package/dist/section-plane-basis.js.map +1 -1
- package/dist/section-plane.d.ts.map +1 -1
- package/dist/section-plane.js +10 -1
- package/dist/section-plane.js.map +1 -1
- package/dist/shaders/section-2d-overlay.wgsl.d.ts +102 -0
- package/dist/shaders/section-2d-overlay.wgsl.d.ts.map +1 -0
- package/dist/shaders/section-2d-overlay.wgsl.js +281 -0
- package/dist/shaders/section-2d-overlay.wgsl.js.map +1 -0
- package/dist/visual-enhancement.d.ts +33 -0
- package/dist/visual-enhancement.d.ts.map +1 -0
- package/dist/visual-enhancement.js +46 -0
- package/dist/visual-enhancement.js.map +1 -0
- 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":"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"}
|
|
@@ -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
|
|
99
|
-
private
|
|
100
|
-
private
|
|
101
|
-
private
|
|
102
|
-
private
|
|
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
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
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
|
|
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:
|
|
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
|
}
|