@ifc-lite/renderer 1.2.0 → 1.3.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.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Renderer constants - extracted magic numbers for maintainability
3
+ */
4
+ export declare const CAMERA_CONSTANTS: {
5
+ /** Inertia damping factor (0-1), higher = more damping */
6
+ readonly DAMPING_FACTOR: 0.92;
7
+ /** Minimum velocity threshold for inertia */
8
+ readonly MIN_VELOCITY_THRESHOLD: 0.001;
9
+ /** First-person movement speed */
10
+ readonly FIRST_PERSON_SPEED: 0.1;
11
+ /** Orbit sensitivity (radians per pixel) */
12
+ readonly ORBIT_SENSITIVITY: 0.01;
13
+ /** Pan speed multiplier */
14
+ readonly PAN_SPEED_MULTIPLIER: 0.001;
15
+ /** Zoom sensitivity */
16
+ readonly ZOOM_SENSITIVITY: 0.001;
17
+ /** Maximum zoom delta per frame */
18
+ readonly MAX_ZOOM_DELTA: 0.1;
19
+ readonly DEFAULT_POSITION: {
20
+ readonly x: 50;
21
+ readonly y: 50;
22
+ readonly z: 100;
23
+ };
24
+ readonly DEFAULT_TARGET: {
25
+ readonly x: 0;
26
+ readonly y: 0;
27
+ readonly z: 0;
28
+ };
29
+ readonly DEFAULT_UP: {
30
+ readonly x: 0;
31
+ readonly y: 1;
32
+ readonly z: 0;
33
+ };
34
+ readonly DEFAULT_FOV: number;
35
+ readonly DEFAULT_NEAR: 0.1;
36
+ readonly DEFAULT_FAR: 100000;
37
+ /** Maximum near/far ratio for depth precision */
38
+ readonly MAX_NEAR_FAR_RATIO: 10000;
39
+ /** Near plane as percentage of distance */
40
+ readonly NEAR_DISTANCE_FACTOR: 0.001;
41
+ /** Far plane multiplier of distance */
42
+ readonly FAR_DISTANCE_MULTIPLIER: 10;
43
+ /** Minimum phi angle to prevent gimbal lock at poles */
44
+ readonly MIN_PHI: 0.15;
45
+ /** Maximum phi angle to prevent gimbal lock at poles */
46
+ readonly MAX_PHI: number;
47
+ /** Sin phi threshold for pole detection */
48
+ readonly POLE_THRESHOLD: 0.05;
49
+ /** Default animation duration in ms */
50
+ readonly DEFAULT_ANIMATION_DURATION: 500;
51
+ /** Quick animation duration in ms */
52
+ readonly QUICK_ANIMATION_DURATION: 300;
53
+ /** Distance multiplier for fitToBounds */
54
+ readonly FIT_DISTANCE_MULTIPLIER: 2;
55
+ /** Padding multiplier for frame selection */
56
+ readonly FRAME_PADDING_MULTIPLIER: 1.2;
57
+ /** Padding multiplier for zoom extent */
58
+ readonly ZOOM_EXTENT_PADDING: 1.5;
59
+ readonly ISOMETRIC_OFFSET: {
60
+ readonly right: 0.6;
61
+ readonly up: 0.5;
62
+ readonly front: 0.6;
63
+ };
64
+ };
65
+ export declare const BVH_CONSTANTS: {
66
+ /** Minimum mesh count to trigger BVH construction */
67
+ readonly THRESHOLD: 100;
68
+ /** Maximum primitives per leaf node */
69
+ readonly MAX_PRIMITIVES_PER_LEAF: 4;
70
+ /** Maximum tree depth */
71
+ readonly MAX_DEPTH: 32;
72
+ };
73
+ export declare const ERROR_CONSTANTS: {
74
+ /** Rate limit for render error logging (ms) */
75
+ readonly RENDER_ERROR_THROTTLE_MS: 1000;
76
+ };
77
+ export declare const PIPELINE_CONSTANTS: {
78
+ /** Total uniform buffer size */
79
+ readonly UNIFORM_BUFFER_SIZE: 192;
80
+ /** Byte offset for flags in uniform buffer */
81
+ readonly FLAGS_BYTE_OFFSET: 176;
82
+ /** Default MSAA sample count */
83
+ readonly DEFAULT_SAMPLE_COUNT: 4;
84
+ /** Depth format for reverse-Z */
85
+ readonly DEPTH_FORMAT: "depth32float";
86
+ };
87
+ export declare const LIGHTING_CONSTANTS: {
88
+ readonly SUN_LIGHT: {
89
+ readonly x: 0.5;
90
+ readonly y: 1;
91
+ readonly z: 0.3;
92
+ };
93
+ readonly FILL_LIGHT: {
94
+ readonly x: -0.5;
95
+ readonly y: 0.3;
96
+ readonly z: -0.3;
97
+ };
98
+ readonly RIM_LIGHT: {
99
+ readonly x: 0;
100
+ readonly y: 0.2;
101
+ readonly z: -1;
102
+ };
103
+ readonly SKY_COLOR: {
104
+ readonly r: 0.3;
105
+ readonly g: 0.35;
106
+ readonly b: 0.4;
107
+ };
108
+ readonly GROUND_COLOR: {
109
+ readonly r: 0.15;
110
+ readonly g: 0.1;
111
+ readonly b: 0.08;
112
+ };
113
+ readonly AMBIENT_INTENSITY: 0.25;
114
+ readonly DIFFUSE_SUN_INTENSITY: 0.55;
115
+ readonly DIFFUSE_FILL_INTENSITY: 0.15;
116
+ readonly RIM_INTENSITY: 0.15;
117
+ readonly WRAP_FACTOR: 0.3;
118
+ };
119
+ export declare const PICK_CONSTANTS: {
120
+ /** Maximum meshes to create for picking during streaming */
121
+ readonly MAX_PICK_MESH_CREATION: 500;
122
+ /** Pick buffer format */
123
+ readonly BUFFER_FORMAT: "rgba8unorm";
124
+ };
125
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA;;GAEG;AAMH,eAAO,MAAM,gBAAgB;IAE3B,0DAA0D;;IAE1D,6CAA6C;;IAI7C,kCAAkC;;IAElC,4CAA4C;;IAE5C,2BAA2B;;IAE3B,uBAAuB;;IAEvB,mCAAmC;;;;;;;;;;;;;;;;;;;;IAYnC,iDAAiD;;IAEjD,2CAA2C;;IAE3C,uCAAuC;;IAIvC,wDAAwD;;IAExD,wDAAwD;;IAExD,2CAA2C;;IAI3C,uCAAuC;;IAEvC,qCAAqC;;IAIrC,0CAA0C;;IAE1C,6CAA6C;;IAE7C,yCAAyC;;;;;;;CAKjC,CAAC;AAMX,eAAO,MAAM,aAAa;IACxB,qDAAqD;;IAErD,uCAAuC;;IAEvC,yBAAyB;;CAEjB,CAAC;AAMX,eAAO,MAAM,eAAe;IAC1B,+CAA+C;;CAEvC,CAAC;AAMX,eAAO,MAAM,kBAAkB;IAE7B,gCAAgC;;IAEhC,8CAA8C;;IAI9C,gCAAgC;;IAIhC,iCAAiC;;CAEzB,CAAC;AAMX,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAMX,eAAO,MAAM,cAAc;IACzB,4DAA4D;;IAE5D,yBAAyB;;CAEjB,CAAC"}
@@ -0,0 +1,124 @@
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
+ * Renderer constants - extracted magic numbers for maintainability
6
+ */
7
+ // ============================================================================
8
+ // Camera Constants
9
+ // ============================================================================
10
+ export const CAMERA_CONSTANTS = {
11
+ // Inertia system
12
+ /** Inertia damping factor (0-1), higher = more damping */
13
+ DAMPING_FACTOR: 0.92,
14
+ /** Minimum velocity threshold for inertia */
15
+ MIN_VELOCITY_THRESHOLD: 0.001,
16
+ // Movement speeds
17
+ /** First-person movement speed */
18
+ FIRST_PERSON_SPEED: 0.1,
19
+ /** Orbit sensitivity (radians per pixel) */
20
+ ORBIT_SENSITIVITY: 0.01,
21
+ /** Pan speed multiplier */
22
+ PAN_SPEED_MULTIPLIER: 0.001,
23
+ /** Zoom sensitivity */
24
+ ZOOM_SENSITIVITY: 0.001,
25
+ /** Maximum zoom delta per frame */
26
+ MAX_ZOOM_DELTA: 0.1,
27
+ // Default camera setup
28
+ DEFAULT_POSITION: { x: 50, y: 50, z: 100 },
29
+ DEFAULT_TARGET: { x: 0, y: 0, z: 0 },
30
+ DEFAULT_UP: { x: 0, y: 1, z: 0 },
31
+ DEFAULT_FOV: Math.PI / 4, // 45 degrees
32
+ DEFAULT_NEAR: 0.1,
33
+ DEFAULT_FAR: 100000,
34
+ // Depth precision
35
+ /** Maximum near/far ratio for depth precision */
36
+ MAX_NEAR_FAR_RATIO: 10000,
37
+ /** Near plane as percentage of distance */
38
+ NEAR_DISTANCE_FACTOR: 0.001,
39
+ /** Far plane multiplier of distance */
40
+ FAR_DISTANCE_MULTIPLIER: 10,
41
+ // Gimbal lock prevention
42
+ /** Minimum phi angle to prevent gimbal lock at poles */
43
+ MIN_PHI: 0.15,
44
+ /** Maximum phi angle to prevent gimbal lock at poles */
45
+ MAX_PHI: Math.PI - 0.15,
46
+ /** Sin phi threshold for pole detection */
47
+ POLE_THRESHOLD: 0.05,
48
+ // Animation
49
+ /** Default animation duration in ms */
50
+ DEFAULT_ANIMATION_DURATION: 500,
51
+ /** Quick animation duration in ms */
52
+ QUICK_ANIMATION_DURATION: 300,
53
+ // Fit to bounds
54
+ /** Distance multiplier for fitToBounds */
55
+ FIT_DISTANCE_MULTIPLIER: 2.0,
56
+ /** Padding multiplier for frame selection */
57
+ FRAME_PADDING_MULTIPLIER: 1.2,
58
+ /** Padding multiplier for zoom extent */
59
+ ZOOM_EXTENT_PADDING: 1.5,
60
+ // Isometric view offsets
61
+ ISOMETRIC_OFFSET: { right: 0.6, up: 0.5, front: 0.6 },
62
+ };
63
+ // ============================================================================
64
+ // BVH Constants
65
+ // ============================================================================
66
+ export const BVH_CONSTANTS = {
67
+ /** Minimum mesh count to trigger BVH construction */
68
+ THRESHOLD: 100,
69
+ /** Maximum primitives per leaf node */
70
+ MAX_PRIMITIVES_PER_LEAF: 4,
71
+ /** Maximum tree depth */
72
+ MAX_DEPTH: 32,
73
+ };
74
+ // ============================================================================
75
+ // Error Handling Constants
76
+ // ============================================================================
77
+ export const ERROR_CONSTANTS = {
78
+ /** Rate limit for render error logging (ms) */
79
+ RENDER_ERROR_THROTTLE_MS: 1000,
80
+ };
81
+ // ============================================================================
82
+ // Pipeline Constants
83
+ // ============================================================================
84
+ export const PIPELINE_CONSTANTS = {
85
+ // Buffer layout (bytes) - must match WGSL shader expectations
86
+ /** Total uniform buffer size */
87
+ UNIFORM_BUFFER_SIZE: 192,
88
+ /** Byte offset for flags in uniform buffer */
89
+ FLAGS_BYTE_OFFSET: 176,
90
+ // MSAA
91
+ /** Default MSAA sample count */
92
+ DEFAULT_SAMPLE_COUNT: 4,
93
+ // Depth buffer
94
+ /** Depth format for reverse-Z */
95
+ DEPTH_FORMAT: 'depth32float',
96
+ };
97
+ // ============================================================================
98
+ // Lighting Constants (for shaders)
99
+ // ============================================================================
100
+ export const LIGHTING_CONSTANTS = {
101
+ // Directional lights (normalized directions)
102
+ SUN_LIGHT: { x: 0.5, y: 1.0, z: 0.3 },
103
+ FILL_LIGHT: { x: -0.5, y: 0.3, z: -0.3 },
104
+ RIM_LIGHT: { x: 0.0, y: 0.2, z: -1.0 },
105
+ // Hemisphere colors
106
+ SKY_COLOR: { r: 0.3, g: 0.35, b: 0.4 },
107
+ GROUND_COLOR: { r: 0.15, g: 0.1, b: 0.08 },
108
+ // Intensities
109
+ AMBIENT_INTENSITY: 0.25,
110
+ DIFFUSE_SUN_INTENSITY: 0.55,
111
+ DIFFUSE_FILL_INTENSITY: 0.15,
112
+ RIM_INTENSITY: 0.15,
113
+ WRAP_FACTOR: 0.3,
114
+ };
115
+ // ============================================================================
116
+ // Pick Constants
117
+ // ============================================================================
118
+ export const PICK_CONSTANTS = {
119
+ /** Maximum meshes to create for picking during streaming */
120
+ MAX_PICK_MESH_CREATION: 500,
121
+ /** Pick buffer format */
122
+ BUFFER_FORMAT: 'rgba8unorm',
123
+ };
124
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,UAAU,CAAa;IAE/B;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCpD;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAoBxB;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAM3B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;;OAGG;IACH,aAAa,IAAI,OAAO;IAWxB;;;OAGG;IACH,iBAAiB,IAAI,UAAU,GAAG,IAAI;IActC,SAAS,IAAI,SAAS;IAOtB,UAAU,IAAI,gBAAgB;IAO9B,SAAS,IAAI,gBAAgB;IAI7B,aAAa,IAAI,OAAO;CAGzB"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,UAAU,CAAa;IAE/B;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCpD;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAoBxB;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAM3B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;;OAGG;IACH,aAAa,IAAI,OAAO;IAWxB;;;OAGG;IACH,iBAAiB,IAAI,UAAU,GAAG,IAAI;IAgBtC,SAAS,IAAI,SAAS;IAOtB,UAAU,IAAI,gBAAgB;IAO9B,SAAS,IAAI,gBAAgB;IAI7B,aAAa,IAAI,OAAO;CAGzB"}
package/dist/device.js CHANGED
@@ -100,8 +100,9 @@ export class WebGPUDevice {
100
100
  * Returns null if texture is not available (context needs reconfiguration)
101
101
  */
102
102
  getCurrentTexture() {
103
- if (!this.context || !this.contextConfigured)
103
+ if (!this.context || !this.contextConfigured) {
104
104
  return null;
105
+ }
105
106
  try {
106
107
  const texture = this.context.getCurrentTexture();
107
108
  this.frameCount++;
@@ -1 +1 @@
1
- {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * FederationRegistry - Bulletproof multi-model ID management
3
+ *
4
+ * Each model gets a unique ID offset, ensuring globally unique IDs across
5
+ * all federated models. This eliminates ID collisions when multiple IFC
6
+ * files have overlapping expressIds.
7
+ *
8
+ * Inspired by HOOPS Communicator's loadSubtree approach where node IDs
9
+ * are automatically offset to avoid conflicts.
10
+ */
11
+ export interface ModelRange {
12
+ modelId: string;
13
+ offset: number;
14
+ maxExpressId: number;
15
+ }
16
+ export interface GlobalIdLookup {
17
+ modelId: string;
18
+ expressId: number;
19
+ }
20
+ /**
21
+ * Central registry for multi-model federation
22
+ * Manages ID offsets and provides O(1) to-global / O(log N) from-global transformations
23
+ */
24
+ export declare class FederationRegistry {
25
+ private modelRanges;
26
+ private sortedRanges;
27
+ private nextOffset;
28
+ /**
29
+ * Register a new model and get its ID offset
30
+ * Call this BEFORE adding meshes to the scene
31
+ *
32
+ * @param modelId Unique identifier for this model
33
+ * @param maxExpressId Highest expressId in this model (scan meshes first)
34
+ * @returns The offset to add to all expressIds for this model
35
+ */
36
+ registerModel(modelId: string, maxExpressId: number): number;
37
+ /**
38
+ * Unregister a model (when removed from viewer)
39
+ * Note: The offset space is NOT reclaimed to avoid invalidating any
40
+ * existing references (selections, undo stack, etc.)
41
+ */
42
+ unregisterModel(modelId: string): void;
43
+ /**
44
+ * Transform a local expressId to a globally unique ID
45
+ * O(1) - direct map lookup + addition
46
+ */
47
+ toGlobalId(modelId: string, expressId: number): number;
48
+ /**
49
+ * Transform a global ID back to model + local expressId
50
+ * O(log N) - binary search on sorted ranges
51
+ */
52
+ fromGlobalId(globalId: number): GlobalIdLookup | null;
53
+ /**
54
+ * Get the model ID that owns a global ID (without computing expressId)
55
+ * O(log N)
56
+ */
57
+ getModelForGlobalId(globalId: number): string | null;
58
+ /**
59
+ * Get the offset for a model (useful for batch transformations)
60
+ */
61
+ getOffset(modelId: string): number | null;
62
+ /**
63
+ * Check if a model is registered
64
+ */
65
+ hasModel(modelId: string): boolean;
66
+ /**
67
+ * Get all registered model IDs
68
+ */
69
+ getModelIds(): string[];
70
+ /**
71
+ * Get the number of registered models
72
+ */
73
+ getModelCount(): number;
74
+ /**
75
+ * Get all global IDs for a model (as a range)
76
+ * Useful for bulk operations like "hide all entities in model X"
77
+ */
78
+ getGlobalIdRange(modelId: string): {
79
+ start: number;
80
+ end: number;
81
+ } | null;
82
+ /**
83
+ * Check if a global ID belongs to a specific model
84
+ * O(1) when we know the model
85
+ */
86
+ isInModel(globalId: number, modelId: string): boolean;
87
+ /**
88
+ * Clear all registrations (for full reset)
89
+ */
90
+ clear(): void;
91
+ /**
92
+ * Binary search to find the range that could contain a globalId
93
+ * Returns the range with the largest offset that is <= globalId
94
+ */
95
+ private binarySearchRange;
96
+ }
97
+ export declare const federationRegistry: FederationRegistry;
98
+ //# sourceMappingURL=federation-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-registry.d.ts","sourceRoot":"","sources":["../src/federation-registry.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;;;;OAOG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAuC5D;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYtC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAStD;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAwBrD;;;OAGG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKpD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIzC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIlC;;OAEG;IACH,WAAW,IAAI,MAAM,EAAE;IAIvB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IASxE;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAOrD;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAsB1B;AAID,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
@@ -0,0 +1,197 @@
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
+ // Safety limit - warn before approaching 32-bit limit
5
+ // WebGPU picking uses r32uint (max 4,294,967,295)
6
+ const MAX_SAFE_OFFSET = 2_000_000_000;
7
+ /**
8
+ * Central registry for multi-model federation
9
+ * Manages ID offsets and provides O(1) to-global / O(log N) from-global transformations
10
+ */
11
+ export class FederationRegistry {
12
+ modelRanges = new Map();
13
+ sortedRanges = []; // Sorted by offset for binary search
14
+ nextOffset = 0;
15
+ /**
16
+ * Register a new model and get its ID offset
17
+ * Call this BEFORE adding meshes to the scene
18
+ *
19
+ * @param modelId Unique identifier for this model
20
+ * @param maxExpressId Highest expressId in this model (scan meshes first)
21
+ * @returns The offset to add to all expressIds for this model
22
+ */
23
+ registerModel(modelId, maxExpressId) {
24
+ // Validate inputs
25
+ if (!modelId || typeof modelId !== 'string') {
26
+ throw new Error(`[FederationRegistry] Invalid modelId: ${modelId}`);
27
+ }
28
+ if (typeof maxExpressId !== 'number' || !Number.isFinite(maxExpressId) || maxExpressId < 0) {
29
+ throw new Error(`[FederationRegistry] Invalid maxExpressId: ${maxExpressId} for model ${modelId}`);
30
+ }
31
+ // Check for duplicate registration
32
+ if (this.modelRanges.has(modelId)) {
33
+ const existing = this.modelRanges.get(modelId);
34
+ console.warn(`[FederationRegistry] Model ${modelId} already registered with offset ${existing.offset}`);
35
+ return existing.offset;
36
+ }
37
+ // Check for overflow
38
+ if (this.nextOffset + maxExpressId > MAX_SAFE_OFFSET) {
39
+ throw new Error(`[FederationRegistry] Cannot register model: would exceed safe ID limit. ` +
40
+ `Current offset: ${this.nextOffset}, model max ID: ${maxExpressId}. ` +
41
+ `Please unload some models first.`);
42
+ }
43
+ const offset = this.nextOffset;
44
+ const range = { modelId, offset, maxExpressId };
45
+ this.modelRanges.set(modelId, range);
46
+ this.sortedRanges.push(range);
47
+ // Keep sorted by offset for binary search
48
+ this.sortedRanges.sort((a, b) => a.offset - b.offset);
49
+ // Next model starts after this model's range (+1 gap for safety)
50
+ this.nextOffset = offset + maxExpressId + 1;
51
+ return offset;
52
+ }
53
+ /**
54
+ * Unregister a model (when removed from viewer)
55
+ * Note: The offset space is NOT reclaimed to avoid invalidating any
56
+ * existing references (selections, undo stack, etc.)
57
+ */
58
+ unregisterModel(modelId) {
59
+ const range = this.modelRanges.get(modelId);
60
+ if (!range) {
61
+ console.warn(`[FederationRegistry] Cannot unregister unknown model: ${modelId}`);
62
+ return;
63
+ }
64
+ this.modelRanges.delete(modelId);
65
+ this.sortedRanges = this.sortedRanges.filter(r => r.modelId !== modelId);
66
+ // Note: nextOffset is NOT reduced - offset space is burned
67
+ }
68
+ /**
69
+ * Transform a local expressId to a globally unique ID
70
+ * O(1) - direct map lookup + addition
71
+ */
72
+ toGlobalId(modelId, expressId) {
73
+ const range = this.modelRanges.get(modelId);
74
+ if (!range) {
75
+ console.warn(`[FederationRegistry] Unknown model: ${modelId}, returning expressId unchanged`);
76
+ return expressId;
77
+ }
78
+ return expressId + range.offset;
79
+ }
80
+ /**
81
+ * Transform a global ID back to model + local expressId
82
+ * O(log N) - binary search on sorted ranges
83
+ */
84
+ fromGlobalId(globalId) {
85
+ if (this.sortedRanges.length === 0) {
86
+ return null;
87
+ }
88
+ // Binary search to find which range contains this globalId
89
+ const range = this.binarySearchRange(globalId);
90
+ if (!range) {
91
+ return null;
92
+ }
93
+ // Verify the globalId is actually within this model's range
94
+ const localId = globalId - range.offset;
95
+ if (localId < 0 || localId > range.maxExpressId) {
96
+ // globalId is in the gap between models
97
+ return null;
98
+ }
99
+ return {
100
+ modelId: range.modelId,
101
+ expressId: localId,
102
+ };
103
+ }
104
+ /**
105
+ * Get the model ID that owns a global ID (without computing expressId)
106
+ * O(log N)
107
+ */
108
+ getModelForGlobalId(globalId) {
109
+ const result = this.fromGlobalId(globalId);
110
+ return result?.modelId ?? null;
111
+ }
112
+ /**
113
+ * Get the offset for a model (useful for batch transformations)
114
+ */
115
+ getOffset(modelId) {
116
+ return this.modelRanges.get(modelId)?.offset ?? null;
117
+ }
118
+ /**
119
+ * Check if a model is registered
120
+ */
121
+ hasModel(modelId) {
122
+ return this.modelRanges.has(modelId);
123
+ }
124
+ /**
125
+ * Get all registered model IDs
126
+ */
127
+ getModelIds() {
128
+ return Array.from(this.modelRanges.keys());
129
+ }
130
+ /**
131
+ * Get the number of registered models
132
+ */
133
+ getModelCount() {
134
+ return this.modelRanges.size;
135
+ }
136
+ /**
137
+ * Get all global IDs for a model (as a range)
138
+ * Useful for bulk operations like "hide all entities in model X"
139
+ */
140
+ getGlobalIdRange(modelId) {
141
+ const range = this.modelRanges.get(modelId);
142
+ if (!range)
143
+ return null;
144
+ return {
145
+ start: range.offset,
146
+ end: range.offset + range.maxExpressId,
147
+ };
148
+ }
149
+ /**
150
+ * Check if a global ID belongs to a specific model
151
+ * O(1) when we know the model
152
+ */
153
+ isInModel(globalId, modelId) {
154
+ const range = this.modelRanges.get(modelId);
155
+ if (!range)
156
+ return false;
157
+ const localId = globalId - range.offset;
158
+ return localId >= 0 && localId <= range.maxExpressId;
159
+ }
160
+ /**
161
+ * Clear all registrations (for full reset)
162
+ */
163
+ clear() {
164
+ this.modelRanges.clear();
165
+ this.sortedRanges = [];
166
+ this.nextOffset = 0;
167
+ }
168
+ /**
169
+ * Binary search to find the range that could contain a globalId
170
+ * Returns the range with the largest offset that is <= globalId
171
+ */
172
+ binarySearchRange(globalId) {
173
+ const ranges = this.sortedRanges;
174
+ if (ranges.length === 0)
175
+ return null;
176
+ // If globalId is before first range, no match
177
+ if (globalId < ranges[0].offset)
178
+ return null;
179
+ let lo = 0;
180
+ let hi = ranges.length - 1;
181
+ // Find the rightmost range where offset <= globalId
182
+ while (lo < hi) {
183
+ const mid = Math.floor((lo + hi + 1) / 2);
184
+ if (ranges[mid].offset <= globalId) {
185
+ lo = mid;
186
+ }
187
+ else {
188
+ hi = mid - 1;
189
+ }
190
+ }
191
+ return ranges[lo];
192
+ }
193
+ }
194
+ // Singleton instance for the application
195
+ // Export both the class (for testing) and a singleton instance
196
+ export const federationRegistry = new FederationRegistry();
197
+ //# sourceMappingURL=federation-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-registry.js","sourceRoot":"","sources":["../src/federation-registry.ts"],"names":[],"mappings":"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"}