@ifc-lite/renderer 1.43.0 → 1.44.1
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-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 +75 -120
- package/dist/camera.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/fill-bridge-anchor.d.ts +32 -0
- package/dist/fill-bridge-anchor.d.ts.map +1 -0
- package/dist/fill-bridge-anchor.js +82 -0
- package/dist/fill-bridge-anchor.js.map +1 -0
- package/dist/fill-predicates.d.ts +44 -0
- package/dist/fill-predicates.d.ts.map +1 -0
- package/dist/fill-predicates.js +65 -0
- package/dist/fill-predicates.js.map +1 -0
- package/dist/fill-triangulate.d.ts +102 -0
- package/dist/fill-triangulate.d.ts.map +1 -0
- package/dist/fill-triangulate.js +333 -0
- package/dist/fill-triangulate.js.map +1 -0
- package/dist/index.d.ts +154 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +294 -45
- package/dist/index.js.map +1 -1
- package/dist/math.d.ts +49 -1
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +122 -67
- package/dist/math.js.map +1 -1
- package/dist/renderer-symbolic-overlays.d.ts.map +1 -1
- package/dist/renderer-symbolic-overlays.js +20 -25
- package/dist/renderer-symbolic-overlays.js.map +1 -1
- 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 +25 -0
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +91 -109
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-lift.d.ts +109 -0
- package/dist/section-2d-lift.d.ts.map +1 -0
- package/dist/section-2d-lift.js +168 -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 +28 -77
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +161 -593
- 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/symbolic-overlay-pipelines.d.ts +10 -39
- package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
- package/dist/symbolic-overlay-pipelines.js +20 -163
- package/dist/symbolic-overlay-pipelines.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,150 @@
|
|
|
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
|
+
* Smallest orthographic half-height the projection matrix is ever built from.
|
|
6
|
+
* Matches the floor the orthographic zoom clamps to in `CameraControls`.
|
|
7
|
+
*/
|
|
8
|
+
export const MIN_ORTHO_SIZE = 0.01;
|
|
9
|
+
/** Default orthographic half-height, in world units, and the neutral fallback. */
|
|
10
|
+
export const DEFAULT_ORTHO_SIZE = 50;
|
|
11
|
+
/**
|
|
12
|
+
* Is `dist` a usable camera-to-target radius — finite, and at least `min` away
|
|
13
|
+
* from zero so dividing by it means something?
|
|
14
|
+
*
|
|
15
|
+
* The navigation gestures all opened with a bare `dist < eps` early return.
|
|
16
|
+
* That is a magnitude test, not a finiteness test, so a malformed pose walked
|
|
17
|
+
* straight past it (#2441). Past the guard, the gesture writes its result into
|
|
18
|
+
* `camera.position` *and* `camera.target`, so a single non-finite coordinate
|
|
19
|
+
* (a BCF viewpoint restored from a file reaches the public setters
|
|
20
|
+
* unvalidated) spreads across all six on the first drag.
|
|
21
|
+
*
|
|
22
|
+
* Callers keep their own fallback: there is no single substitute distance that
|
|
23
|
+
* is right for all of them, which is also why `Camera.getDistance()` reports
|
|
24
|
+
* the pose verbatim rather than sanitizing it centrally.
|
|
25
|
+
*/
|
|
26
|
+
export function isUsableDistance(dist, min) {
|
|
27
|
+
return Number.isFinite(dist) && dist >= min;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Is `up` a usable screen-up reference — every component finite?
|
|
31
|
+
*
|
|
32
|
+
* `up` is the third vector of the pose, and it reaches the camera exactly the
|
|
33
|
+
* way `position` and `target` do: BCF stores `CameraUpVector`, `bcfToViewerCoords`
|
|
34
|
+
* only swaps axes, and `applyViewpoint` writes the result straight through
|
|
35
|
+
* (`animateToWithUp` on the animated path — which bypasses `setUp` entirely —
|
|
36
|
+
* or `setUp` on the instant one).
|
|
37
|
+
*
|
|
38
|
+
* Finiteness only, deliberately no magnitude floor. `normalize` already absorbs
|
|
39
|
+
* a zero-length or degenerate `up` by returning `{0,0,0}`, and a *short* `up` is
|
|
40
|
+
* a valid input whose direction is perfectly well defined — `MathUtils.lookAt`
|
|
41
|
+
* documents the same thing and keys its own degeneracy test on the angle rather
|
|
42
|
+
* than a length for exactly this reason. A floor here would silently drop the
|
|
43
|
+
* cursor anchor for poses that navigate correctly today.
|
|
44
|
+
*
|
|
45
|
+
* The floor `normalize` used to have was a *lower* bound, which is what left
|
|
46
|
+
* the gap: `len > 1e-10` is false for NaN (so a NaN `up` degraded safely to
|
|
47
|
+
* the zero vector) but **true for Infinity**, and scaling infinite components
|
|
48
|
+
* by `1 / Infinity` is `Infinity * 0` — NaN. Measured, not reasoned: `up`
|
|
49
|
+
* `(Infinity, 1, 0)` on a finite pose came back from one cursor-anchored zoom
|
|
50
|
+
* with position AND target `(NaN, NaN, NaN)`, in both projection modes (#2441).
|
|
51
|
+
* Both copies of `normalize` now key that floor on `Number.isFinite` too
|
|
52
|
+
* (#2479), so an unusable `up` reaches the same zero vector by either route —
|
|
53
|
+
* this predicate says so at the top of the gesture rather than relying on a
|
|
54
|
+
* helper's degradation three lines in, and it is what stops the *pose* being
|
|
55
|
+
* rewritten from a basis that carries no orientation.
|
|
56
|
+
*
|
|
57
|
+
* As with {@link isUsableDistance}, the caller keeps its own fallback and the
|
|
58
|
+
* pose is left exactly as it was found — `getUp()` still reports the malformed
|
|
59
|
+
* vector, so a restored viewpoint is not silently rewritten on its way back out.
|
|
60
|
+
*/
|
|
61
|
+
export function isUsableUp(up) {
|
|
62
|
+
return Number.isFinite(up.x) && Number.isFinite(up.y) && Number.isFinite(up.z);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clamp an orthographic half-height, rejecting a non-finite one.
|
|
66
|
+
*
|
|
67
|
+
* `Math.max`/`Math.min` are NaN-transparent, so a clamp alone does not stop a
|
|
68
|
+
* malformed value reaching the projection matrix (#2441). Returns `null` when
|
|
69
|
+
* there is no usable size, so the caller can keep the value it already had
|
|
70
|
+
* rather than substitute an arbitrary one.
|
|
71
|
+
*
|
|
72
|
+
* The `Infinity` rejection is not theoretical: `orthoSize` is scaled in place
|
|
73
|
+
* by the orthographic zoom, so a legitimately huge but finite half-height
|
|
74
|
+
* overflows to `Infinity` after enough zoom-out notches, and
|
|
75
|
+
* `Math.max(MIN_ORTHO_SIZE, Infinity)` is `Infinity`.
|
|
76
|
+
*/
|
|
77
|
+
export function usableOrthoSize(size) {
|
|
78
|
+
return Number.isFinite(size) ? Math.max(MIN_ORTHO_SIZE, size) : null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Are all of `values` finite?
|
|
82
|
+
*
|
|
83
|
+
* The gesture *arguments* — wheel deltas, pointer deltas, walk axes — are a
|
|
84
|
+
* different input class from the pose the gestures already guard (#2473), and
|
|
85
|
+
* they reach the same arithmetic. Measured on the pre-guard code: `orbit(NaN,
|
|
86
|
+
* 0)`, `pan(NaN, 0)`, `zoom(NaN)` and `moveFirstPerson(NaN, 0, 0)` each turned
|
|
87
|
+
* a perfectly finite pose into a non-finite one in a single call, and
|
|
88
|
+
* `orbit(Infinity, 0)` / `pan(Infinity, 0)` / `moveFirstPerson(Infinity, 0, 0)`
|
|
89
|
+
* did the same — the two do **not** behave alike everywhere, so both must be
|
|
90
|
+
* tested. (`zoom` is the exception: its delta is clamped by
|
|
91
|
+
* `Math.min(|delta| * s, MAX_ZOOM_DELTA)`, which absorbs `Infinity` but not
|
|
92
|
+
* `NaN`.)
|
|
93
|
+
*/
|
|
94
|
+
export function areFiniteNumbers(...values) {
|
|
95
|
+
for (const v of values) {
|
|
96
|
+
if (!Number.isFinite(v))
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Is this a usable cursor anchor — a finite cursor position inside a viewport
|
|
103
|
+
* with a real extent?
|
|
104
|
+
*
|
|
105
|
+
* The cursor-anchored zoom divides by the canvas dimensions, so they need
|
|
106
|
+
* `> 0` and not merely "truthy". Truthiness already rejects `0` and `NaN`
|
|
107
|
+
* (both falsy) which is why a collapsed canvas never reached the division, but
|
|
108
|
+
* it accepts `Infinity` and a negative width — the latter mirrors the anchor
|
|
109
|
+
* and drifts the target the wrong way. `Number.isFinite(w) && w > 0` is the
|
|
110
|
+
* check that means what the division needs.
|
|
111
|
+
*/
|
|
112
|
+
export function isUsableCursorAnchor(cursorX, cursorY, viewportWidth, viewportHeight) {
|
|
113
|
+
return (areFiniteNumbers(cursorX, cursorY, viewportWidth, viewportHeight) &&
|
|
114
|
+
viewportWidth > 0 &&
|
|
115
|
+
viewportHeight > 0);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Is this AABB something the camera can be fitted to?
|
|
119
|
+
*
|
|
120
|
+
* Two rejections, and they are different failures:
|
|
121
|
+
*
|
|
122
|
+
* - **Non-finite corners.** Fitting computes `center = (min + max) / 2` and
|
|
123
|
+
* `size = max - min`, and writes both into the pose. `Math.max` picking the
|
|
124
|
+
* largest extent is NaN-transparent, so one bad coordinate reaches
|
|
125
|
+
* `camera.position`, `camera.target` *and* (in orthographic mode)
|
|
126
|
+
* `orthoSize`, which `getOrthoSize()` then hands to a saved viewpoint —
|
|
127
|
+
* persisting the damage past the session (#2461).
|
|
128
|
+
* - **An inverted box** (`max < min` on any axis). That is the empty-AABB
|
|
129
|
+
* sentinel every accumulator in this package starts from (`min = +Infinity,
|
|
130
|
+
* max = -Infinity`) leaking out as if it were a real box, which is what a
|
|
131
|
+
* mesh with no finite vertices produces. Its centre is `NaN` and its size
|
|
132
|
+
* is negative; there is nothing to frame.
|
|
133
|
+
*
|
|
134
|
+
* A *degenerate* box (`max === min` on some or all axes — a flat wall, a
|
|
135
|
+
* single point) is explicitly **not** rejected: it is a legitimate thing to
|
|
136
|
+
* frame and `frameBounds` already centres on it.
|
|
137
|
+
*
|
|
138
|
+
* The answer to an unusable box is to reject the fit and leave the pose alone,
|
|
139
|
+
* not to clamp: there is no meaningful substitute for an infinite or inverted
|
|
140
|
+
* extent, and no previous bounds to fall back to at these entry points, which
|
|
141
|
+
* are stateless. Keeping the pose the user already had is the same policy
|
|
142
|
+
* `setAspect`, `setFOV` and `setOrthoSize` settled on (#2441/#2450).
|
|
143
|
+
*/
|
|
144
|
+
export function isUsableBounds(min, max) {
|
|
145
|
+
return (areFiniteNumbers(min.x, min.y, min.z, max.x, max.y, max.z) &&
|
|
146
|
+
max.x >= min.x &&
|
|
147
|
+
max.y >= min.y &&
|
|
148
|
+
max.z >= min.z);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=camera-guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-guards.js","sourceRoot":"","sources":["../src/camera-guards.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA0B/D;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC,kFAAkF;AAClF,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAW;IACxD,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,UAAU,CAAC,EAAQ;IACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAG,MAAgB;IAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,OAAe,EACf,aAAqB,EACrB,cAAsB;IAEtB,OAAO,CACL,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,CAAC;QACjE,aAAa,GAAG,CAAC;QACjB,cAAc,GAAG,CAAC,CACnB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,cAAc,CAAC,GAAS,EAAE,GAAS;IACjD,OAAO,CACL,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1D,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CameraInternalState } from './camera-state.js';
|
|
2
|
+
export declare function updateCameraMatrices(state: CameraInternalState): void;
|
|
3
|
+
/**
|
|
4
|
+
* Compute tight near/far for orthographic mode by projecting the scene
|
|
5
|
+
* bounding sphere onto the camera view direction.
|
|
6
|
+
*
|
|
7
|
+
* This gives optimal depth precision (minimizing z-fighting) while ensuring
|
|
8
|
+
* no geometry is clipped regardless of camera position or view angle.
|
|
9
|
+
*/
|
|
10
|
+
export declare function computeOrthoNearFar(state: CameraInternalState, distance: number): {
|
|
11
|
+
near: number;
|
|
12
|
+
far: number;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=camera-matrices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-matrices.d.ts","sourceRoot":"","sources":["../src/camera-matrices.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CA4DrE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAyE/B"}
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
* View / projection / view-projection matrix derivation.
|
|
6
|
+
*
|
|
7
|
+
* One subject: camera state in, three finite matrices out. Its failure story
|
|
8
|
+
* is the #2441 near/far backstops — a non-finite pose or `orthoSize` must not
|
|
9
|
+
* reach the projection matrix, because `MathUtils.lookAt` scrubs the *view*
|
|
10
|
+
* matrix but nothing scrubs the projection one, and a NaN there leaves the
|
|
11
|
+
* viewport dead while every other reading looks healthy.
|
|
12
|
+
*
|
|
13
|
+
* **Hot path.** `updateCameraMatrices` runs on every frame the camera moves.
|
|
14
|
+
* It takes the shared state object **by reference** and nothing else: do not
|
|
15
|
+
* destructure it into parameters (that allocates an arguments object per
|
|
16
|
+
* frame) and do not widen the parameter to a structural supertype (that
|
|
17
|
+
* invites megamorphic dispatch). The allocation profile is deliberately
|
|
18
|
+
* unchanged from the method this replaced — `lookAt`, `perspectiveReverseZ` /
|
|
19
|
+
* `orthographicReverseZ` and `multiply` each already return a fresh `Mat4`,
|
|
20
|
+
* and the ortho branch already returned a fresh `{near, far}` per frame.
|
|
21
|
+
*/
|
|
22
|
+
import { MathUtils } from './math.js';
|
|
23
|
+
import { DEFAULT_ORTHO_SIZE, usableOrthoSize } from './camera-guards.js';
|
|
24
|
+
export function updateCameraMatrices(state) {
|
|
25
|
+
const dx = state.camera.position.x - state.camera.target.x;
|
|
26
|
+
const dy = state.camera.position.y - state.camera.target.y;
|
|
27
|
+
const dz = state.camera.position.z - state.camera.target.z;
|
|
28
|
+
const rawDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
29
|
+
// A non-finite position or target — a malformed BCF viewpoint reaches the
|
|
30
|
+
// public setters unvalidated — would put NaN into near/far and from there
|
|
31
|
+
// into the projection matrix, leaving the viewport dead even though
|
|
32
|
+
// `MathUtils.lookAt` scrubs the view matrix (#2441). Fall back to a
|
|
33
|
+
// neutral distance so the projection stays finite; the camera state itself
|
|
34
|
+
// is left as the caller set it.
|
|
35
|
+
const distance = Number.isFinite(rawDistance) ? rawDistance : 1;
|
|
36
|
+
state.viewMatrix = MathUtils.lookAt(state.camera.position, state.camera.target, state.camera.up);
|
|
37
|
+
if (state.projectionMode === 'orthographic') {
|
|
38
|
+
// Orthographic: project scene bounding sphere onto view direction for tight near/far.
|
|
39
|
+
// Tight range maximizes depth precision (less z-fighting) and prevents clipping.
|
|
40
|
+
const nf = computeOrthoNearFar(state, distance);
|
|
41
|
+
state.camera.near = nf.near;
|
|
42
|
+
state.camera.far = nf.far;
|
|
43
|
+
// Backstop for the writers that never see `setOrthoSize`'s clamp: the
|
|
44
|
+
// orthographic zoom scales `orthoSize` in place and the animator
|
|
45
|
+
// interpolates it, so a NaN reaching either (from a malformed pose, or
|
|
46
|
+
// from bounds that were themselves non-finite) would land straight in
|
|
47
|
+
// the projection matrix. Same fallback shape as the distance above.
|
|
48
|
+
//
|
|
49
|
+
// Finiteness alone is not the whole backstop: `Number.isFinite(0)` is
|
|
50
|
+
// true, and a zero — or negative — half-height makes `right - left` and
|
|
51
|
+
// `top - bottom` zero, so `orthographicReverseZ` divides by zero and the
|
|
52
|
+
// matrix comes back with `Infinity` scale terms. That is the same dead
|
|
53
|
+
// viewport as a NaN, reached through a *valid-but-falsy* value rather
|
|
54
|
+
// than an exotic one. `usableOrthoSize` is the single predicate that says
|
|
55
|
+
// both things at once, and it is the same one every writer already goes
|
|
56
|
+
// through — so this backstop now enforces exactly the invariant the
|
|
57
|
+
// writers promise rather than half of it (#2441).
|
|
58
|
+
const h = usableOrthoSize(state.orthoSize) ?? DEFAULT_ORTHO_SIZE;
|
|
59
|
+
const w = h * state.camera.aspect;
|
|
60
|
+
state.projMatrix = MathUtils.orthographicReverseZ(-w, w, -h, h, state.camera.near, state.camera.far);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Perspective: adapt near/far based on camera-to-target distance
|
|
64
|
+
state.camera.near = Math.max(0.01, distance * 0.001);
|
|
65
|
+
state.camera.far = Math.max(distance * 10, 1000);
|
|
66
|
+
state.projMatrix = MathUtils.perspectiveReverseZ(state.camera.fov, state.camera.aspect, state.camera.near, state.camera.far);
|
|
67
|
+
}
|
|
68
|
+
state.viewProjMatrix = MathUtils.multiply(state.projMatrix, state.viewMatrix);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compute tight near/far for orthographic mode by projecting the scene
|
|
72
|
+
* bounding sphere onto the camera view direction.
|
|
73
|
+
*
|
|
74
|
+
* This gives optimal depth precision (minimizing z-fighting) while ensuring
|
|
75
|
+
* no geometry is clipped regardless of camera position or view angle.
|
|
76
|
+
*/
|
|
77
|
+
export function computeOrthoNearFar(state, distance) {
|
|
78
|
+
const bounds = state.sceneBounds;
|
|
79
|
+
if (!bounds) {
|
|
80
|
+
// Fallback: generous range centered on camera
|
|
81
|
+
return { near: -Math.max(distance, 500), far: Math.max(distance, 500) };
|
|
82
|
+
}
|
|
83
|
+
// Scene bounding sphere center and radius
|
|
84
|
+
const cx = (bounds.min.x + bounds.max.x) / 2;
|
|
85
|
+
const cy = (bounds.min.y + bounds.max.y) / 2;
|
|
86
|
+
const cz = (bounds.min.z + bounds.max.z) / 2;
|
|
87
|
+
const ex = bounds.max.x - bounds.min.x;
|
|
88
|
+
const ey = bounds.max.y - bounds.min.y;
|
|
89
|
+
const ez = bounds.max.z - bounds.min.z;
|
|
90
|
+
const radius = Math.sqrt(ex * ex + ey * ey + ez * ez) / 2;
|
|
91
|
+
// View direction (camera looks from position toward target)
|
|
92
|
+
const pos = state.camera.position;
|
|
93
|
+
let vx = state.camera.target.x - pos.x;
|
|
94
|
+
let vy = state.camera.target.y - pos.y;
|
|
95
|
+
let vz = state.camera.target.z - pos.z;
|
|
96
|
+
const vLen = Math.sqrt(vx * vx + vy * vy + vz * vz);
|
|
97
|
+
// Add 10% padding for safety.
|
|
98
|
+
const pad = radius * 0.1 + 1;
|
|
99
|
+
let near;
|
|
100
|
+
let far;
|
|
101
|
+
if (Number.isFinite(vLen) && vLen > 1e-8) {
|
|
102
|
+
vx /= vLen;
|
|
103
|
+
vy /= vLen;
|
|
104
|
+
vz /= vLen;
|
|
105
|
+
// Signed distance from camera to scene center along view direction
|
|
106
|
+
const toCenter = (cx - pos.x) * vx + (cy - pos.y) * vy + (cz - pos.z) * vz;
|
|
107
|
+
// Near/far as distances from camera along view direction.
|
|
108
|
+
// The sphere spans [toCenter - radius, toCenter + radius] along view dir.
|
|
109
|
+
near = toCenter - radius - pad;
|
|
110
|
+
far = toCenter + radius + pad;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// No view direction to project onto — position and target coincide, or
|
|
114
|
+
// the pose is non-finite. Skipping the normalization (which is what the
|
|
115
|
+
// bare `vLen > 1e-8` did) left `v` at its raw near-zero value, so
|
|
116
|
+
// `toCenter` collapsed to ~0 and the range came out centred on the
|
|
117
|
+
// *camera* rather than on the scene: a camera parked 1000 units away got
|
|
118
|
+
// `[-(r + pad), +(r + pad)]` and clipped the entire model away, which is
|
|
119
|
+
// a blank viewport reached through a range that is perfectly finite and
|
|
120
|
+
// therefore sails past the non-finite backstop below.
|
|
121
|
+
//
|
|
122
|
+
// There is no honest direction to substitute either: `MathUtils.lookAt`
|
|
123
|
+
// picks its own fallback basis for a degenerate pose, and any axis chosen
|
|
124
|
+
// here could disagree with the one the frame is actually drawn from.
|
|
125
|
+
// Bracket the whole bounding sphere symmetrically instead — that contains
|
|
126
|
+
// the scene whichever way `lookAt` ended up looking.
|
|
127
|
+
const span = Math.sqrt((cx - pos.x) * (cx - pos.x) +
|
|
128
|
+
(cy - pos.y) * (cy - pos.y) +
|
|
129
|
+
(cz - pos.z) * (cz - pos.z)) + radius + pad;
|
|
130
|
+
near = -span;
|
|
131
|
+
far = span;
|
|
132
|
+
}
|
|
133
|
+
// Ensure minimum range for depth precision
|
|
134
|
+
if (far - near < 1) {
|
|
135
|
+
near -= 0.5;
|
|
136
|
+
far += 0.5;
|
|
137
|
+
}
|
|
138
|
+
// Same contract as the perspective branch: a non-finite camera position or
|
|
139
|
+
// scene bound must not reach the projection matrix (#2441).
|
|
140
|
+
if (!Number.isFinite(near) || !Number.isFinite(far)) {
|
|
141
|
+
const fallback = Math.max(Number.isFinite(distance) ? distance : 0, 500);
|
|
142
|
+
return { near: -fallback, far: fallback };
|
|
143
|
+
}
|
|
144
|
+
return { near, far };
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=camera-matrices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-matrices.js","sourceRoot":"","sources":["../src/camera-matrices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset views: the ViewCube's six named directions, plus the admission check
|
|
3
|
+
* that decides whether a preset may be applied at all.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `camera-framing.ts`, which owns the *free* framing pickers
|
|
6
|
+
* (point / bounds / extents — "put the camera on this thing, keeping the
|
|
7
|
+
* current direction"). Presets are the opposite subject: the direction is
|
|
8
|
+
* dictated by the named face and the caller's rotation cycle, and the box is
|
|
9
|
+
* whatever the caller supplied or whatever the current pose implies. The two
|
|
10
|
+
* share only box arithmetic, which is why this module imports `centerOf` /
|
|
11
|
+
* `maxExtentOf` rather than owning a second copy.
|
|
12
|
+
*
|
|
13
|
+
* Pure by construction, exactly as `camera-framing.ts` is: everything here
|
|
14
|
+
* reads `CameraInternalState` and returns a target, nothing writes to it or
|
|
15
|
+
* touches the tween. That is what keeps both modules free of a cycle back into
|
|
16
|
+
* `camera-animation.ts`, which is the one that applies the results.
|
|
17
|
+
*
|
|
18
|
+
* **Guard placement.** `resolvePresetBounds` validates the box exactly once,
|
|
19
|
+
* here, and a rejection is `null`. Callers null-check and do nothing else: a
|
|
20
|
+
* second, defensive copy of the same guard in the caller would mean neither
|
|
21
|
+
* copy is load-bearing on its own, and the mutation test that pins this guard
|
|
22
|
+
* would go quiet while still looking green.
|
|
23
|
+
*/
|
|
24
|
+
import type { Vec3 } from './types.js';
|
|
25
|
+
import type { CameraInternalState } from './camera-state.js';
|
|
26
|
+
import { type FramingBounds } from './camera-framing.js';
|
|
27
|
+
/**
|
|
28
|
+
* Get current bounds estimate (simplified - in production would use scene bounds).
|
|
29
|
+
*/
|
|
30
|
+
export declare function estimateBoundsFromPose(state: CameraInternalState): FramingBounds;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the box a preset view should fit, from the caller's bounds or the
|
|
33
|
+
* current pose, and reject it if it is not usable.
|
|
34
|
+
*
|
|
35
|
+
* This is the whole admission decision for `setPresetView`, deliberately kept
|
|
36
|
+
* ahead of the rotation-cycling counter: a rejected preset must not advance
|
|
37
|
+
* the cycle, and the caller can only honour that if the verdict arrives before
|
|
38
|
+
* it mutates anything.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolvePresetBounds(state: CameraInternalState, bounds?: FramingBounds): FramingBounds | null;
|
|
41
|
+
/**
|
|
42
|
+
* Pose for a preset view (Y-up coordinate system).
|
|
43
|
+
*
|
|
44
|
+
* `bounds` must already have passed {@link resolvePresetBounds}; `rotation` is
|
|
45
|
+
* the caller's 0-3 cycle position, which is why this takes it rather than
|
|
46
|
+
* owning it — the counter belongs to the animator, which is what remembers
|
|
47
|
+
* that the same face was clicked twice.
|
|
48
|
+
*
|
|
49
|
+
* @param buildingRotation Optional building rotation in radians (from IfcSite placement)
|
|
50
|
+
*/
|
|
51
|
+
export declare function presetViewTarget(state: CameraInternalState, view: 'top' | 'bottom' | 'front' | 'back' | 'left' | 'right', bounds: FramingBounds, rotation: number, buildingRotation?: number): {
|
|
52
|
+
position: Vec3;
|
|
53
|
+
target: Vec3;
|
|
54
|
+
up: Vec3;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=camera-preset-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-preset-view.d.ts","sourceRoot":"","sources":["../src/camera-preset-view.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEhG;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,aAAa,CAsBhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,EAC1B,MAAM,CAAC,EAAE,aAAa,GACrB,aAAa,GAAG,IAAI,CAYtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,mBAAmB,EAC1B,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC5D,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,gBAAgB,CAAC,EAAE,MAAM,GACxB;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CA0H5C"}
|
|
@@ -0,0 +1,180 @@
|
|
|
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 { isUsableBounds } from './camera-guards.js';
|
|
5
|
+
import { centerOf, fitDistanceFor, maxExtentOf } from './camera-framing.js';
|
|
6
|
+
/**
|
|
7
|
+
* Get current bounds estimate (simplified - in production would use scene bounds).
|
|
8
|
+
*/
|
|
9
|
+
export function estimateBoundsFromPose(state) {
|
|
10
|
+
// Estimate bounds from camera distance
|
|
11
|
+
const dir = {
|
|
12
|
+
x: state.camera.position.x - state.camera.target.x,
|
|
13
|
+
y: state.camera.position.y - state.camera.target.y,
|
|
14
|
+
z: state.camera.position.z - state.camera.target.z,
|
|
15
|
+
};
|
|
16
|
+
const distance = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
17
|
+
const size = distance / 2;
|
|
18
|
+
return {
|
|
19
|
+
min: {
|
|
20
|
+
x: state.camera.target.x - size,
|
|
21
|
+
y: state.camera.target.y - size,
|
|
22
|
+
z: state.camera.target.z - size,
|
|
23
|
+
},
|
|
24
|
+
max: {
|
|
25
|
+
x: state.camera.target.x + size,
|
|
26
|
+
y: state.camera.target.y + size,
|
|
27
|
+
z: state.camera.target.z + size,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the box a preset view should fit, from the caller's bounds or the
|
|
33
|
+
* current pose, and reject it if it is not usable.
|
|
34
|
+
*
|
|
35
|
+
* This is the whole admission decision for `setPresetView`, deliberately kept
|
|
36
|
+
* ahead of the rotation-cycling counter: a rejected preset must not advance
|
|
37
|
+
* the cycle, and the caller can only honour that if the verdict arrives before
|
|
38
|
+
* it mutates anything.
|
|
39
|
+
*/
|
|
40
|
+
export function resolvePresetBounds(state, bounds) {
|
|
41
|
+
const useBounds = bounds || estimateBoundsFromPose(state);
|
|
42
|
+
// Both sources need the check, not just the caller's: the pose-derived
|
|
43
|
+
// estimate above starts from the live pose, so a pose that is already
|
|
44
|
+
// malformed produces a malformed box and the ViewCube would then bake it in
|
|
45
|
+
// permanently. Rejecting leaves the preset un-applied, which keeps a
|
|
46
|
+
// recoverable pose recoverable (#2461).
|
|
47
|
+
if (!isUsableBounds(useBounds.min, useBounds.max)) {
|
|
48
|
+
console.warn('[Camera] Non-finite bounds for setPresetView; keeping current view');
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return useBounds;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Pose for a preset view (Y-up coordinate system).
|
|
55
|
+
*
|
|
56
|
+
* `bounds` must already have passed {@link resolvePresetBounds}; `rotation` is
|
|
57
|
+
* the caller's 0-3 cycle position, which is why this takes it rather than
|
|
58
|
+
* owning it — the counter belongs to the animator, which is what remembers
|
|
59
|
+
* that the same face was clicked twice.
|
|
60
|
+
*
|
|
61
|
+
* @param buildingRotation Optional building rotation in radians (from IfcSite placement)
|
|
62
|
+
*/
|
|
63
|
+
export function presetViewTarget(state, view, bounds, rotation, buildingRotation) {
|
|
64
|
+
const center = centerOf(bounds.min, bounds.max);
|
|
65
|
+
const maxSize = maxExtentOf(bounds.min, bounds.max);
|
|
66
|
+
// Calculate distance based on FOV for proper fit. Aspect-aware: on a
|
|
67
|
+
// portrait viewport the horizontal field is the narrower one, and a preset
|
|
68
|
+
// fitted to the vertical field alone overflows it. See `fitDistanceFor`.
|
|
69
|
+
const distance = fitDistanceFor(state, maxSize, 1.5); // 1.5x for padding
|
|
70
|
+
let endPos;
|
|
71
|
+
const endTarget = center;
|
|
72
|
+
// WebGL uses Y-up coordinate system internally
|
|
73
|
+
// We set both position AND up vector for proper orthogonal views
|
|
74
|
+
let upVector = { x: 0, y: 1, z: 0 }; // Default Y-up
|
|
75
|
+
// Apply building rotation if present (rotate around Y axis).
|
|
76
|
+
//
|
|
77
|
+
// Normalized rather than trusted: this is the IfcSite placement angle,
|
|
78
|
+
// derived from the file and threaded through `Camera.setPresetView` — the
|
|
79
|
+
// published entry point — without ever meeting a guard. `Math.cos(NaN)` is
|
|
80
|
+
// NaN, and the four horizontal presets multiply it straight into `endPos`,
|
|
81
|
+
// so a malformed placement would send the ViewCube to a non-finite pose. A
|
|
82
|
+
// zero rotation is the same answer as "no rotation supplied", which is what
|
|
83
|
+
// the undefined case already resolves to.
|
|
84
|
+
const rotationRadians = Number.isFinite(buildingRotation) ? buildingRotation : 0;
|
|
85
|
+
const cosR = rotationRadians !== 0 ? Math.cos(rotationRadians) : 1.0;
|
|
86
|
+
const sinR = rotationRadians !== 0 ? Math.sin(rotationRadians) : 0.0;
|
|
87
|
+
switch (view) {
|
|
88
|
+
case 'top': {
|
|
89
|
+
// Top view: position camera *just barely* off the +Y pole so the
|
|
90
|
+
// subsequent orbit math has a well-defined polar tangent (no pole
|
|
91
|
+
// singularity). camera.up stays world Y throughout — screen-up is
|
|
92
|
+
// then determined by lookAt projecting (0,1,0) onto perp(look),
|
|
93
|
+
// which falls along the horizontal component of `-look`.
|
|
94
|
+
//
|
|
95
|
+
// The 4 rotation cycles select which compass direction appears at
|
|
96
|
+
// the top of the screen by varying the small horizontal offset
|
|
97
|
+
// (theta in the spherical math).
|
|
98
|
+
// rotation 0 → camera slightly to +Z of center → screen-up = +Z
|
|
99
|
+
// rotation 1 → camera slightly to +X → screen-up = +X
|
|
100
|
+
// rotation 2 → camera slightly to -Z → screen-up = -Z
|
|
101
|
+
// rotation 3 → camera slightly to -X → screen-up = -X
|
|
102
|
+
// Building rotation is applied as the same Y-axis rotation that
|
|
103
|
+
// setPresetView would have used to remap the legacy up vector.
|
|
104
|
+
const poleOffset = Math.sin(0.01) * distance; // ~0.6° tilt
|
|
105
|
+
const verticalOffset = Math.cos(0.01) * distance;
|
|
106
|
+
// `?? 0`: `rotation` is the animator's 0-3 cycle counter today, but it
|
|
107
|
+
// is a plain `number` on the signature, and an out-of-range, fractional
|
|
108
|
+
// or non-finite one indexes past the table and makes `thetaWorld` — and
|
|
109
|
+
// with it the whole preset pose — NaN.
|
|
110
|
+
const thetaPerRotation = [0, Math.PI / 2, Math.PI, -Math.PI / 2];
|
|
111
|
+
const thetaWorld = (thetaPerRotation[rotation] ?? 0) + rotationRadians;
|
|
112
|
+
endPos = {
|
|
113
|
+
x: center.x + poleOffset * Math.sin(thetaWorld),
|
|
114
|
+
y: center.y + verticalOffset,
|
|
115
|
+
z: center.z + poleOffset * Math.cos(thetaWorld),
|
|
116
|
+
};
|
|
117
|
+
upVector = { x: 0, y: 1, z: 0 };
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case 'bottom': {
|
|
121
|
+
// Bottom view: mirror of top — phi = π − MIN_PHI.
|
|
122
|
+
const poleOffset = Math.sin(0.01) * distance;
|
|
123
|
+
const verticalOffset = Math.cos(0.01) * distance;
|
|
124
|
+
const thetaPerRotation = [Math.PI, Math.PI / 2, 0, -Math.PI / 2];
|
|
125
|
+
const thetaWorld = (thetaPerRotation[rotation] ?? 0) + rotationRadians;
|
|
126
|
+
endPos = {
|
|
127
|
+
x: center.x + poleOffset * Math.sin(thetaWorld),
|
|
128
|
+
y: center.y - verticalOffset,
|
|
129
|
+
z: center.z + poleOffset * Math.cos(thetaWorld),
|
|
130
|
+
};
|
|
131
|
+
upVector = { x: 0, y: 1, z: 0 };
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case 'front':
|
|
135
|
+
// Front view: from +Z looking at model
|
|
136
|
+
// Rotate camera position around Y axis by building rotation
|
|
137
|
+
// Standard rotation: x' = x*cos - z*sin, z' = x*sin + z*cos
|
|
138
|
+
// For +Z direction (0,0,1): x' = -sin, z' = cos
|
|
139
|
+
// But we need to look at building's front, so use negative rotation
|
|
140
|
+
endPos = {
|
|
141
|
+
x: center.x + sinR * distance,
|
|
142
|
+
y: center.y,
|
|
143
|
+
z: center.z + cosR * distance,
|
|
144
|
+
};
|
|
145
|
+
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
146
|
+
break;
|
|
147
|
+
case 'back':
|
|
148
|
+
// Back view: from -Z looking at model
|
|
149
|
+
// For -Z direction (0,0,-1) rotated: x' = sin, z' = -cos
|
|
150
|
+
endPos = {
|
|
151
|
+
x: center.x - sinR * distance,
|
|
152
|
+
y: center.y,
|
|
153
|
+
z: center.z - cosR * distance,
|
|
154
|
+
};
|
|
155
|
+
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
156
|
+
break;
|
|
157
|
+
case 'left':
|
|
158
|
+
// Left view: from -X looking at model
|
|
159
|
+
// For -X direction (-1,0,0) rotated: x' = -cos, z' = sin
|
|
160
|
+
endPos = {
|
|
161
|
+
x: center.x - cosR * distance,
|
|
162
|
+
y: center.y,
|
|
163
|
+
z: center.z + sinR * distance,
|
|
164
|
+
};
|
|
165
|
+
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
166
|
+
break;
|
|
167
|
+
case 'right':
|
|
168
|
+
// Right view: from +X looking at model
|
|
169
|
+
// For +X direction (1,0,0) rotated: x' = cos, z' = -sin
|
|
170
|
+
endPos = {
|
|
171
|
+
x: center.x + cosR * distance,
|
|
172
|
+
y: center.y,
|
|
173
|
+
z: center.z - sinR * distance,
|
|
174
|
+
};
|
|
175
|
+
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
return { position: endPos, target: endTarget, up: upVector };
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=camera-preset-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-preset-view.js","sourceRoot":"","sources":["../src/camera-preset-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* and view fitting. Extracted from Camera class using composition pattern.
|
|
4
4
|
*/
|
|
5
5
|
import type { Vec3 } from './types.js';
|
|
6
|
-
import type { CameraInternalState } from './camera-
|
|
6
|
+
import type { CameraInternalState } from './camera-state.js';
|
|
7
7
|
/**
|
|
8
8
|
* Handles projection math: screen-to-world and world-to-screen conversions,
|
|
9
9
|
* bounding box fitting, and near/far plane management.
|
|
@@ -1 +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,
|
|
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,mBAAmB,CAAC;AAkB7D;;;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;IAkG9H;;;;OAIG;IACH,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI;IAiCvC;;;;OAIG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG7C"}
|