@ifc-lite/viewer 1.19.1 → 1.21.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 (106) hide show
  1. package/.turbo/turbo-build.log +59 -44
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +488 -0
  4. package/dist/assets/{basketViewActivator-CA2CTcVo.js → basketViewActivator-Bzw51jhm.js} +6 -6
  5. package/dist/assets/decode-worker-t2EGKAxO.js +1708 -0
  6. package/dist/assets/drawing-2d-Bjy8YPrg.js +257 -0
  7. package/dist/assets/exporters-u0sz2Upj.js +259119 -0
  8. package/dist/assets/geometry-controller.worker-NH8pZmrU.js +7 -0
  9. package/dist/assets/geometry.worker-Bp4rW_R1.js +1 -0
  10. package/dist/assets/ids-B7AXEv7h.js +4067 -0
  11. package/dist/assets/ifc-lite-DfZHk36-.js +7 -0
  12. package/dist/assets/ifc-lite_bg-DlKs5-yM.wasm +0 -0
  13. package/dist/assets/ifc-lite_bg-PqmRe3Ph.wasm +0 -0
  14. package/dist/assets/index-CSWgTe1s.css +1 -0
  15. package/dist/assets/{index-D8Epw-e7.js → index-DVNSvEMh.js} +40146 -35823
  16. package/dist/assets/laz-perf-Cvr_Lepg.js +1 -0
  17. package/dist/assets/laz-perf-DnSyzVYH.wasm +0 -0
  18. package/dist/assets/{native-bridge-DKmx1z95.js → native-bridge-BiD01jI9.js} +1 -1
  19. package/dist/assets/parser.worker-Bnbrl6gy.js +182 -0
  20. package/dist/assets/{sandbox-tccwm5Bo.js → sandbox-DPD1ROr0.js} +4 -4
  21. package/dist/assets/{server-client-LoWPK1N2.js → server-client-DP8fMPY9.js} +1 -1
  22. package/dist/assets/{wasm-bridge-BsJGgPMs.js → wasm-bridge-CErti6zX.js} +1 -1
  23. package/dist/assets/workerHelpers-CBbWSJmd.js +36 -0
  24. package/dist/index.html +8 -8
  25. package/index.html +1 -1
  26. package/package.json +10 -10
  27. package/src/components/viewer/BasketPresentationDock.tsx +3 -0
  28. package/src/components/viewer/CesiumOverlay.tsx +165 -120
  29. package/src/components/viewer/DeviationPanel.tsx +172 -0
  30. package/src/components/viewer/HierarchyPanel.tsx +29 -3
  31. package/src/components/viewer/HoverTooltip.tsx +5 -0
  32. package/src/components/viewer/IDSAuditSummary.tsx +389 -0
  33. package/src/components/viewer/IDSPanel.tsx +80 -26
  34. package/src/components/viewer/MainToolbar.tsx +60 -7
  35. package/src/components/viewer/MergeLayersBanner.tsx +108 -0
  36. package/src/components/viewer/MobileToolbar.tsx +326 -0
  37. package/src/components/viewer/PointCloudClasses.tsx +111 -0
  38. package/src/components/viewer/PointCloudLegend.tsx +119 -0
  39. package/src/components/viewer/PointCloudPanel.tsx +52 -1
  40. package/src/components/viewer/PropertiesPanel.tsx +37 -6
  41. package/src/components/viewer/RectSelectionOverlay.tsx +48 -0
  42. package/src/components/viewer/StatusBar.tsx +14 -0
  43. package/src/components/viewer/ViewerLayout.tsx +288 -95
  44. package/src/components/viewer/Viewport.tsx +86 -18
  45. package/src/components/viewer/ViewportContainer.tsx +25 -11
  46. package/src/components/viewer/ViewportOverlays.tsx +41 -26
  47. package/src/components/viewer/mouseHandlerTypes.ts +22 -0
  48. package/src/components/viewer/properties/GeoreferencingPanel.tsx +77 -8
  49. package/src/components/viewer/properties/MaterialCard.tsx +2 -2
  50. package/src/components/viewer/selectionHandlers.ts +41 -0
  51. package/src/components/viewer/tools/SectionPanel.tsx +181 -24
  52. package/src/components/viewer/tools/SectionVisualization.tsx +384 -3
  53. package/src/components/viewer/useAnimationLoop.ts +22 -0
  54. package/src/components/viewer/useMouseControls.ts +296 -3
  55. package/src/components/viewer/usePointCloudSync.ts +8 -1
  56. package/src/components/viewer/useRenderUpdates.ts +21 -1
  57. package/src/components/viewer/useTouchControls.ts +100 -41
  58. package/src/hooks/federationLoadGate.test.ts +90 -0
  59. package/src/hooks/federationLoadGate.ts +127 -0
  60. package/src/hooks/ids/idsDataAccessor.ts +11 -259
  61. package/src/hooks/ingest/pointCloudIngest.ts +127 -16
  62. package/src/hooks/useDrawingGeneration.ts +81 -8
  63. package/src/hooks/useIDS.ts +90 -10
  64. package/src/hooks/useIfcFederation.ts +94 -16
  65. package/src/hooks/useIfcLoader.ts +289 -64
  66. package/src/hooks/useViewerSelectors.ts +10 -0
  67. package/src/lib/geo/cesium-bridge.ts +84 -67
  68. package/src/lib/geo/clamp-anchor.test.ts +80 -0
  69. package/src/lib/geo/clamp-anchor.ts +57 -0
  70. package/src/lib/geo/effective-georef.test.ts +79 -1
  71. package/src/lib/geo/effective-georef.ts +83 -0
  72. package/src/lib/geo/reproject.ts +26 -13
  73. package/src/lib/geo/terrain-elevation.ts +166 -0
  74. package/src/lib/lens/adapter.ts +1 -1
  75. package/src/lib/llm/context-builder.ts +1 -1
  76. package/src/lib/perf/memoryAccounting.test.ts +92 -0
  77. package/src/lib/perf/memoryAccounting.ts +235 -0
  78. package/src/sdk/adapters/mutation-view.ts +1 -1
  79. package/src/store/constants.ts +39 -2
  80. package/src/store/index.ts +6 -1
  81. package/src/store/slices/cesiumSlice.ts +1 -1
  82. package/src/store/slices/idsSlice.ts +24 -0
  83. package/src/store/slices/loadingSlice.ts +12 -0
  84. package/src/store/slices/pointCloudSlice.ts +72 -1
  85. package/src/store/slices/sectionSlice.test.ts +590 -1
  86. package/src/store/slices/sectionSlice.ts +344 -17
  87. package/src/store/slices/uiSlice.merge-layers.test.ts +217 -0
  88. package/src/store/slices/uiSlice.ts +60 -2
  89. package/src/store/types.ts +42 -0
  90. package/src/store.ts +13 -0
  91. package/src/utils/acquireFileBuffer.test.ts +231 -0
  92. package/src/utils/acquireFileBuffer.ts +128 -0
  93. package/src/utils/ifcConfig.ts +24 -0
  94. package/src/utils/nativeSpatialDataStore.ts +20 -2
  95. package/src/utils/spatialHierarchy.test.ts +116 -0
  96. package/src/utils/spatialHierarchy.ts +23 -0
  97. package/tailwind.config.js +5 -0
  98. package/tsconfig.json +1 -0
  99. package/vite.config.ts +6 -0
  100. package/dist/assets/decode-worker-Collf_X_.js +0 -1320
  101. package/dist/assets/drawing-2d-DoxKMqbO.js +0 -257
  102. package/dist/assets/exporters-xbXqEDlO.js +0 -81590
  103. package/dist/assets/geometry.worker-DQEZB2rB.js +0 -1
  104. package/dist/assets/ids-2WdONLlu.js +0 -2033
  105. package/dist/assets/ifc-lite_bg-4yUkDRD8.wasm +0 -0
  106. package/dist/assets/index-BXeEKqJG.css +0 -1
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { StateCreator } from 'zustand';
12
12
  import type {
13
+ IDSAuditReport,
13
14
  IDSDocument,
14
15
  IDSValidationReport,
15
16
  IDSSpecificationResult,
@@ -40,6 +41,15 @@ export type IDSFilterMode = 'all' | 'failed' | 'passed';
40
41
  export interface IDSSliceState {
41
42
  /** Loaded IDS document */
42
43
  idsDocument: IDSDocument | null;
44
+ /**
45
+ * Audit report for the loaded IDS document itself — flags authoring
46
+ * issues (missing attributes, invalid IFC entity references, regex
47
+ * errors, etc.). Distinct from `idsValidationReport`, which describes
48
+ * how an IFC model conforms to the IDS.
49
+ */
50
+ idsAuditReport: IDSAuditReport | null;
51
+ /** Whether the audit pipeline is currently running. */
52
+ idsAuditing: boolean;
43
53
  /** Validation report after running validation */
44
54
  idsValidationReport: IDSValidationReport | null;
45
55
  /** Currently active specification (for filtering results) */
@@ -71,6 +81,10 @@ export interface IDSSlice extends IDSSliceState {
71
81
  setIdsDocument: (document: IDSDocument | null) => void;
72
82
  clearIdsDocument: () => void;
73
83
 
84
+ // Audit actions
85
+ setIdsAuditReport: (report: IDSAuditReport | null) => void;
86
+ setIdsAuditing: (auditing: boolean) => void;
87
+
74
88
  // Validation actions
75
89
  setIdsValidationReport: (report: IDSValidationReport | null) => void;
76
90
  clearIdsValidationReport: () => void;
@@ -158,6 +172,8 @@ function buildEntityIdSets(
158
172
  export const createIdsSlice: StateCreator<IDSSlice, [], [], IDSSlice> = (set, get) => ({
159
173
  // Initial state
160
174
  idsDocument: null,
175
+ idsAuditReport: null,
176
+ idsAuditing: false,
161
177
  idsValidationReport: null,
162
178
  idsActiveSpecificationId: null,
163
179
  idsActiveEntityId: null,
@@ -175,6 +191,9 @@ export const createIdsSlice: StateCreator<IDSSlice, [], [], IDSSlice> = (set, ge
175
191
  setIdsDocument: (idsDocument) =>
176
192
  set({
177
193
  idsDocument,
194
+ // Loading a new document invalidates any previous audit/validation
195
+ // results — they were tied to a specific document instance.
196
+ idsAuditReport: null,
178
197
  idsValidationReport: null,
179
198
  idsActiveSpecificationId: null,
180
199
  idsActiveEntityId: null,
@@ -186,6 +205,7 @@ export const createIdsSlice: StateCreator<IDSSlice, [], [], IDSSlice> = (set, ge
186
205
  clearIdsDocument: () =>
187
206
  set({
188
207
  idsDocument: null,
208
+ idsAuditReport: null,
189
209
  idsValidationReport: null,
190
210
  idsActiveSpecificationId: null,
191
211
  idsActiveEntityId: null,
@@ -194,6 +214,10 @@ export const createIdsSlice: StateCreator<IDSSlice, [], [], IDSSlice> = (set, ge
194
214
  idsPassedEntityIds: new Set(),
195
215
  }),
196
216
 
217
+ // Audit actions
218
+ setIdsAuditReport: (idsAuditReport) => set({ idsAuditReport }),
219
+ setIdsAuditing: (idsAuditing) => set({ idsAuditing }),
220
+
197
221
  // Validation actions
198
222
  setIdsValidationReport: (report) => {
199
223
  const { failed, passed } = buildEntityIdSets(report);
@@ -16,6 +16,15 @@ export interface LoadingSlice {
16
16
  geometryProgress: { phase: string; percent: number; indeterminate?: boolean } | null;
17
17
  metadataProgress: { phase: string; percent: number; indeterminate?: boolean } | null;
18
18
  error: string | null;
19
+ /**
20
+ * Cancellation hook for an in-flight long-running operation (e.g.
21
+ * streaming a 100M-point scan). UI components can show a Cancel
22
+ * button while this is non-null. The loader hooks register the
23
+ * canceller after starting the stream and clear it on success /
24
+ * error. Kept on the loading slice (not its own slice) since it
25
+ * tracks lifecycle alongside `progress`.
26
+ */
27
+ activeStreamCanceller: (() => void) | null;
19
28
 
20
29
  // Actions
21
30
  setLoading: (loading: boolean) => void;
@@ -24,6 +33,7 @@ export interface LoadingSlice {
24
33
  setGeometryProgress: (progress: { phase: string; percent: number; indeterminate?: boolean } | null) => void;
25
34
  setMetadataProgress: (progress: { phase: string; percent: number; indeterminate?: boolean } | null) => void;
26
35
  setError: (error: string | null) => void;
36
+ setActiveStreamCanceller: (cancel: (() => void) | null) => void;
27
37
  }
28
38
 
29
39
  export const createLoadingSlice: StateCreator<LoadingSlice, [], [], LoadingSlice> = (set) => ({
@@ -34,6 +44,7 @@ export const createLoadingSlice: StateCreator<LoadingSlice, [], [], LoadingSlice
34
44
  geometryProgress: null,
35
45
  metadataProgress: null,
36
46
  error: null,
47
+ activeStreamCanceller: null,
37
48
 
38
49
  // Actions
39
50
  setLoading: (loading) => set({ loading }),
@@ -42,4 +53,5 @@ export const createLoadingSlice: StateCreator<LoadingSlice, [], [], LoadingSlice
42
53
  setGeometryProgress: (geometryProgress) => set({ geometryProgress }),
43
54
  setMetadataProgress: (metadataProgress) => set({ metadataProgress }),
44
55
  setError: (error) => set({ error }),
56
+ setActiveStreamCanceller: (activeStreamCanceller) => set({ activeStreamCanceller }),
45
57
  });
@@ -12,7 +12,7 @@
12
12
 
13
13
  import type { StateCreator } from 'zustand';
14
14
 
15
- export type PointColorModeUi = 'rgb' | 'classification' | 'intensity' | 'height' | 'fixed';
15
+ export type PointColorModeUi = 'rgb' | 'classification' | 'intensity' | 'height' | 'fixed' | 'deviation';
16
16
  export type PointSizeModeUi = 'fixed-px' | 'adaptive-world' | 'attenuated';
17
17
 
18
18
  export interface PointCloudSlice {
@@ -31,6 +31,35 @@ export interface PointCloudSlice {
31
31
  pointCloudEdlEnabled: boolean;
32
32
  /** EDL strength multiplier. 0..3, default 1. */
33
33
  pointCloudEdlStrength: number;
34
+ /**
35
+ * Per-ASPRS-class visibility bitmask (32 bits = covers classes
36
+ * 0..31, the LAS 1.4 standard range). Bit `i` set → class `i`
37
+ * visible. Default `0xFFFFFFFF` (all visible). Only point clouds
38
+ * carry classifications; meshes ignore this.
39
+ */
40
+ pointCloudClassMask: number;
41
+ /**
42
+ * Stride-cull factor for the splat shader. 1 = render every point,
43
+ * N>1 = render every Nth point. Used by the section-plane slider's
44
+ * drag-preview path so dragging over a 100M-point scan stays
45
+ * responsive. Defaults to 1 (full density).
46
+ */
47
+ pointCloudPreviewStride: number;
48
+ /**
49
+ * BIM↔scan deviation heatmap range. `centerOffset` shifts the
50
+ * "white" point off zero (handy when a scan has a global offset
51
+ * from the model); `halfRange` is the metres mapped to ±1 on the
52
+ * blue-white-red ramp. Defaults to (0, 0.05) — ±5cm.
53
+ */
54
+ pointCloudDeviationCenterOffset: number;
55
+ pointCloudDeviationHalfRange: number;
56
+ /**
57
+ * True once `Renderer.computeDeviations` has populated the deviation
58
+ * buffers for the current point cloud + mesh set. UI gates the
59
+ * "Deviation" colour-mode option on this flag so users don't get a
60
+ * confusing all-blue rendering when nothing has been computed.
61
+ */
62
+ pointCloudDeviationComputed: boolean;
34
63
  /**
35
64
  * Best-effort count of point cloud assets currently uploaded to the
36
65
  * renderer. Updated by ingest paths; UI uses it to show/hide the
@@ -45,6 +74,14 @@ export interface PointCloudSlice {
45
74
  setPointCloudRoundShape: (enabled: boolean) => void;
46
75
  setPointCloudEdlEnabled: (enabled: boolean) => void;
47
76
  setPointCloudEdlStrength: (strength: number) => void;
77
+ setPointCloudClassMask: (mask: number) => void;
78
+ /** Toggle a single ASPRS class. `classId` is clamped to 0..31. */
79
+ togglePointCloudClass: (classId: number) => void;
80
+ /** Set the stride-cull factor (1 = full density). */
81
+ setPointCloudPreviewStride: (stride: number) => void;
82
+ setPointCloudDeviationCenterOffset: (m: number) => void;
83
+ setPointCloudDeviationHalfRange: (m: number) => void;
84
+ setPointCloudDeviationComputed: (computed: boolean) => void;
48
85
  setPointCloudAssetCount: (count: number) => void;
49
86
  incrementPointCloudAssetCount: (n?: number) => void;
50
87
  }
@@ -67,6 +104,14 @@ export const POINT_CLOUD_DEFAULTS = {
67
104
  pointCloudRoundShape: true,
68
105
  pointCloudEdlEnabled: true,
69
106
  pointCloudEdlStrength: 1,
107
+ // 0xFFFFFFFF — all 32 classes visible. Stored as `-1 >>> 0` to
108
+ // keep the value as an unsigned 32-bit integer; JS doesn't have
109
+ // a u32 literal type so we round-trip through `>>> 0`.
110
+ pointCloudClassMask: 0xFFFFFFFF,
111
+ pointCloudPreviewStride: 1,
112
+ pointCloudDeviationCenterOffset: 0,
113
+ pointCloudDeviationHalfRange: 0.05,
114
+ pointCloudDeviationComputed: false,
70
115
  pointCloudAssetCount: 0,
71
116
  } as const;
72
117
 
@@ -91,6 +136,32 @@ export const createPointCloudSlice: StateCreator<PointCloudSlice, [], [], PointC
91
136
  setPointCloudEdlStrength: (strength) => set({
92
137
  pointCloudEdlStrength: Number.isFinite(strength) ? Math.max(0, Math.min(3, strength)) : 1,
93
138
  }),
139
+ setPointCloudClassMask: (mask) => set({
140
+ // Coerce through `>>> 0` to keep the stored value as an unsigned
141
+ // 32-bit integer; non-finite / negative inputs reset to "all on".
142
+ pointCloudClassMask: Number.isFinite(mask) ? (mask >>> 0) : 0xFFFFFFFF,
143
+ }),
144
+ togglePointCloudClass: (classId) => set((s) => {
145
+ const c = Math.max(0, Math.min(31, classId | 0));
146
+ const bit = 1 << c;
147
+ // XOR flips the bit; coerce through `>>> 0` so the stored value
148
+ // stays in the unsigned 32-bit range.
149
+ return { pointCloudClassMask: (s.pointCloudClassMask ^ bit) >>> 0 };
150
+ }),
151
+ setPointCloudPreviewStride: (stride) => set({
152
+ pointCloudPreviewStride: Number.isFinite(stride)
153
+ ? Math.max(1, Math.min(256, Math.floor(stride) || 1))
154
+ : 1,
155
+ }),
156
+ setPointCloudDeviationCenterOffset: (m) => set({
157
+ pointCloudDeviationCenterOffset: Number.isFinite(m) ? m : 0,
158
+ }),
159
+ setPointCloudDeviationHalfRange: (m) => set({
160
+ // halfRange must stay strictly positive — a zero or negative value
161
+ // would NaN the GPU ramp's division. Clamp to 0.1 mm minimum.
162
+ pointCloudDeviationHalfRange: Number.isFinite(m) ? Math.max(1e-4, m) : 0.05,
163
+ }),
164
+ setPointCloudDeviationComputed: (computed) => set({ pointCloudDeviationComputed: computed }),
94
165
  setPointCloudAssetCount: (count) => set({
95
166
  pointCloudAssetCount: Number.isFinite(count) ? Math.max(0, count) : 0,
96
167
  }),