@ifc-lite/renderer 1.49.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/camera-animation.d.ts.map +1 -1
- package/dist/camera-animation.js +37 -27
- package/dist/camera-animation.js.map +1 -1
- package/dist/camera-controls.d.ts +26 -15
- package/dist/camera-controls.d.ts.map +1 -1
- package/dist/camera-controls.js +32 -18
- package/dist/camera-controls.js.map +1 -1
- package/dist/camera-framing.d.ts +60 -21
- package/dist/camera-framing.d.ts.map +1 -1
- package/dist/camera-framing.js +168 -131
- package/dist/camera-framing.js.map +1 -1
- package/dist/camera-preset-view.d.ts +2 -2
- package/dist/camera-preset-view.d.ts.map +1 -1
- package/dist/camera-preset-view.js +52 -42
- package/dist/camera-preset-view.js.map +1 -1
- package/dist/camera.d.ts +50 -6
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +113 -13
- package/dist/camera.js.map +1 -1
- package/dist/device.d.ts +11 -0
- package/dist/device.d.ts.map +1 -1
- package/dist/device.js +71 -5
- package/dist/device.js.map +1 -1
- package/dist/federation-registry.d.ts.map +1 -1
- package/dist/federation-registry.js +19 -2
- package/dist/federation-registry.js.map +1 -1
- package/dist/frame-timing-cpu.d.ts +31 -0
- package/dist/frame-timing-cpu.d.ts.map +1 -0
- package/dist/frame-timing-cpu.js +25 -0
- package/dist/frame-timing-cpu.js.map +1 -0
- package/dist/frame-timing-gpu.d.ts +144 -0
- package/dist/frame-timing-gpu.d.ts.map +1 -0
- package/dist/frame-timing-gpu.js +176 -0
- package/dist/frame-timing-gpu.js.map +1 -0
- package/dist/frame-timing-stats.d.ts +100 -0
- package/dist/frame-timing-stats.d.ts.map +1 -0
- package/dist/frame-timing-stats.js +116 -0
- package/dist/frame-timing-stats.js.map +1 -0
- package/dist/frame-timing.d.ts +102 -0
- package/dist/frame-timing.d.ts.map +1 -0
- package/dist/frame-timing.js +112 -0
- package/dist/frame-timing.js.map +1 -0
- package/dist/index.d.ts +77 -59
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +272 -73
- package/dist/index.js.map +1 -1
- package/dist/instanced-override-color.d.ts +17 -0
- package/dist/instanced-override-color.d.ts.map +1 -0
- package/dist/instanced-override-color.js +22 -0
- package/dist/instanced-override-color.js.map +1 -0
- package/dist/instanced-render.d.ts +10 -0
- package/dist/instanced-render.d.ts.map +1 -1
- package/dist/instanced-render.js +13 -3
- package/dist/instanced-render.js.map +1 -1
- package/dist/lod-simplify.d.ts +0 -9
- package/dist/lod-simplify.d.ts.map +1 -1
- package/dist/lod-simplify.js +45 -7
- package/dist/lod-simplify.js.map +1 -1
- package/dist/pick-resolve.d.ts +125 -0
- package/dist/pick-resolve.d.ts.map +1 -0
- package/dist/pick-resolve.js +127 -0
- package/dist/pick-resolve.js.map +1 -0
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +20 -46
- package/dist/picker.js.map +1 -1
- package/dist/picking-manager.d.ts.map +1 -1
- package/dist/picking-manager.js +13 -1
- package/dist/picking-manager.js.map +1 -1
- package/dist/pipeline.d.ts +16 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +89 -3
- package/dist/pipeline.js.map +1 -1
- package/dist/pointcloud/point-cloud-spatial-index.d.ts +81 -9
- package/dist/pointcloud/point-cloud-spatial-index.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-spatial-index.js +140 -29
- package/dist/pointcloud/point-cloud-spatial-index.js.map +1 -1
- package/dist/raycast-engine.d.ts +4 -4
- package/dist/raycast-engine.d.ts.map +1 -1
- package/dist/raycast-engine.js +10 -3
- package/dist/raycast-engine.js.map +1 -1
- package/dist/renderer-overlays.d.ts +3 -21
- package/dist/renderer-overlays.d.ts.map +1 -1
- package/dist/renderer-overlays.js +57 -85
- package/dist/renderer-overlays.js.map +1 -1
- package/dist/renderer-symbolic-overlays.d.ts +29 -2
- package/dist/renderer-symbolic-overlays.d.ts.map +1 -1
- package/dist/renderer-symbolic-overlays.js +61 -16
- package/dist/renderer-symbolic-overlays.js.map +1 -1
- package/dist/scene-contents.d.ts +132 -0
- package/dist/scene-contents.d.ts.map +1 -0
- package/dist/scene-contents.js +5 -0
- package/dist/scene-contents.js.map +1 -0
- package/dist/scene-raycaster.d.ts +14 -8
- package/dist/scene-raycaster.d.ts.map +1 -1
- package/dist/scene-raycaster.js +6 -2
- package/dist/scene-raycaster.js.map +1 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +63 -12
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-overlay.d.ts +52 -63
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +75 -133
- package/dist/section-2d-overlay.js.map +1 -1
- package/dist/section-plane.d.ts +11 -0
- package/dist/section-plane.d.ts.map +1 -1
- package/dist/section-plane.js.map +1 -1
- package/dist/shaders/main.wgsl.d.ts +1 -1
- package/dist/shaders/main.wgsl.d.ts.map +1 -1
- package/dist/shaders/main.wgsl.js +87 -4
- package/dist/shaders/main.wgsl.js.map +1 -1
- package/dist/shaders/section-2d-overlay.wgsl.d.ts +2 -2
- package/dist/shaders/section-2d-overlay.wgsl.d.ts.map +1 -1
- package/dist/shaders/section-2d-overlay.wgsl.js +2 -2
- package/dist/shaders/section-2d-overlay.wgsl.js.map +1 -1
- package/dist/shaders/shadow.wgsl.d.ts +31 -0
- package/dist/shaders/shadow.wgsl.d.ts.map +1 -0
- package/dist/shaders/shadow.wgsl.js +141 -0
- package/dist/shaders/shadow.wgsl.js.map +1 -0
- package/dist/shadow-light-matrix.d.ts +106 -0
- package/dist/shadow-light-matrix.d.ts.map +1 -0
- package/dist/shadow-light-matrix.js +185 -0
- package/dist/shadow-light-matrix.js.map +1 -0
- package/dist/shadow-occluders.d.ts +106 -0
- package/dist/shadow-occluders.d.ts.map +1 -0
- package/dist/shadow-occluders.js +156 -0
- package/dist/shadow-occluders.js.map +1 -0
- package/dist/shadow-pass.d.ts +132 -0
- package/dist/shadow-pass.d.ts.map +1 -0
- package/dist/shadow-pass.js +342 -0
- package/dist/shadow-pass.js.map +1 -0
- package/dist/snap-detector.d.ts +10 -0
- package/dist/snap-detector.d.ts.map +1 -1
- package/dist/snap-detector.js.map +1 -1
- package/dist/symbolic-overlay-pipelines.d.ts +34 -0
- package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
- package/dist/symbolic-overlay-pipelines.js +31 -20
- package/dist/symbolic-overlay-pipelines.js.map +1 -1
- package/dist/types.d.ts +45 -19
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/camera-framing.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
4
|
import { areFiniteNumbers, isUsableBounds, isUsableDistance } from './camera-guards.js';
|
|
5
|
+
import { MathUtils, viewBasis } from './math.js';
|
|
6
|
+
import { CAMERA_CONSTANTS } from './constants.js';
|
|
5
7
|
/** Centre of a box. */
|
|
6
8
|
export function centerOf(min, max) {
|
|
7
9
|
return {
|
|
@@ -10,47 +12,169 @@ export function centerOf(min, max) {
|
|
|
10
12
|
z: (min.z + max.z) / 2,
|
|
11
13
|
};
|
|
12
14
|
}
|
|
13
|
-
/** Largest edge length of a box. */
|
|
14
|
-
|
|
15
|
+
/** Largest edge length of a box. Local: only the two fits below measure it. */
|
|
16
|
+
function maxExtentOf(min, max) {
|
|
15
17
|
return Math.max(max.x - min.x, max.y - min.y, max.z - min.z);
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
+
* The viewport's width-to-height ratio, or 1 when it carries no usable one.
|
|
21
|
+
*
|
|
22
|
+
* `setAspect` is the only writer and already rejects a non-positive or
|
|
23
|
+
* non-finite ratio, so the substitute is only for a hand-built state — but
|
|
24
|
+
* both fits below key on it, and an `Infinity` would silently drop the
|
|
25
|
+
* horizontal constraint from one while the other substituted.
|
|
26
|
+
*/
|
|
27
|
+
function usableAspect(state) {
|
|
28
|
+
const aspect = state.camera.aspect;
|
|
29
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : 1;
|
|
30
|
+
}
|
|
31
|
+
/** Smallest half-height in model units that shows every corner of the box. */
|
|
32
|
+
function orthoHalfHeightFor(bounds, axes, aspect) {
|
|
33
|
+
let half = 0;
|
|
34
|
+
for (const corner of cornerOffsets(bounds)) {
|
|
35
|
+
const h = Math.abs(MathUtils.dot(corner, axes.right));
|
|
36
|
+
const v = Math.abs(MathUtils.dot(corner, axes.up));
|
|
37
|
+
half = Math.max(half, v, h / aspect);
|
|
38
|
+
}
|
|
39
|
+
return half;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Orthographic half-height that shows the box with `padding` slack, or
|
|
43
|
+
* `undefined` in perspective mode where `orthoSize` is not in play.
|
|
44
|
+
*
|
|
45
|
+
* Corner-based for the same reason {@link fitDistanceFor} is (#3892), and it
|
|
46
|
+
* is the half that decides what an orthographic viewer actually sees: there
|
|
47
|
+
* the standoff sets no scale at all, so a largest-side `orthoSize` cropped the
|
|
48
|
+
* selection on its own. The depth term does not appear — an orthographic
|
|
49
|
+
* projection does not foreshorten — but the obliqueness one does, and in full:
|
|
50
|
+
* down a south-east isometric direction a 20-unit cube reaches 15.9 units
|
|
51
|
+
* above the centre line, against the 10 the largest-side rule allowed.
|
|
20
52
|
*/
|
|
21
|
-
function orthoSizeFor(state,
|
|
53
|
+
function orthoSizeFor(state, bounds, axes, padding) {
|
|
22
54
|
if (state.projectionMode !== 'orthographic')
|
|
23
55
|
return undefined;
|
|
24
|
-
|
|
25
|
-
|
|
56
|
+
return Math.max(0.01, orthoHalfHeightFor(bounds, axes, usableAspect(state))) * padding;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The eight corners of a box, as offsets from its own centre.
|
|
60
|
+
*
|
|
61
|
+
* Both fits below need exactly this, and the offset form is what makes the
|
|
62
|
+
* corner arithmetic independent of where the box sits in the world. (The
|
|
63
|
+
* package has other corner walks — `shadow-light-matrix.ts`,
|
|
64
|
+
* `render-section-plane.ts` — but they take tuples and return world points.)
|
|
65
|
+
*/
|
|
66
|
+
function cornerOffsets(bounds) {
|
|
67
|
+
const center = centerOf(bounds.min, bounds.max);
|
|
68
|
+
const offsets = [];
|
|
69
|
+
for (const x of [bounds.min.x, bounds.max.x]) {
|
|
70
|
+
for (const y of [bounds.min.y, bounds.max.y]) {
|
|
71
|
+
for (const z of [bounds.min.z, bounds.max.z]) {
|
|
72
|
+
offsets.push({ x: x - center.x, y: y - center.y, z: z - center.z });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return offsets;
|
|
26
77
|
}
|
|
27
78
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* way from a dictated direction.
|
|
79
|
+
* Smallest standoff along `-axes.forward` that puts every corner of the box
|
|
80
|
+
* inside both half-angles, times `padding`. Shared with
|
|
81
|
+
* `camera-preset-view.ts`, which fits the same way from a dictated direction.
|
|
31
82
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* distance derived from the vertical field alone leaves the box overflowing
|
|
36
|
-
* left and right — the fit silently clips the very thing it was asked to
|
|
37
|
-
* frame. Landscape is unaffected: for `aspect >= 1` the vertical field is
|
|
38
|
-
* already the binding one and this returns the vertical distance exactly,
|
|
39
|
-
* bit for bit.
|
|
83
|
+
* The distance used to come from the box's largest SIDE, which answers a
|
|
84
|
+
* different question than the projection asks (#3892). Two ways that came
|
|
85
|
+
* apart:
|
|
40
86
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
87
|
+
* - **Depth.** The near half of the box is closer than its centre, so it
|
|
88
|
+
* projects bigger than a rule measured at the centre allows for. Head-on
|
|
89
|
+
* and axis-aligned, a cube of side `s` needs `s/2 / tan + s/2`, not
|
|
90
|
+
* `s/2 / tan`; at a 60 degree field the old rule cropped it even under the
|
|
91
|
+
* 1.5 padding.
|
|
92
|
+
* - **Obliqueness.** `frameBoundsTarget` fits along the live view direction,
|
|
93
|
+
* which is essentially never axis-aligned, and down a diagonal a box
|
|
94
|
+
* projects wider than any single side of it.
|
|
95
|
+
*
|
|
96
|
+
* Only the corners answer the question, so all eight are walked. A corner's
|
|
97
|
+
* sideways offsets do not depend on the standoff and its depth is
|
|
98
|
+
* `dot(corner, forward) + distance`, so it is inside when
|
|
99
|
+
* `|h| <= tanH * depth` and `|v| <= tanV * depth`; solving each for `distance`
|
|
100
|
+
* and taking the largest satisfies all sixteen constraints at once, because
|
|
101
|
+
* growing the distance only ever relaxes them.
|
|
102
|
+
*
|
|
103
|
+
* Both half-angles bind. The vertical one is `fov / 2` and the horizontal one
|
|
104
|
+
* is `atan(tan(fov / 2) * aspect)`, so on a portrait viewport (`aspect < 1`)
|
|
105
|
+
* the horizontal field is the *narrower* of the two and fitting the vertical
|
|
106
|
+
* field alone would leave the box overflowing left and right. `orthoSizeFor`
|
|
107
|
+
* above has divided by `aspect` for the same reason since it was written, and
|
|
108
|
+
* now walks the same corners.
|
|
109
|
+
*
|
|
110
|
+
* Two fit-distance formulas in this package are deliberately NOT this one:
|
|
111
|
+
* `CameraProjection.fitToBounds` and the compact branch of
|
|
112
|
+
* `camera-fit-policy.ts`, which reproduce the legacy opening pose of every
|
|
113
|
+
* model 1:1 and have tests pinning exactly that. They are a different subject
|
|
114
|
+
* — the initial auto-fit, not "frame what I selected" — and moving them would
|
|
115
|
+
* change the first thing every user sees.
|
|
116
|
+
*
|
|
117
|
+
* The twin of `fitCornersInFrustum` in `packages/bcf/src/ids-camera.ts`
|
|
118
|
+
* (#3882), which fits the same closed form to the BCF camera's one dictated
|
|
119
|
+
* isometric direction. A copy rather than a shared helper because sharing runs
|
|
120
|
+
* the dependency the wrong way — `bcf` does not depend on `renderer`, and this
|
|
121
|
+
* signature is stated in terms of `CameraInternalState`. Keep the arithmetic
|
|
122
|
+
* legible enough that the two read alike.
|
|
44
123
|
*/
|
|
45
|
-
export function fitDistanceFor(state,
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
124
|
+
export function fitDistanceFor(state, bounds, axes, padding) {
|
|
125
|
+
const tanV = Math.tan(state.camera.fov / 2);
|
|
126
|
+
const tanH = usableAspect(state) * tanV;
|
|
127
|
+
let distance = 0;
|
|
128
|
+
for (const corner of cornerOffsets(bounds)) {
|
|
129
|
+
const depth = MathUtils.dot(corner, axes.forward);
|
|
130
|
+
const h = Math.abs(MathUtils.dot(corner, axes.right)) / tanH;
|
|
131
|
+
const v = Math.abs(MathUtils.dot(corner, axes.up)) / tanV;
|
|
132
|
+
distance = Math.max(distance, h - depth, v - depth);
|
|
133
|
+
}
|
|
134
|
+
return distance * padding;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The pose both fits return: the box centred, seen from the direction the
|
|
138
|
+
* camera is already looking in, at the standoff that keeps every corner of it
|
|
139
|
+
* on screen.
|
|
140
|
+
*
|
|
141
|
+
* `frameBounds` and `zoomExtent` differ only in their padding and in what they
|
|
142
|
+
* do with a degenerate box, so the pose itself is built once here. Callers
|
|
143
|
+
* have already run `isUsableBounds` and their own degenerate branch.
|
|
144
|
+
*
|
|
145
|
+
* The direction comes from the pose rather than from `state.viewMatrix`.
|
|
146
|
+
* `frameBoundsTarget` used to read its forward axis as `-(m[8], m[9], m[10])`,
|
|
147
|
+
* which is the world Z axis expressed in CAMERA coordinates, not the camera's
|
|
148
|
+
* world-space backward axis (that is `(m[2], m[6], m[10])`). It is unit
|
|
149
|
+
* length, so neither a finiteness nor a magnitude floor could notice, and it
|
|
150
|
+
* agreed with the pose only for a symmetric rotation — Frame Selection jumped
|
|
151
|
+
* to a mirrored direction on an ordinary orbited pose (#3892).
|
|
152
|
+
*
|
|
153
|
+
* `viewBasis` is the one function that builds this frame, shared with
|
|
154
|
+
* `MathUtils.lookAt` and `unprojectToRay` (#2467). It scrubs non-finite
|
|
155
|
+
* coordinates and substitutes a deterministic basis for a degenerate pose or
|
|
156
|
+
* `up`, so it always returns finite unit axes: the two direction ladders that
|
|
157
|
+
* used to stand in these functions (view matrix, then pose, then a hard-coded
|
|
158
|
+
* isometric) were reimplementing that fallback with less care, and one of them
|
|
159
|
+
* against the wrong vector. The fit needs the `up` axis as well, and only the
|
|
160
|
+
* basis has it.
|
|
161
|
+
*/
|
|
162
|
+
function fitPoseFor(state, bounds, center, padding) {
|
|
163
|
+
const basis = viewBasis(state.camera.position, state.camera.target, state.camera.up);
|
|
164
|
+
const distance = fitDistanceFor(state, bounds, basis, padding);
|
|
165
|
+
return {
|
|
166
|
+
// The camera sits opposite the direction it looks in.
|
|
167
|
+
position: {
|
|
168
|
+
x: center.x - basis.forward.x * distance,
|
|
169
|
+
y: center.y - basis.forward.y * distance,
|
|
170
|
+
z: center.z - basis.forward.z * distance,
|
|
171
|
+
},
|
|
172
|
+
target: center,
|
|
173
|
+
// orthoSize so the zoom level resets properly in orthographic mode.
|
|
174
|
+
orthoSize: orthoSizeFor(state, bounds, basis, padding),
|
|
175
|
+
// `zoomExtent`'s caller hands this to `CameraProjection.updateNearFarPlanes`.
|
|
176
|
+
fitDistance: distance,
|
|
177
|
+
};
|
|
54
178
|
}
|
|
55
179
|
/**
|
|
56
180
|
* Frame/center view on a point (keeps current distance and direction).
|
|
@@ -100,66 +224,11 @@ export function frameBoundsTarget(state, min, max) {
|
|
|
100
224
|
// Very small or zero size - just center on it
|
|
101
225
|
return framePointTarget(state, center);
|
|
102
226
|
}
|
|
103
|
-
|
|
104
|
-
const distance = fitDistanceFor(state, maxSize, 1.2); // 1.2x padding for nice framing
|
|
105
|
-
// Get current viewing direction from view matrix (more reliable than position-target)
|
|
106
|
-
// View matrix forward is -Z axis in view space
|
|
107
|
-
const viewMatrix = state.viewMatrix.m;
|
|
108
|
-
// Extract forward direction from view matrix (negative Z column, normalized)
|
|
109
|
-
let dir = {
|
|
110
|
-
x: -viewMatrix[8], // -m[2][0] (forward X)
|
|
111
|
-
y: -viewMatrix[9], // -m[2][1] (forward Y)
|
|
112
|
-
z: -viewMatrix[10], // -m[2][2] (forward Z)
|
|
113
|
-
};
|
|
114
|
-
const dirLen = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
115
|
-
// Normalize direction
|
|
116
|
-
if (dirLen > 1e-6) {
|
|
117
|
-
dir.x /= dirLen;
|
|
118
|
-
dir.y /= dirLen;
|
|
119
|
-
dir.z /= dirLen;
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// Fallback: use position-target if view matrix is invalid
|
|
123
|
-
dir = {
|
|
124
|
-
x: state.camera.position.x - state.camera.target.x,
|
|
125
|
-
y: state.camera.position.y - state.camera.target.y,
|
|
126
|
-
z: state.camera.position.z - state.camera.target.z,
|
|
127
|
-
};
|
|
128
|
-
const fallbackLen = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
129
|
-
// Finiteness, not just magnitude — see `zoomExtentTarget`. `dirLen` above
|
|
130
|
-
// is safe (`MathUtils.lookAt` guarantees a finite view matrix), but this
|
|
131
|
-
// fallback reads the raw pose, where an overflowed coordinate is reachable.
|
|
132
|
-
if (isUsableDistance(fallbackLen, 1e-6)) {
|
|
133
|
-
dir.x /= fallbackLen;
|
|
134
|
-
dir.y /= fallbackLen;
|
|
135
|
-
dir.z /= fallbackLen;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
// Last resort: southeast isometric
|
|
139
|
-
dir.x = 0.6;
|
|
140
|
-
dir.y = 0.5;
|
|
141
|
-
dir.z = 0.6;
|
|
142
|
-
const len = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
143
|
-
dir.x /= len;
|
|
144
|
-
dir.y /= len;
|
|
145
|
-
dir.z /= len;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return {
|
|
149
|
-
// New position: center + direction * distance
|
|
150
|
-
position: {
|
|
151
|
-
x: center.x + dir.x * distance,
|
|
152
|
-
y: center.y + dir.y * distance,
|
|
153
|
-
z: center.z + dir.z * distance,
|
|
154
|
-
},
|
|
155
|
-
target: center,
|
|
156
|
-
// Calculate orthoSize for orthographic mode so zoom level resets properly
|
|
157
|
-
orthoSize: orthoSizeFor(state, maxSize, 1.2),
|
|
158
|
-
};
|
|
227
|
+
return fitPoseFor(state, { min, max }, center, CAMERA_CONSTANTS.FRAME_PADDING_MULTIPLIER);
|
|
159
228
|
}
|
|
160
229
|
/**
|
|
161
|
-
* Zoom to extents: same fit
|
|
162
|
-
*
|
|
230
|
+
* Zoom to extents: same fit and the same view direction as `frameBounds`, with
|
|
231
|
+
* wider padding and the fit distance reported back to the caller.
|
|
163
232
|
*/
|
|
164
233
|
export function zoomExtentTarget(state, min, max) {
|
|
165
234
|
// Same input class and same reasoning as `frameBoundsTarget` (#2461).
|
|
@@ -167,13 +236,11 @@ export function zoomExtentTarget(state, min, max) {
|
|
|
167
236
|
return null;
|
|
168
237
|
const center = centerOf(min, max);
|
|
169
238
|
const maxSize = maxExtentOf(min, max);
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
};
|
|
176
|
-
const currentDistance = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
239
|
+
// The standoff the camera already has, which the degenerate-box branch
|
|
240
|
+
// below keeps rather than fitting.
|
|
241
|
+
const currentDistance = Math.sqrt((state.camera.position.x - state.camera.target.x) ** 2 +
|
|
242
|
+
(state.camera.position.y - state.camera.target.y) ** 2 +
|
|
243
|
+
(state.camera.position.z - state.camera.target.z) ** 2);
|
|
177
244
|
// The degenerate box `frameBoundsTarget` has always special-cased and this
|
|
178
245
|
// one did not. `isUsableBounds` deliberately admits `max === min` (a flat
|
|
179
246
|
// wall, a single picked point, a one-element model), and for such a box the
|
|
@@ -185,46 +252,16 @@ export function zoomExtentTarget(state, min, max) {
|
|
|
185
252
|
//
|
|
186
253
|
// Only when the current offset is usable. When it is not, the pose already
|
|
187
254
|
// has position === target (or is non-finite), so there is no offset to keep
|
|
188
|
-
// and nothing is gained by keeping it
|
|
189
|
-
//
|
|
255
|
+
// and nothing is gained by keeping it. Such a call falls through to the fit,
|
|
256
|
+
// which for a point-sized box returns a zero standoff and so writes
|
|
257
|
+
// `position === target` again — unchanged from before #3892, and the one
|
|
258
|
+
// input for which this function still hands back a pose with no direction in
|
|
259
|
+
// it. `MathUtils.lookAt` substitutes a basis for it downstream.
|
|
190
260
|
if (maxSize < 1e-6 && isUsableDistance(currentDistance, 1e-10)) {
|
|
191
261
|
const framed = framePointTarget(state, center);
|
|
192
262
|
if (framed)
|
|
193
263
|
return { ...framed, fitDistance: currentDistance };
|
|
194
264
|
}
|
|
195
|
-
|
|
196
|
-
const distance = fitDistanceFor(state, maxSize, 1.5); // 1.5x for padding
|
|
197
|
-
// Normalize direction. Finiteness, not just magnitude: `len > 1e-10` is
|
|
198
|
-
// *true* for Infinity, and `Infinity / Infinity` is NaN, so a pose whose
|
|
199
|
-
// position has overflowed walks past a bare floor and writes a NaN position
|
|
200
|
-
// from a perfectly usable box (#2441).
|
|
201
|
-
if (isUsableDistance(currentDistance, 1e-10)) {
|
|
202
|
-
dir.x /= currentDistance;
|
|
203
|
-
dir.y /= currentDistance;
|
|
204
|
-
dir.z /= currentDistance;
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
// Fallback direction
|
|
208
|
-
dir.x = 0.6;
|
|
209
|
-
dir.y = 0.5;
|
|
210
|
-
dir.z = 0.6;
|
|
211
|
-
const len = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
|
|
212
|
-
dir.x /= len;
|
|
213
|
-
dir.y /= len;
|
|
214
|
-
dir.z /= len;
|
|
215
|
-
}
|
|
216
|
-
return {
|
|
217
|
-
// New position: center + direction * distance
|
|
218
|
-
position: {
|
|
219
|
-
x: center.x + dir.x * distance,
|
|
220
|
-
y: center.y + dir.y * distance,
|
|
221
|
-
z: center.z + dir.z * distance,
|
|
222
|
-
},
|
|
223
|
-
target: center,
|
|
224
|
-
// Calculate orthoSize for orthographic mode so zoom level resets properly
|
|
225
|
-
orthoSize: orthoSizeFor(state, maxSize, 1.5),
|
|
226
|
-
// The caller hands this to `CameraProjection.updateNearFarPlanes`.
|
|
227
|
-
fitDistance: distance,
|
|
228
|
-
};
|
|
265
|
+
return fitPoseFor(state, { min, max }, center, CAMERA_CONSTANTS.ZOOM_EXTENT_PADDING);
|
|
229
266
|
}
|
|
230
267
|
//# sourceMappingURL=camera-framing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camera-framing.js","sourceRoot":"","sources":["../src/camera-framing.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAmC/D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"camera-framing.js","sourceRoot":"","sources":["../src/camera-framing.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* current direction"). Presets are the opposite subject: the direction is
|
|
8
8
|
* dictated by the named face and the caller's rotation cycle, and the box is
|
|
9
9
|
* whatever the caller supplied or whatever the current pose implies. The two
|
|
10
|
-
* share
|
|
11
|
-
* `
|
|
10
|
+
* share the box arithmetic and the corner fit, which is why this module
|
|
11
|
+
* imports `centerOf` / `fitDistanceFor` rather than owning a second copy.
|
|
12
12
|
*
|
|
13
13
|
* Pure by construction, exactly as `camera-framing.ts` is: everything here
|
|
14
14
|
* reads `CameraInternalState` and returns a target, nothing writes to it or
|
|
@@ -1 +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,
|
|
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,EAA4B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWnF;;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,CA4H5C"}
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
4
|
import { isUsableBounds } from './camera-guards.js';
|
|
5
|
-
import { centerOf, fitDistanceFor
|
|
5
|
+
import { centerOf, fitDistanceFor } from './camera-framing.js';
|
|
6
|
+
import { viewBasis } from './math.js';
|
|
7
|
+
import { CAMERA_CONSTANTS } from './constants.js';
|
|
8
|
+
/**
|
|
9
|
+
* The ~0.6 degree tilt that keeps the top and bottom presets off the pole, so
|
|
10
|
+
* the orbit math that follows has a well-defined polar tangent.
|
|
11
|
+
*/
|
|
12
|
+
const POLE_TILT_SIN = Math.sin(0.01);
|
|
13
|
+
const POLE_TILT_COS = Math.cos(0.01);
|
|
6
14
|
/**
|
|
7
15
|
* Get current bounds estimate (simplified - in production would use scene bounds).
|
|
8
16
|
*/
|
|
@@ -62,13 +70,11 @@ export function resolvePresetBounds(state, bounds) {
|
|
|
62
70
|
*/
|
|
63
71
|
export function presetViewTarget(state, view, bounds, rotation, buildingRotation) {
|
|
64
72
|
const center = centerOf(bounds.min, bounds.max);
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
let endPos;
|
|
71
|
-
const endTarget = center;
|
|
73
|
+
// Unit offset from the centre to the camera, per named face. The fit
|
|
74
|
+
// distance depends on it — the box's projected extent is a property of the
|
|
75
|
+
// direction it is seen from — so the switch below picks the direction and
|
|
76
|
+
// the standoff is applied once, afterwards.
|
|
77
|
+
let offsetDir;
|
|
72
78
|
// WebGL uses Y-up coordinate system internally
|
|
73
79
|
// We set both position AND up vector for proper orthogonal views
|
|
74
80
|
let upVector = { x: 0, y: 1, z: 0 }; // Default Y-up
|
|
@@ -77,7 +83,7 @@ export function presetViewTarget(state, view, bounds, rotation, buildingRotation
|
|
|
77
83
|
// Normalized rather than trusted: this is the IfcSite placement angle,
|
|
78
84
|
// derived from the file and threaded through `Camera.setPresetView` — the
|
|
79
85
|
// published entry point — without ever meeting a guard. `Math.cos(NaN)` is
|
|
80
|
-
// NaN, and the four horizontal presets multiply it straight into
|
|
86
|
+
// NaN, and the four horizontal presets multiply it straight into the offset,
|
|
81
87
|
// so a malformed placement would send the ViewCube to a non-finite pose. A
|
|
82
88
|
// zero rotation is the same answer as "no rotation supplied", which is what
|
|
83
89
|
// the undefined case already resolves to.
|
|
@@ -101,32 +107,32 @@ export function presetViewTarget(state, view, bounds, rotation, buildingRotation
|
|
|
101
107
|
// rotation 3 → camera slightly to -X → screen-up = -X
|
|
102
108
|
// Building rotation is applied as the same Y-axis rotation that
|
|
103
109
|
// setPresetView would have used to remap the legacy up vector.
|
|
104
|
-
const poleOffset =
|
|
105
|
-
const verticalOffset =
|
|
110
|
+
const poleOffset = POLE_TILT_SIN;
|
|
111
|
+
const verticalOffset = POLE_TILT_COS;
|
|
106
112
|
// `?? 0`: `rotation` is the animator's 0-3 cycle counter today, but it
|
|
107
113
|
// is a plain `number` on the signature, and an out-of-range, fractional
|
|
108
114
|
// or non-finite one indexes past the table and makes `thetaWorld` — and
|
|
109
115
|
// with it the whole preset pose — NaN.
|
|
110
116
|
const thetaPerRotation = [0, Math.PI / 2, Math.PI, -Math.PI / 2];
|
|
111
117
|
const thetaWorld = (thetaPerRotation[rotation] ?? 0) + rotationRadians;
|
|
112
|
-
|
|
113
|
-
x:
|
|
114
|
-
y:
|
|
115
|
-
z:
|
|
118
|
+
offsetDir = {
|
|
119
|
+
x: poleOffset * Math.sin(thetaWorld),
|
|
120
|
+
y: verticalOffset,
|
|
121
|
+
z: poleOffset * Math.cos(thetaWorld),
|
|
116
122
|
};
|
|
117
123
|
upVector = { x: 0, y: 1, z: 0 };
|
|
118
124
|
break;
|
|
119
125
|
}
|
|
120
126
|
case 'bottom': {
|
|
121
127
|
// Bottom view: mirror of top — phi = π − MIN_PHI.
|
|
122
|
-
const poleOffset =
|
|
123
|
-
const verticalOffset =
|
|
128
|
+
const poleOffset = POLE_TILT_SIN;
|
|
129
|
+
const verticalOffset = POLE_TILT_COS;
|
|
124
130
|
const thetaPerRotation = [Math.PI, Math.PI / 2, 0, -Math.PI / 2];
|
|
125
131
|
const thetaWorld = (thetaPerRotation[rotation] ?? 0) + rotationRadians;
|
|
126
|
-
|
|
127
|
-
x:
|
|
128
|
-
y:
|
|
129
|
-
z:
|
|
132
|
+
offsetDir = {
|
|
133
|
+
x: poleOffset * Math.sin(thetaWorld),
|
|
134
|
+
y: -verticalOffset,
|
|
135
|
+
z: poleOffset * Math.cos(thetaWorld),
|
|
130
136
|
};
|
|
131
137
|
upVector = { x: 0, y: 1, z: 0 };
|
|
132
138
|
break;
|
|
@@ -137,44 +143,48 @@ export function presetViewTarget(state, view, bounds, rotation, buildingRotation
|
|
|
137
143
|
// Standard rotation: x' = x*cos - z*sin, z' = x*sin + z*cos
|
|
138
144
|
// For +Z direction (0,0,1): x' = -sin, z' = cos
|
|
139
145
|
// But we need to look at building's front, so use negative rotation
|
|
140
|
-
|
|
141
|
-
x: center.x + sinR * distance,
|
|
142
|
-
y: center.y,
|
|
143
|
-
z: center.z + cosR * distance,
|
|
144
|
-
};
|
|
146
|
+
offsetDir = { x: sinR, y: 0, z: cosR };
|
|
145
147
|
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
146
148
|
break;
|
|
147
149
|
case 'back':
|
|
148
150
|
// Back view: from -Z looking at model
|
|
149
151
|
// For -Z direction (0,0,-1) rotated: x' = sin, z' = -cos
|
|
150
|
-
|
|
151
|
-
x: center.x - sinR * distance,
|
|
152
|
-
y: center.y,
|
|
153
|
-
z: center.z - cosR * distance,
|
|
154
|
-
};
|
|
152
|
+
offsetDir = { x: -sinR, y: 0, z: -cosR };
|
|
155
153
|
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
156
154
|
break;
|
|
157
155
|
case 'left':
|
|
158
156
|
// Left view: from -X looking at model
|
|
159
157
|
// For -X direction (-1,0,0) rotated: x' = -cos, z' = sin
|
|
160
|
-
|
|
161
|
-
x: center.x - cosR * distance,
|
|
162
|
-
y: center.y,
|
|
163
|
-
z: center.z + sinR * distance,
|
|
164
|
-
};
|
|
158
|
+
offsetDir = { x: -cosR, y: 0, z: sinR };
|
|
165
159
|
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
166
160
|
break;
|
|
167
161
|
case 'right':
|
|
168
162
|
// Right view: from +X looking at model
|
|
169
163
|
// For +X direction (1,0,0) rotated: x' = cos, z' = -sin
|
|
170
|
-
|
|
171
|
-
x: center.x + cosR * distance,
|
|
172
|
-
y: center.y,
|
|
173
|
-
z: center.z - sinR * distance,
|
|
174
|
-
};
|
|
164
|
+
offsetDir = { x: cosR, y: 0, z: -sinR };
|
|
175
165
|
upVector = { x: 0, y: 1, z: 0 }; // Y-up
|
|
176
166
|
break;
|
|
177
167
|
}
|
|
178
|
-
|
|
168
|
+
// The standoff that keeps every corner of the box on screen from this
|
|
169
|
+
// direction, with 1.5x padding. `viewBasis` is the same function
|
|
170
|
+
// `MathUtils.lookAt` will build the real view matrix with, so the axes here
|
|
171
|
+
// are the ones the frame is drawn in — including the substitute up axis a
|
|
172
|
+
// near-vertical top/bottom preset gets. It is given `offsetDir` about the
|
|
173
|
+
// origin rather than the real pose because it only ever uses `eye - target`,
|
|
174
|
+
// and the difference at the real centre is the same direction with the low
|
|
175
|
+
// bits of a georeferenced coordinate rounded off it.
|
|
176
|
+
const basis = viewBasis(offsetDir, { x: 0, y: 0, z: 0 }, upVector);
|
|
177
|
+
const distance = fitDistanceFor(state, bounds, basis, CAMERA_CONSTANTS.ZOOM_EXTENT_PADDING);
|
|
178
|
+
return {
|
|
179
|
+
// Off the basis rather than off `offsetDir`, so the standoff is the
|
|
180
|
+
// distance whatever length the switch above happened to build.
|
|
181
|
+
position: {
|
|
182
|
+
x: center.x - basis.forward.x * distance,
|
|
183
|
+
y: center.y - basis.forward.y * distance,
|
|
184
|
+
z: center.z - basis.forward.z * distance,
|
|
185
|
+
},
|
|
186
|
+
target: center,
|
|
187
|
+
up: upVector,
|
|
188
|
+
};
|
|
179
189
|
}
|
|
180
190
|
//# sourceMappingURL=camera-preset-view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camera-preset-view.js","sourceRoot":"","sources":["../src/camera-preset-view.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA4B/D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"camera-preset-view.js","sourceRoot":"","sources":["../src/camera-preset-view.ts"],"names":[],"mappings":"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"}
|