@ifc-lite/renderer 1.6.0 → 1.7.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 (42) hide show
  1. package/README.md +40 -0
  2. package/dist/camera-animation.d.ts +108 -0
  3. package/dist/camera-animation.d.ts.map +1 -0
  4. package/dist/camera-animation.js +606 -0
  5. package/dist/camera-animation.js.map +1 -0
  6. package/dist/camera-controls.d.ts +75 -0
  7. package/dist/camera-controls.d.ts.map +1 -0
  8. package/dist/camera-controls.js +239 -0
  9. package/dist/camera-controls.js.map +1 -0
  10. package/dist/camera-projection.d.ts +51 -0
  11. package/dist/camera-projection.d.ts.map +1 -0
  12. package/dist/camera-projection.js +147 -0
  13. package/dist/camera-projection.js.map +1 -0
  14. package/dist/camera.d.ts +33 -45
  15. package/dist/camera.d.ts.map +1 -1
  16. package/dist/camera.js +128 -815
  17. package/dist/camera.js.map +1 -1
  18. package/dist/geometry-manager.d.ts +99 -0
  19. package/dist/geometry-manager.d.ts.map +1 -0
  20. package/dist/geometry-manager.js +387 -0
  21. package/dist/geometry-manager.js.map +1 -0
  22. package/dist/index.d.ts +7 -19
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +50 -658
  25. package/dist/index.js.map +1 -1
  26. package/dist/math.d.ts +6 -0
  27. package/dist/math.d.ts.map +1 -1
  28. package/dist/math.js +20 -0
  29. package/dist/math.js.map +1 -1
  30. package/dist/picking-manager.d.ts +31 -0
  31. package/dist/picking-manager.d.ts.map +1 -0
  32. package/dist/picking-manager.js +140 -0
  33. package/dist/picking-manager.js.map +1 -0
  34. package/dist/raycast-engine.d.ts +76 -0
  35. package/dist/raycast-engine.d.ts.map +1 -0
  36. package/dist/raycast-engine.js +255 -0
  37. package/dist/raycast-engine.js.map +1 -0
  38. package/dist/scene.d.ts +8 -1
  39. package/dist/scene.d.ts.map +1 -1
  40. package/dist/scene.js +59 -25
  41. package/dist/scene.js.map +1 -1
  42. package/package.json +4 -4
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Camera orbit, pan, and zoom controls with spherical coordinate math.
3
+ * Extracted from Camera class using composition pattern.
4
+ */
5
+ import type { Camera as CameraType, Vec3, Mat4 } from './types.js';
6
+ /** Projection mode for the camera */
7
+ export type ProjectionMode = 'perspective' | 'orthographic';
8
+ /**
9
+ * Shared mutable state for camera sub-systems.
10
+ * All sub-systems reference the same state object so changes are visible across them.
11
+ */
12
+ export interface CameraInternalState {
13
+ camera: CameraType;
14
+ viewMatrix: Mat4;
15
+ projMatrix: Mat4;
16
+ viewProjMatrix: Mat4;
17
+ /** Current projection mode */
18
+ projectionMode: ProjectionMode;
19
+ /** Orthographic half-height in world units (controls zoom level in ortho mode) */
20
+ orthoSize: number;
21
+ }
22
+ /**
23
+ * Handles core camera movement: orbit, pan, and zoom.
24
+ * Uses spherical coordinates for orbit with Y-up convention.
25
+ */
26
+ export declare class CameraControls {
27
+ private readonly state;
28
+ private readonly updateMatrices;
29
+ /** Dynamic orbit pivot (for orbiting around selected element or cursor point) */
30
+ private orbitPivot;
31
+ constructor(state: CameraInternalState, updateMatrices: () => void);
32
+ /**
33
+ * Set temporary orbit pivot (for orbiting around selected element or cursor point)
34
+ * When set, orbit() will rotate around this point instead of the camera target
35
+ */
36
+ setOrbitPivot(pivot: Vec3 | null): void;
37
+ /**
38
+ * Get current orbit pivot (returns temporary pivot if set, otherwise target)
39
+ */
40
+ getOrbitPivot(): Vec3;
41
+ /**
42
+ * Check if a temporary orbit pivot is set
43
+ */
44
+ hasOrbitPivot(): boolean;
45
+ /**
46
+ * Clear the orbit pivot
47
+ */
48
+ clearOrbitPivot(): void;
49
+ /**
50
+ * Orbit around target or pivot (Y-up coordinate system).
51
+ * If an orbit pivot is set, orbits around that point.
52
+ *
53
+ * Note: Does not handle velocity or preset view tracking;
54
+ * the Camera class coordinates those concerns.
55
+ */
56
+ orbit(deltaX: number, deltaY: number): void;
57
+ /**
58
+ * Pan camera (Y-up coordinate system).
59
+ *
60
+ * Note: Does not handle velocity; the Camera class coordinates that.
61
+ */
62
+ pan(deltaX: number, deltaY: number): void;
63
+ /**
64
+ * Zoom camera towards mouse position.
65
+ * @param delta - Zoom delta (positive = zoom out, negative = zoom in)
66
+ * @param mouseX - Mouse X position in canvas coordinates
67
+ * @param mouseY - Mouse Y position in canvas coordinates
68
+ * @param canvasWidth - Canvas width
69
+ * @param canvasHeight - Canvas height
70
+ *
71
+ * Note: Does not handle velocity; the Camera class coordinates that.
72
+ */
73
+ zoom(delta: number, mouseX?: number, mouseY?: number, canvasWidth?: number, canvasHeight?: number): void;
74
+ }
75
+ //# sourceMappingURL=camera-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-controls.d.ts","sourceRoot":"","sources":["../src/camera-controls.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEnE,qCAAqC;AACrC,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,cAAc,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,IAAI,CAAC;IACrB,8BAA8B;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;IALjC,iFAAiF;IACjF,OAAO,CAAC,UAAU,CAAqB;gBAGpB,KAAK,EAAE,mBAAmB,EAC1B,cAAc,EAAE,MAAM,IAAI;IAG7C;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,eAAe,IAAI,IAAI;IAIvB;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IA+D3C;;;;OAIG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IA4CzC;;;;;;;;;OASG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;CA2FzG"}
@@ -0,0 +1,239 @@
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
+ * Handles core camera movement: orbit, pan, and zoom.
6
+ * Uses spherical coordinates for orbit with Y-up convention.
7
+ */
8
+ export class CameraControls {
9
+ state;
10
+ updateMatrices;
11
+ /** Dynamic orbit pivot (for orbiting around selected element or cursor point) */
12
+ orbitPivot = null;
13
+ constructor(state, updateMatrices) {
14
+ this.state = state;
15
+ this.updateMatrices = updateMatrices;
16
+ }
17
+ /**
18
+ * Set temporary orbit pivot (for orbiting around selected element or cursor point)
19
+ * When set, orbit() will rotate around this point instead of the camera target
20
+ */
21
+ setOrbitPivot(pivot) {
22
+ this.orbitPivot = pivot ? { ...pivot } : null;
23
+ }
24
+ /**
25
+ * Get current orbit pivot (returns temporary pivot if set, otherwise target)
26
+ */
27
+ getOrbitPivot() {
28
+ return this.orbitPivot ? { ...this.orbitPivot } : { ...this.state.camera.target };
29
+ }
30
+ /**
31
+ * Check if a temporary orbit pivot is set
32
+ */
33
+ hasOrbitPivot() {
34
+ return this.orbitPivot !== null;
35
+ }
36
+ /**
37
+ * Clear the orbit pivot
38
+ */
39
+ clearOrbitPivot() {
40
+ this.orbitPivot = null;
41
+ }
42
+ /**
43
+ * Orbit around target or pivot (Y-up coordinate system).
44
+ * If an orbit pivot is set, orbits around that point.
45
+ *
46
+ * Note: Does not handle velocity or preset view tracking;
47
+ * the Camera class coordinates those concerns.
48
+ */
49
+ orbit(deltaX, deltaY) {
50
+ // Always ensure Y-up for consistent orbit behavior
51
+ this.state.camera.up = { x: 0, y: 1, z: 0 };
52
+ // Invert controls: mouse movement direction = model rotation direction
53
+ const dx = -deltaX * 0.01;
54
+ const dy = -deltaY * 0.01;
55
+ // Use orbit pivot if set, otherwise use target
56
+ const pivotPoint = this.orbitPivot || this.state.camera.target;
57
+ const dir = {
58
+ x: this.state.camera.position.x - pivotPoint.x,
59
+ y: this.state.camera.position.y - pivotPoint.y,
60
+ z: this.state.camera.position.z - pivotPoint.z,
61
+ };
62
+ const distance = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
63
+ if (distance < 1e-6)
64
+ return;
65
+ // Y-up coordinate system using standard spherical coordinates
66
+ // theta: horizontal rotation around Y axis
67
+ // phi: vertical angle from Y axis (0 = top, PI = bottom)
68
+ let currentPhi = Math.acos(Math.max(-1, Math.min(1, dir.y / distance)));
69
+ // When at poles (top/bottom view), use a stable theta based on current direction
70
+ // to avoid gimbal lock issues
71
+ let theta;
72
+ const sinPhi = Math.sin(currentPhi);
73
+ if (sinPhi > 0.05) {
74
+ // Normal case - calculate theta from horizontal position
75
+ theta = Math.atan2(dir.x, dir.z);
76
+ }
77
+ else {
78
+ // At a pole - determine which one and push away
79
+ theta = 0; // Default theta when at pole
80
+ if (currentPhi < Math.PI / 2) {
81
+ // Top pole (phi ~ 0) - push down
82
+ currentPhi = 0.15;
83
+ }
84
+ else {
85
+ // Bottom pole (phi ~ PI) - push up
86
+ currentPhi = Math.PI - 0.15;
87
+ }
88
+ }
89
+ theta += dx;
90
+ const phi = currentPhi + dy;
91
+ // Clamp phi to prevent gimbal lock (stay away from exact poles)
92
+ const phiClamped = Math.max(0.15, Math.min(Math.PI - 0.15, phi));
93
+ // Calculate new camera position around pivot
94
+ const newPosX = pivotPoint.x + distance * Math.sin(phiClamped) * Math.sin(theta);
95
+ const newPosY = pivotPoint.y + distance * Math.cos(phiClamped);
96
+ const newPosZ = pivotPoint.z + distance * Math.sin(phiClamped) * Math.cos(theta);
97
+ // Update camera position
98
+ this.state.camera.position.x = newPosX;
99
+ this.state.camera.position.y = newPosY;
100
+ this.state.camera.position.z = newPosZ;
101
+ this.updateMatrices();
102
+ }
103
+ /**
104
+ * Pan camera (Y-up coordinate system).
105
+ *
106
+ * Note: Does not handle velocity; the Camera class coordinates that.
107
+ */
108
+ pan(deltaX, deltaY) {
109
+ const dir = {
110
+ x: this.state.camera.position.x - this.state.camera.target.x,
111
+ y: this.state.camera.position.y - this.state.camera.target.y,
112
+ z: this.state.camera.position.z - this.state.camera.target.z,
113
+ };
114
+ const distance = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
115
+ // Right vector: cross product of direction and up (0,1,0)
116
+ const right = {
117
+ x: -dir.z,
118
+ y: 0,
119
+ z: dir.x,
120
+ };
121
+ const rightLen = Math.sqrt(right.x * right.x + right.z * right.z);
122
+ if (rightLen > 1e-10) {
123
+ right.x /= rightLen;
124
+ right.z /= rightLen;
125
+ }
126
+ // Up vector: cross product of right and direction
127
+ const up = {
128
+ x: (right.z * dir.y - right.y * dir.z),
129
+ y: (right.x * dir.z - right.z * dir.x),
130
+ z: (right.y * dir.x - right.x * dir.y),
131
+ };
132
+ const upLen = Math.sqrt(up.x * up.x + up.y * up.y + up.z * up.z);
133
+ if (upLen > 1e-10) {
134
+ up.x /= upLen;
135
+ up.y /= upLen;
136
+ up.z /= upLen;
137
+ }
138
+ const panSpeed = distance * 0.001;
139
+ this.state.camera.target.x += (right.x * deltaX + up.x * deltaY) * panSpeed;
140
+ this.state.camera.target.y += (right.y * deltaX + up.y * deltaY) * panSpeed;
141
+ this.state.camera.target.z += (right.z * deltaX + up.z * deltaY) * panSpeed;
142
+ this.state.camera.position.x += (right.x * deltaX + up.x * deltaY) * panSpeed;
143
+ this.state.camera.position.y += (right.y * deltaX + up.y * deltaY) * panSpeed;
144
+ this.state.camera.position.z += (right.z * deltaX + up.z * deltaY) * panSpeed;
145
+ this.updateMatrices();
146
+ }
147
+ /**
148
+ * Zoom camera towards mouse position.
149
+ * @param delta - Zoom delta (positive = zoom out, negative = zoom in)
150
+ * @param mouseX - Mouse X position in canvas coordinates
151
+ * @param mouseY - Mouse Y position in canvas coordinates
152
+ * @param canvasWidth - Canvas width
153
+ * @param canvasHeight - Canvas height
154
+ *
155
+ * Note: Does not handle velocity; the Camera class coordinates that.
156
+ */
157
+ zoom(delta, mouseX, mouseY, canvasWidth, canvasHeight) {
158
+ const dir = {
159
+ x: this.state.camera.position.x - this.state.camera.target.x,
160
+ y: this.state.camera.position.y - this.state.camera.target.y,
161
+ z: this.state.camera.position.z - this.state.camera.target.z,
162
+ };
163
+ const distance = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
164
+ // Normalize delta (wheel events can have large values)
165
+ const normalizedDelta = Math.sign(delta) * Math.min(Math.abs(delta) * 0.001, 0.1);
166
+ const zoomFactor = 1 + normalizedDelta;
167
+ // If mouse position provided, zoom towards that point
168
+ if (mouseX !== undefined && mouseY !== undefined && canvasWidth && canvasHeight) {
169
+ // Convert mouse to normalized device coordinates (-1 to 1)
170
+ const ndcX = (mouseX / canvasWidth) * 2 - 1;
171
+ const ndcY = 1 - (mouseY / canvasHeight) * 2; // Flip Y
172
+ // Calculate offset from center in world space
173
+ // Use the camera's right and up vectors
174
+ const forward = {
175
+ x: -dir.x / distance,
176
+ y: -dir.y / distance,
177
+ z: -dir.z / distance,
178
+ };
179
+ // Right = forward x up
180
+ const up = this.state.camera.up;
181
+ const right = {
182
+ x: forward.y * up.z - forward.z * up.y,
183
+ y: forward.z * up.x - forward.x * up.z,
184
+ z: forward.x * up.y - forward.y * up.x,
185
+ };
186
+ const rightLen = Math.sqrt(right.x * right.x + right.y * right.y + right.z * right.z);
187
+ if (rightLen > 1e-10) {
188
+ right.x /= rightLen;
189
+ right.y /= rightLen;
190
+ right.z /= rightLen;
191
+ }
192
+ // Actual up = right x forward
193
+ const actualUp = {
194
+ x: right.y * forward.z - right.z * forward.y,
195
+ y: right.z * forward.x - right.x * forward.z,
196
+ z: right.x * forward.y - right.y * forward.x,
197
+ };
198
+ // Calculate view frustum size at target distance
199
+ const halfHeight = this.state.projectionMode === 'orthographic'
200
+ ? this.state.orthoSize
201
+ : distance * Math.tan(this.state.camera.fov / 2);
202
+ const halfWidth = halfHeight * this.state.camera.aspect;
203
+ // World offset from center towards mouse position
204
+ const worldOffsetX = ndcX * halfWidth;
205
+ const worldOffsetY = ndcY * halfHeight;
206
+ // Point in world space that mouse is pointing at (on the target plane)
207
+ const mouseWorldPoint = {
208
+ x: this.state.camera.target.x + right.x * worldOffsetX + actualUp.x * worldOffsetY,
209
+ y: this.state.camera.target.y + right.y * worldOffsetX + actualUp.y * worldOffsetY,
210
+ z: this.state.camera.target.z + right.z * worldOffsetX + actualUp.z * worldOffsetY,
211
+ };
212
+ // Move both camera and target towards mouse point while zooming
213
+ const moveAmount = (1 - zoomFactor); // Negative when zooming in
214
+ this.state.camera.target.x += (mouseWorldPoint.x - this.state.camera.target.x) * moveAmount;
215
+ this.state.camera.target.y += (mouseWorldPoint.y - this.state.camera.target.y) * moveAmount;
216
+ this.state.camera.target.z += (mouseWorldPoint.z - this.state.camera.target.z) * moveAmount;
217
+ }
218
+ if (this.state.projectionMode === 'orthographic') {
219
+ // Orthographic: scale view volume instead of moving camera
220
+ this.state.orthoSize = Math.max(0.01, this.state.orthoSize * zoomFactor);
221
+ // Still move camera position to keep orbit distance consistent for when switching back
222
+ const newDistance = Math.max(0.1, distance * zoomFactor);
223
+ const scale = newDistance / distance;
224
+ this.state.camera.position.x = this.state.camera.target.x + dir.x * scale;
225
+ this.state.camera.position.y = this.state.camera.target.y + dir.y * scale;
226
+ this.state.camera.position.z = this.state.camera.target.z + dir.z * scale;
227
+ }
228
+ else {
229
+ // Perspective: scale distance
230
+ const newDistance = Math.max(0.1, distance * zoomFactor);
231
+ const scale = newDistance / distance;
232
+ this.state.camera.position.x = this.state.camera.target.x + dir.x * scale;
233
+ this.state.camera.position.y = this.state.camera.target.y + dir.y * scale;
234
+ this.state.camera.position.z = this.state.camera.target.z + dir.z * scale;
235
+ }
236
+ this.updateMatrices();
237
+ }
238
+ }
239
+ //# sourceMappingURL=camera-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-controls.js","sourceRoot":"","sources":["../src/camera-controls.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Camera projection utilities for screen/world coordinate conversion
3
+ * and view fitting. Extracted from Camera class using composition pattern.
4
+ */
5
+ import type { Vec3 } from './types.js';
6
+ import type { CameraInternalState } from './camera-controls.js';
7
+ /**
8
+ * Handles projection math: screen-to-world and world-to-screen conversions,
9
+ * bounding box fitting, and near/far plane management.
10
+ */
11
+ export declare class CameraProjection {
12
+ private readonly state;
13
+ private readonly updateMatrices;
14
+ constructor(state: CameraInternalState, updateMatrices: () => void);
15
+ /**
16
+ * Project a world position to screen coordinates
17
+ * @param worldPos - Position in world space
18
+ * @param canvasWidth - Canvas width in pixels
19
+ * @param canvasHeight - Canvas height in pixels
20
+ * @returns Screen coordinates { x, y } or null if behind camera
21
+ */
22
+ projectToScreen(worldPos: Vec3, canvasWidth: number, canvasHeight: number): {
23
+ x: number;
24
+ y: number;
25
+ } | null;
26
+ /**
27
+ * Unproject screen coordinates to a ray in world space
28
+ * @param screenX - X position in screen coordinates
29
+ * @param screenY - Y position in screen coordinates
30
+ * @param canvasWidth - Canvas width in pixels
31
+ * @param canvasHeight - Canvas height in pixels
32
+ * @returns Ray origin and direction in world space
33
+ */
34
+ unprojectToRay(screenX: number, screenY: number, canvasWidth: number, canvasHeight: number): {
35
+ origin: Vec3;
36
+ direction: Vec3;
37
+ };
38
+ /**
39
+ * Fit view to bounding box
40
+ * Sets camera to southeast isometric view (typical BIM starting view)
41
+ * Y-up coordinate system: Y is vertical
42
+ */
43
+ fitToBounds(min: Vec3, max: Vec3): void;
44
+ /**
45
+ * Update near/far planes dynamically based on camera distance.
46
+ * Now a no-op since updateMatrices() handles this automatically.
47
+ * Kept for API compatibility with CameraAnimator.
48
+ */
49
+ updateNearFarPlanes(_distance: number): void;
50
+ }
51
+ //# sourceMappingURL=camera-projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-projection.d.ts","sourceRoot":"","sources":["../src/camera-projection.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGhE;;;GAGG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBADd,KAAK,EAAE,mBAAmB,EAC1B,cAAc,EAAE,MAAM,IAAI;IAG7C;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAkC3G;;;;;;;OAOG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE;IA8D9H;;;;OAIG;IACH,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI;IA4BvC;;;;OAIG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG7C"}
@@ -0,0 +1,147 @@
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
+ import { MathUtils } from './math.js';
5
+ /**
6
+ * Handles projection math: screen-to-world and world-to-screen conversions,
7
+ * bounding box fitting, and near/far plane management.
8
+ */
9
+ export class CameraProjection {
10
+ state;
11
+ updateMatrices;
12
+ constructor(state, updateMatrices) {
13
+ this.state = state;
14
+ this.updateMatrices = updateMatrices;
15
+ }
16
+ /**
17
+ * Project a world position to screen coordinates
18
+ * @param worldPos - Position in world space
19
+ * @param canvasWidth - Canvas width in pixels
20
+ * @param canvasHeight - Canvas height in pixels
21
+ * @returns Screen coordinates { x, y } or null if behind camera
22
+ */
23
+ projectToScreen(worldPos, canvasWidth, canvasHeight) {
24
+ // Transform world position by view-projection matrix
25
+ const m = this.state.viewProjMatrix.m;
26
+ // Manual matrix-vector multiplication for vec4(worldPos, 1.0)
27
+ const clipX = m[0] * worldPos.x + m[4] * worldPos.y + m[8] * worldPos.z + m[12];
28
+ const clipY = m[1] * worldPos.x + m[5] * worldPos.y + m[9] * worldPos.z + m[13];
29
+ const clipZ = m[2] * worldPos.x + m[6] * worldPos.y + m[10] * worldPos.z + m[14];
30
+ const clipW = m[3] * worldPos.x + m[7] * worldPos.y + m[11] * worldPos.z + m[15];
31
+ // Check if behind camera
32
+ if (clipW <= 0) {
33
+ return null;
34
+ }
35
+ // Perspective divide to get NDC
36
+ const ndcX = clipX / clipW;
37
+ const ndcY = clipY / clipW;
38
+ const ndcZ = clipZ / clipW;
39
+ // Check if outside clip volume
40
+ if (ndcZ < -1 || ndcZ > 1) {
41
+ return null;
42
+ }
43
+ // Convert NDC to screen coordinates
44
+ // NDC: (-1,-1) = bottom-left, (1,1) = top-right
45
+ // Screen: (0,0) = top-left, (width, height) = bottom-right
46
+ const screenX = (ndcX + 1) * 0.5 * canvasWidth;
47
+ const screenY = (1 - ndcY) * 0.5 * canvasHeight; // Flip Y
48
+ return { x: screenX, y: screenY };
49
+ }
50
+ /**
51
+ * Unproject screen coordinates to a ray in world space
52
+ * @param screenX - X position in screen coordinates
53
+ * @param screenY - Y position in screen coordinates
54
+ * @param canvasWidth - Canvas width in pixels
55
+ * @param canvasHeight - Canvas height in pixels
56
+ * @returns Ray origin and direction in world space
57
+ */
58
+ unprojectToRay(screenX, screenY, canvasWidth, canvasHeight) {
59
+ // Convert screen coords to NDC (-1 to 1)
60
+ const ndcX = (screenX / canvasWidth) * 2 - 1;
61
+ const ndcY = 1 - (screenY / canvasHeight) * 2; // Flip Y
62
+ if (this.state.projectionMode === 'orthographic') {
63
+ // Orthographic: rays are parallel. Origin varies with screen position.
64
+ const halfH = this.state.orthoSize;
65
+ const halfW = halfH * this.state.camera.aspect;
66
+ // Forward direction (camera towards target)
67
+ const forward = MathUtils.normalize({
68
+ x: this.state.camera.target.x - this.state.camera.position.x,
69
+ y: this.state.camera.target.y - this.state.camera.position.y,
70
+ z: this.state.camera.target.z - this.state.camera.position.z,
71
+ });
72
+ // Right = forward x up
73
+ const right = MathUtils.normalize(MathUtils.cross(forward, this.state.camera.up));
74
+ // Actual up = right x forward
75
+ const actualUp = MathUtils.cross(right, forward);
76
+ // Ray origin: camera position offset by NDC * view extents
77
+ const origin = {
78
+ x: this.state.camera.position.x + right.x * ndcX * halfW + actualUp.x * ndcY * halfH,
79
+ y: this.state.camera.position.y + right.y * ndcX * halfW + actualUp.y * ndcY * halfH,
80
+ z: this.state.camera.position.z + right.z * ndcX * halfW + actualUp.z * ndcY * halfH,
81
+ };
82
+ return { origin, direction: forward };
83
+ }
84
+ // Perspective: ray origin is always the camera position
85
+ // Direction is computed through the screen point
86
+ // Invert the view-projection matrix
87
+ const invViewProj = MathUtils.invert(this.state.viewProjMatrix);
88
+ if (!invViewProj) {
89
+ // Fallback: return ray from camera position towards target
90
+ const dir = MathUtils.normalize({
91
+ x: this.state.camera.target.x - this.state.camera.position.x,
92
+ y: this.state.camera.target.y - this.state.camera.position.y,
93
+ z: this.state.camera.target.z - this.state.camera.position.z,
94
+ });
95
+ return { origin: { ...this.state.camera.position }, direction: dir };
96
+ }
97
+ // Unproject a point at some depth to get a point on the ray
98
+ // Using z=0.5 (midpoint in Reverse-Z: 1.0=near, 0.0=far) to get a finite point
99
+ const worldPoint = MathUtils.transformPoint(invViewProj, { x: ndcX, y: ndcY, z: 0.5 });
100
+ // Ray origin is camera position, direction is towards unprojected point
101
+ const origin = { ...this.state.camera.position };
102
+ const direction = MathUtils.normalize({
103
+ x: worldPoint.x - origin.x,
104
+ y: worldPoint.y - origin.y,
105
+ z: worldPoint.z - origin.z,
106
+ });
107
+ return { origin, direction };
108
+ }
109
+ /**
110
+ * Fit view to bounding box
111
+ * Sets camera to southeast isometric view (typical BIM starting view)
112
+ * Y-up coordinate system: Y is vertical
113
+ */
114
+ fitToBounds(min, max) {
115
+ const center = {
116
+ x: (min.x + max.x) / 2,
117
+ y: (min.y + max.y) / 2,
118
+ z: (min.z + max.z) / 2,
119
+ };
120
+ const size = {
121
+ x: max.x - min.x,
122
+ y: max.y - min.y,
123
+ z: max.z - min.z,
124
+ };
125
+ const maxSize = Math.max(size.x, size.y, size.z);
126
+ const distance = maxSize * 2.0;
127
+ this.state.camera.target = center;
128
+ // Southeast isometric view for Y-up:
129
+ // Position camera above and to the front-right of the model
130
+ this.state.camera.position = {
131
+ x: center.x + distance * 0.6, // Right
132
+ y: center.y + distance * 0.5, // Above
133
+ z: center.z + distance * 0.6, // Front
134
+ };
135
+ // near/far are computed dynamically in updateMatrices() based on distance
136
+ this.updateMatrices();
137
+ }
138
+ /**
139
+ * Update near/far planes dynamically based on camera distance.
140
+ * Now a no-op since updateMatrices() handles this automatically.
141
+ * Kept for API compatibility with CameraAnimator.
142
+ */
143
+ updateNearFarPlanes(_distance) {
144
+ // near/far are computed dynamically in Camera.updateMatrices()
145
+ }
146
+ }
147
+ //# sourceMappingURL=camera-projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-projection.js","sourceRoot":"","sources":["../src/camera-projection.ts"],"names":[],"mappings":"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"}