@weasel-js/kernel3d 1.18.1 → 1.19.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/dist/index.d.ts +40 -15
- package/dist/index.js +91 -51
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -53,14 +53,16 @@ declare const DEFAULT_ORBIT_LIMITS: OrbitLimits;
|
|
|
53
53
|
* itself when it already holds. */
|
|
54
54
|
declare function clampCamera(camera: Camera3d, limits?: Partial<OrbitLimits>): Camera3d;
|
|
55
55
|
/** The camera turned about its target by the given radians, pitch held inside
|
|
56
|
-
* `limits`. Yaw is not wrapped. */
|
|
56
|
+
* `limits`. Yaw is not wrapped. A turn that is not finite leaves it as it is. */
|
|
57
57
|
declare function orbitBy(camera: Camera3d, deltaYaw: number, deltaPitch: number, limits?: Partial<OrbitLimits>): Camera3d;
|
|
58
|
-
/** The camera with its distance multiplied by `factor`, held inside `limits`.
|
|
58
|
+
/** The camera with its distance multiplied by `factor`, held inside `limits`.
|
|
59
|
+
* A `NaN` factor leaves it as it is. */
|
|
59
60
|
declare function dollyBy(camera: Camera3d, factor: number, limits?: Partial<OrbitLimits>): Camera3d;
|
|
60
61
|
/**
|
|
61
62
|
* The camera with its target slid across the screen plane, so the point at the
|
|
62
63
|
* target follows a pointer that moved `dx`, `dy` CSS pixels in a pane
|
|
63
|
-
* `paneHeight` pixels tall. Neither angle nor distance changes.
|
|
64
|
+
* `paneHeight` pixels tall. Neither angle nor distance changes. A pan that
|
|
65
|
+
* carries the target past the double range leaves the camera as it is.
|
|
64
66
|
*/
|
|
65
67
|
declare function panBy(camera: Camera3d, dx: number, dy: number, paneHeight: number): Camera3d;
|
|
66
68
|
/**
|
|
@@ -209,14 +211,18 @@ interface Viewport3d {
|
|
|
209
211
|
originX?: number;
|
|
210
212
|
originY?: number;
|
|
211
213
|
}
|
|
212
|
-
/**
|
|
213
|
-
|
|
214
|
+
/**
|
|
215
|
+
* The viewport the view `viewId` looks through, read on every dep call so a
|
|
216
|
+
* dep always sees the current camera and pane. `viewId` is a `<CanvasView>`'s
|
|
217
|
+
* id; absent or `null`, the surface's own camera.
|
|
218
|
+
*/
|
|
219
|
+
type ViewportSource = (viewId?: string | null) => Viewport3d;
|
|
214
220
|
type Point$1 = {
|
|
215
221
|
x: number;
|
|
216
222
|
y: number;
|
|
217
223
|
};
|
|
218
|
-
/** Where `p` draws in the viewport, or null when it is behind the near plane
|
|
219
|
-
* or projects to nothing finite. */
|
|
224
|
+
/** Where `p` draws in the viewport, or null when it is behind the near plane,
|
|
225
|
+
* the pane has no area, or it projects to nothing finite. */
|
|
220
226
|
declare function projectPoint(p: Vec3, viewport: Viewport3d): Point$1 | null;
|
|
221
227
|
|
|
222
228
|
/** The 3D world every dep is built from: core's scene with a `Pose3`, the
|
|
@@ -273,7 +279,8 @@ declare function screenBoxOf<TData, TLayer extends string>(world: World3d<TData,
|
|
|
273
279
|
/**
|
|
274
280
|
* The kit's deps, implemented against a 3D world.
|
|
275
281
|
*
|
|
276
|
-
* Every one of these takes its camera from a thunk rather than an argument
|
|
282
|
+
* Every one of these takes its camera from a thunk rather than an argument,
|
|
283
|
+
* `world.viewport(viewId)` for the view it was built for:
|
|
277
284
|
* the dispatcher keeps handing actions two numbers, and what makes them mean
|
|
278
285
|
* something in 3D is the camera each dep already closes over.
|
|
279
286
|
*/
|
|
@@ -283,14 +290,27 @@ declare function screenBoxOf<TData, TLayer extends string>(world: World3d<TData,
|
|
|
283
290
|
*
|
|
284
291
|
* The kit calls this with what it believes is a world point; a 3D host feeds
|
|
285
292
|
* the dispatcher an identity `clientToWorld`, so it is the pane-relative screen
|
|
286
|
-
* point, which is exactly what a ray needs.
|
|
293
|
+
* point, which is exactly what a ray needs. *
|
|
294
|
+
* `viewId` names the view whose camera casts the ray; a surface with several
|
|
295
|
+
* 3D views gives each `<CanvasView deps>` its own. The same goes for every
|
|
296
|
+
* factory here that takes one.
|
|
297
|
+
*/
|
|
298
|
+
declare function createNodeAtPoint<TData, TLayer extends string>(world: World3d<TData, TLayer>, viewId?: string | null): NodeAtPointDep;
|
|
299
|
+
/**
|
|
300
|
+
* `<SceneCanvas geometry={{ pickEvery }}>` over a 3D world: the node along the
|
|
301
|
+
* ray the point names, cast from the camera of the view the pick is asked for.
|
|
287
302
|
*/
|
|
288
|
-
declare function
|
|
303
|
+
declare function createPickEvery<TData, TLayer extends string>(world: World3d<TData, TLayer>): (point: {
|
|
304
|
+
x: number;
|
|
305
|
+
y: number;
|
|
306
|
+
}, view?: {
|
|
307
|
+
viewId?: string | null;
|
|
308
|
+
}) => NodeId | null;
|
|
289
309
|
/** Marquee: the nodes whose projected box the screen rectangle touches, in render order. */
|
|
290
310
|
declare function createAreaSelect<TData, TLayer extends string>(world: World3d<TData, TLayer>, selection: {
|
|
291
311
|
get(): readonly NodeId[];
|
|
292
312
|
set(ids: NodeId[]): void;
|
|
293
|
-
}): AreaSelectDep;
|
|
313
|
+
}, viewId?: string | null): AreaSelectDep;
|
|
294
314
|
/** Options for `createSnap`. */
|
|
295
315
|
interface Snap3dOptions {
|
|
296
316
|
/** What a gesture snaps to, in order: earlier wins a full tie. Two sharing
|
|
@@ -305,6 +325,8 @@ interface Snap3dOptions {
|
|
|
305
325
|
/** Where the marks of the snap in flight are written, for a host to draw
|
|
306
326
|
* with `projectSnapMarks`. */
|
|
307
327
|
store?: SnapOutcomeStore<Vec3>;
|
|
328
|
+
/** The view whose camera a gesture is cast through. Default the surface's. */
|
|
329
|
+
viewId?: string | null;
|
|
308
330
|
}
|
|
309
331
|
/**
|
|
310
332
|
* The `snap` dep over a 3D world. A gesture's `omit` is honored; its 2D
|
|
@@ -327,7 +349,7 @@ declare function createSnap<TData, TLayer extends string>(world: World3d<TData,
|
|
|
327
349
|
* through the pose they were handed, facing the camera, so nothing they
|
|
328
350
|
* produce changes depth.
|
|
329
351
|
*/
|
|
330
|
-
declare function createPoseDescriptor<TData, TLayer extends string>(world: World3d<TData, TLayer
|
|
352
|
+
declare function createPoseDescriptor<TData, TLayer extends string>(world: World3d<TData, TLayer>, viewId?: string | null): PoseDescriptor<Pose3, Node3d<TData, TLayer>>;
|
|
331
353
|
|
|
332
354
|
/** The `insert` dep over a 3D world: a drag becomes a footprint on the ground. */
|
|
333
355
|
|
|
@@ -348,6 +370,8 @@ interface Footprint {
|
|
|
348
370
|
*/
|
|
349
371
|
declare function createInsert(opts: {
|
|
350
372
|
viewport: ViewportSource;
|
|
373
|
+
/** The view whose camera a drag is cast through, for a `<CanvasView deps>` of its own. Default the surface's. */
|
|
374
|
+
viewId?: string | null;
|
|
351
375
|
up?: Vec3;
|
|
352
376
|
/** Smallest footprint a click-sized drag produces. Default 0.25. */
|
|
353
377
|
minExtent?: number;
|
|
@@ -419,8 +443,9 @@ interface GroundGridSourceOptions {
|
|
|
419
443
|
/**
|
|
420
444
|
* A grid on the ground plane as snap targets: for each pointer or geometry
|
|
421
445
|
* probe on the ground, the grid line on either side of it along each of the
|
|
422
|
-
* ground's two axes
|
|
423
|
-
*
|
|
446
|
+
* ground's two axes, none along an axis where the probe lies so far out that
|
|
447
|
+
* lines a step apart are no longer two numbers. Its reach is unlimited and it
|
|
448
|
+
* is a fallback, so it holds every axis no target claims and never displaces one.
|
|
424
449
|
*/
|
|
425
450
|
declare function groundGridSource(opts: GroundGridSourceOptions): SnapSource<Vec3>;
|
|
426
451
|
|
|
@@ -709,5 +734,5 @@ declare const kernel3dKitSettingsSchema: Omit<_weasel_js_prefs.PrefGroup, "child
|
|
|
709
734
|
};
|
|
710
735
|
};
|
|
711
736
|
|
|
712
|
-
export { DEFAULT_ORBIT_LIMITS, HEAD, HEAD_OVERDRAW, LINE_FLOATS, MAX_PITCH, POSE3_COMPOSITION, UNIT_CUBE, aabbOfPose, aimOf3d, aimSpace3d, alignPlaneSource, boxSnapSource, cameraEye, cameraOfAim3d, cameraView, cameraViewProjection, clampCamera, collectOverlayBoxes, createAreaSelect, createCamera, createInsert, createLinePass, createNodeAtPoint, createPoseDescriptor, createSnap, dollyAction, dollyBy, dollyToward, groundGridSource, headFor, homeAction, kernel3dKitSettingsSchema, layoutLine, ndcToScreen, orbitAction, orbitBy, packLines, panAction, panBy, pinchDollyAction, pose3, poseMatrix, projectAabbToScreen, projectPoint, projectSnapMarks, rayThroughScreenPoint, screenBoxOf, screenToNdc, useOrbitTool, visibleRuns, worldPoseOf };
|
|
737
|
+
export { DEFAULT_ORBIT_LIMITS, HEAD, HEAD_OVERDRAW, LINE_FLOATS, MAX_PITCH, POSE3_COMPOSITION, UNIT_CUBE, aabbOfPose, aimOf3d, aimSpace3d, alignPlaneSource, boxSnapSource, cameraEye, cameraOfAim3d, cameraView, cameraViewProjection, clampCamera, collectOverlayBoxes, createAreaSelect, createCamera, createInsert, createLinePass, createNodeAtPoint, createPickEvery, createPoseDescriptor, createSnap, dollyAction, dollyBy, dollyToward, groundGridSource, headFor, homeAction, kernel3dKitSettingsSchema, layoutLine, ndcToScreen, orbitAction, orbitBy, packLines, panAction, panBy, pinchDollyAction, pose3, poseMatrix, projectAabbToScreen, projectPoint, projectSnapMarks, rayThroughScreenPoint, screenBoxOf, screenToNdc, useOrbitTool, visibleRuns, worldPoseOf };
|
|
713
738
|
export type { Aim3d, Aim3dOptions, Camera3d, Camera3dDep, ChromeBox, Footprint, Frustum3d, GroundGridSourceOptions, HeadShape, HeadSize, Line3, LineDrawOptions, LineLayout, LinePass, LineRun3, Node3d, NodeBounds, Orbit3dKitSettings, OrbitLimits, Pose3, Scene3d, ScreenBox, ScreenLine, ScreenPoint, Snap3dOptions, Viewport3d, ViewportSource, VisibleRun3, World3d };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { lookAt, multiply, perspective, add, scale, quatIdentity, compose, transformAabb, quatMultiply, quatConjugate, quatRotate, sub, invert, transformPoint, normalize, transformPoint4, distance,
|
|
1
|
+
import { lookAt, multiply, perspective, add, scale, quatIdentity, compose, transformAabb, quatMultiply, quatConjugate, quatRotate, sub, invert, transformPoint, normalize, cross, dot, transformPoint4, distance, len, aabbOfPoints, intersectRayPlane, pointOnRay, intersectRayAabb } from '@weasel-js/geom/3d';
|
|
2
2
|
import { clamp, lengthTable, curveSpan, rectsOverlap } from '@weasel-js/geom';
|
|
3
|
-
import { scenePoseFrame, createSnapOutcomeStore, assertSnapSourceIds, DEFAULT_SNAP_PX, resolveOverlays, snapSourcesFor, resolvedSnapMarks, SNAP_AXIS_STEP, gatherSnapCandidates, scenePoseAdapter, composeWorldPose } from '@weasel-js/core/engine';
|
|
3
|
+
import { scenePoseFrame, createSnapOutcomeStore, assertSnapSourceIds, DEFAULT_SNAP_PX, resolveOverlays, snapSourcesFor, resolveHolding, resolvedSnapMarks, SNAP_AXIS_STEP, gatherSnapCandidates, scenePoseAdapter, composeWorldPose } from '@weasel-js/core/engine';
|
|
4
4
|
import { isDev } from '@weasel-js/react';
|
|
5
5
|
import { closestOnFlat, resolveSnap, createBvh, stepLine, createSettledCache } from '@weasel-js/geom/nd';
|
|
6
6
|
import { overlaysOf, defineTool } from '@weasel-js/routing';
|
|
@@ -45,19 +45,23 @@ var DEFAULT_ORBIT_LIMITS = {
|
|
|
45
45
|
};
|
|
46
46
|
function clampCamera(camera, limits = {}) {
|
|
47
47
|
const l = { ...DEFAULT_ORBIT_LIMITS, ...limits };
|
|
48
|
-
const pitch = clamp(camera.pitch,
|
|
48
|
+
const pitch = clamp(camera.pitch, clamp(l.minPitch, -MAX_PITCH, MAX_PITCH), clamp(l.maxPitch, -MAX_PITCH, MAX_PITCH));
|
|
49
49
|
const distance2 = clamp(camera.distance, l.minDistance, l.maxDistance);
|
|
50
50
|
if (pitch === camera.pitch && distance2 === camera.distance) return camera;
|
|
51
51
|
return { ...camera, pitch, distance: distance2 };
|
|
52
52
|
}
|
|
53
|
+
function heldFinite(camera, moved) {
|
|
54
|
+
const { target: t, yaw, pitch, distance: distance2 } = moved;
|
|
55
|
+
return Number.isFinite(t.x + t.y + t.z + yaw + pitch + distance2) ? moved : camera;
|
|
56
|
+
}
|
|
53
57
|
function orbitBy(camera, deltaYaw, deltaPitch, limits) {
|
|
54
|
-
return clampCamera(
|
|
58
|
+
return heldFinite(camera, clampCamera(
|
|
55
59
|
{ ...camera, yaw: camera.yaw + deltaYaw, pitch: camera.pitch + deltaPitch },
|
|
56
60
|
limits
|
|
57
|
-
);
|
|
61
|
+
));
|
|
58
62
|
}
|
|
59
63
|
function dollyBy(camera, factor, limits) {
|
|
60
|
-
return clampCamera({ ...camera, distance: camera.distance * factor }, limits);
|
|
64
|
+
return heldFinite(camera, clampCamera({ ...camera, distance: camera.distance * factor }, limits));
|
|
61
65
|
}
|
|
62
66
|
function panBy(camera, dx, dy, paneHeight) {
|
|
63
67
|
if (!(paneHeight > 0)) return camera;
|
|
@@ -70,7 +74,7 @@ function panBy(camera, dx, dy, paneHeight) {
|
|
|
70
74
|
z: -Math.cos(yaw) * Math.sin(pitch)
|
|
71
75
|
};
|
|
72
76
|
const shift = add(scale(right, -dx * perPixel), scale(up, dy * perPixel));
|
|
73
|
-
return { ...camera, target: add(camera.target, shift) };
|
|
77
|
+
return heldFinite(camera, { ...camera, target: add(camera.target, shift) });
|
|
74
78
|
}
|
|
75
79
|
function dollyToward(camera, factor, at, pane, limits) {
|
|
76
80
|
const dollied = dollyBy(camera, factor, limits);
|
|
@@ -81,14 +85,14 @@ function dollyToward(camera, factor, at, pane, limits) {
|
|
|
81
85
|
-kept * (at.y - pane.height / 2),
|
|
82
86
|
pane.height
|
|
83
87
|
);
|
|
84
|
-
return { ...dollied, target: moved.target };
|
|
88
|
+
return heldFinite(camera, { ...dollied, target: moved.target });
|
|
85
89
|
}
|
|
86
90
|
var UNIT_CUBE = {
|
|
87
91
|
min: { x: -0.5, y: -0.5, z: -0.5 },
|
|
88
92
|
max: { x: 0.5, y: 0.5, z: 0.5 }
|
|
89
93
|
};
|
|
90
|
-
function pose3(position,
|
|
91
|
-
return { position, rotation, scale:
|
|
94
|
+
function pose3(position, scale7 = { x: 1, y: 1, z: 1 }, rotation = quatIdentity()) {
|
|
95
|
+
return { position, rotation, scale: scale7 };
|
|
92
96
|
}
|
|
93
97
|
function poseMatrix(pose) {
|
|
94
98
|
return compose(pose.position, pose.rotation, pose.scale);
|
|
@@ -97,10 +101,14 @@ function aabbOfPose(pose, local = UNIT_CUBE) {
|
|
|
97
101
|
return transformAabb(poseMatrix(pose), local);
|
|
98
102
|
}
|
|
99
103
|
var times = (a, b) => ({ x: a.x * b.x, y: a.y * b.y, z: a.z * b.z });
|
|
104
|
+
var overAxis = (a, s, zero) => {
|
|
105
|
+
const q = a / s;
|
|
106
|
+
return s === 0 || !Number.isFinite(q) ? zero : q;
|
|
107
|
+
};
|
|
100
108
|
var over = (a, s, zero) => ({
|
|
101
|
-
x:
|
|
102
|
-
y:
|
|
103
|
-
z:
|
|
109
|
+
x: overAxis(a.x, s.x, zero.x),
|
|
110
|
+
y: overAxis(a.y, s.y, zero.y),
|
|
111
|
+
z: overAxis(a.z, s.z, zero.z)
|
|
104
112
|
});
|
|
105
113
|
var ORIGIN = { x: 0, y: 0, z: 0 };
|
|
106
114
|
var POSE3_COMPOSITION = {
|
|
@@ -129,7 +137,8 @@ function ndcToScreen(ndc, rect) {
|
|
|
129
137
|
};
|
|
130
138
|
}
|
|
131
139
|
function rayThroughScreenPoint(point, rect, viewProjection) {
|
|
132
|
-
const
|
|
140
|
+
const eye = eyeOf(viewProjection) ?? ORIGIN2;
|
|
141
|
+
const inv = invert(multiply(viewProjection, compose(eye, quatIdentity(), UNIT)));
|
|
133
142
|
if (!inv) return null;
|
|
134
143
|
const ndc = screenToNdc(point, rect);
|
|
135
144
|
const near = transformPoint(inv, { x: ndc.x, y: ndc.y, z: -1 });
|
|
@@ -137,7 +146,19 @@ function rayThroughScreenPoint(point, rect, viewProjection) {
|
|
|
137
146
|
const direction = sub(far, near);
|
|
138
147
|
const unit = normalize(direction);
|
|
139
148
|
if (unit.x === 0 && unit.y === 0 && unit.z === 0) return null;
|
|
140
|
-
return { origin: near, direction };
|
|
149
|
+
return { origin: add(eye, near), direction };
|
|
150
|
+
}
|
|
151
|
+
var ORIGIN2 = { x: 0, y: 0, z: 0 };
|
|
152
|
+
var UNIT = { x: 1, y: 1, z: 1 };
|
|
153
|
+
function eyeOf(m) {
|
|
154
|
+
const row = (r) => ({ x: m[r], y: m[4 + r], z: m[8 + r] });
|
|
155
|
+
const [a, b, c] = [row(0), row(1), row(3)];
|
|
156
|
+
const bc = cross(b, c);
|
|
157
|
+
const ca = cross(c, a);
|
|
158
|
+
const ab = cross(a, b);
|
|
159
|
+
const det = dot(a, bc);
|
|
160
|
+
const eye = scale(add(add(scale(bc, m[12]), scale(ca, m[13])), scale(ab, m[15])), -1 / det);
|
|
161
|
+
return Number.isFinite(eye.x + eye.y + eye.z) ? eye : null;
|
|
141
162
|
}
|
|
142
163
|
var CLIP_SIDES = [
|
|
143
164
|
(p) => p[2] + p[3],
|
|
@@ -153,6 +174,7 @@ function lerpClip(a, b, t) {
|
|
|
153
174
|
}
|
|
154
175
|
var EDGE_BITS = [1, 2, 4];
|
|
155
176
|
function projectAabbToScreen(box, viewProjection, rect) {
|
|
177
|
+
if (!(rect.width > 0 && rect.height > 0)) return null;
|
|
156
178
|
const corners = [];
|
|
157
179
|
for (let i = 0; i < 8; i++) {
|
|
158
180
|
const corner = {
|
|
@@ -186,7 +208,7 @@ function projectAabbToScreen(box, viewProjection, rect) {
|
|
|
186
208
|
for (const side of CLIP_SIDES) {
|
|
187
209
|
const da = side(a);
|
|
188
210
|
const db = side(b);
|
|
189
|
-
if (da < 0 && db < 0) {
|
|
211
|
+
if (Number.isNaN(da) || Number.isNaN(db) || da < 0 && db < 0) {
|
|
190
212
|
t0 = 1;
|
|
191
213
|
t1 = 0;
|
|
192
214
|
break;
|
|
@@ -200,7 +222,8 @@ function projectAabbToScreen(box, viewProjection, rect) {
|
|
|
200
222
|
}
|
|
201
223
|
}
|
|
202
224
|
if (!any) return null;
|
|
203
|
-
|
|
225
|
+
const out = { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
226
|
+
return Number.isFinite(out.x + out.y + out.width + out.height) ? out : null;
|
|
204
227
|
}
|
|
205
228
|
function rectOf(viewport) {
|
|
206
229
|
return {
|
|
@@ -217,8 +240,9 @@ function rayAt(viewport, point) {
|
|
|
217
240
|
return rayThroughScreenPoint(point, rectOf(viewport), viewProjectionOf(viewport));
|
|
218
241
|
}
|
|
219
242
|
function projectPoint(p, viewport) {
|
|
243
|
+
if (!(viewport.width > 0 && viewport.height > 0)) return null;
|
|
220
244
|
const [x, y, z, w] = transformPoint4(viewProjectionOf(viewport), p);
|
|
221
|
-
if (!(w > 0) || z
|
|
245
|
+
if (!(w > 0) || !(z >= -w)) return null;
|
|
222
246
|
const screen = ndcToScreen({ x: x / w, y: y / w }, rectOf(viewport));
|
|
223
247
|
return Number.isFinite(screen.x) && Number.isFinite(screen.y) ? screen : null;
|
|
224
248
|
}
|
|
@@ -257,8 +281,8 @@ function worldPoses(scene, reading) {
|
|
|
257
281
|
return (id) => frame.world(id);
|
|
258
282
|
}
|
|
259
283
|
const adapter = scenePoseAdapter(untyped);
|
|
260
|
-
const
|
|
261
|
-
return (id) => composeWorldPose(adapter, id,
|
|
284
|
+
const compose3 = scene.composition.compose;
|
|
285
|
+
return (id) => composeWorldPose(adapter, id, compose3);
|
|
262
286
|
}
|
|
263
287
|
function boxAt(world, node, pose) {
|
|
264
288
|
if (world.bounds) return world.bounds(pose === node.pose ? node : { ...node, pose });
|
|
@@ -517,7 +541,7 @@ function createSession3d(inputs) {
|
|
|
517
541
|
return {
|
|
518
542
|
at(p, mods) {
|
|
519
543
|
if (!frame) return unsnapped(p);
|
|
520
|
-
const vp = world.viewport();
|
|
544
|
+
const vp = world.viewport(inputs.viewId);
|
|
521
545
|
const screen = frame.anchor(vp);
|
|
522
546
|
const anchor = screen && castOnto(vp, screen, up, frame.offset);
|
|
523
547
|
const hit = screen && castOnto(vp, { x: screen.x + p.x - req.press.x, y: screen.y + p.y - req.press.y }, up, frame.offset);
|
|
@@ -532,16 +556,17 @@ function createSession3d(inputs) {
|
|
|
532
556
|
store.set([]);
|
|
533
557
|
} else {
|
|
534
558
|
const probes = frame.probes(anchor);
|
|
535
|
-
const
|
|
536
|
-
|
|
559
|
+
const at = probes.map((q) => ({ id: q.id, at: tuple(q.at), role: q.role }));
|
|
560
|
+
const res = resolveHolding(candidatesOf(inputs, sources, probes, delta0, vp, origin, up), (kept) => resolveSnap({
|
|
561
|
+
probes: at,
|
|
537
562
|
input,
|
|
538
563
|
delta0: tuple(delta0),
|
|
539
|
-
candidates:
|
|
564
|
+
candidates: kept,
|
|
540
565
|
toScreen: (w) => {
|
|
541
566
|
const s = projectPoint(vec3Of(w), vp);
|
|
542
567
|
return s ? [s.x, s.y] : [NaN, NaN];
|
|
543
568
|
}
|
|
544
|
-
});
|
|
569
|
+
}), vec3Of);
|
|
545
570
|
delta = vec3Of(res.delta);
|
|
546
571
|
held = res.members.length > 0;
|
|
547
572
|
store.set(resolvedSnapMarks(res.satisfied, delta));
|
|
@@ -632,16 +657,20 @@ function movedOnLevel(pose, delta, upAxis) {
|
|
|
632
657
|
const position = { ...add(pose.position, delta), [upAxis]: pose.position[upAxis] };
|
|
633
658
|
return { ...pose, position };
|
|
634
659
|
}
|
|
635
|
-
function createNodeAtPoint(world) {
|
|
636
|
-
return (point, exclude) =>
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
660
|
+
function createNodeAtPoint(world, viewId) {
|
|
661
|
+
return (point, exclude) => pickOnRay(world, viewId, point, exclude);
|
|
662
|
+
}
|
|
663
|
+
function pickOnRay(world, viewId, point, exclude) {
|
|
664
|
+
const ray = rayAt(world.viewport(viewId), point);
|
|
665
|
+
if (!ray) return null;
|
|
666
|
+
return worldPickIndex(world).nearestOnRay(ray, exclude ? new Set(exclude) : null, 1);
|
|
667
|
+
}
|
|
668
|
+
function createPickEvery(world) {
|
|
669
|
+
return (point, view) => pickOnRay(world, view?.viewId, point);
|
|
641
670
|
}
|
|
642
|
-
function createAreaSelect(world, selection) {
|
|
671
|
+
function createAreaSelect(world, selection, viewId) {
|
|
643
672
|
return {
|
|
644
|
-
hitTestArea: (bounds) => worldPickIndex(world).inScreenRect(world.viewport(), bounds),
|
|
673
|
+
hitTestArea: (bounds) => worldPickIndex(world).inScreenRect(world.viewport(viewId), bounds),
|
|
645
674
|
getSelection: () => [...selection.get()],
|
|
646
675
|
setSelection: (ids) => selection.set([...ids])
|
|
647
676
|
};
|
|
@@ -668,25 +697,26 @@ function createSnap(world, opts = {}) {
|
|
|
668
697
|
world,
|
|
669
698
|
sources,
|
|
670
699
|
store,
|
|
700
|
+
viewId: opts.viewId,
|
|
671
701
|
reachPx: opts.reachPx ?? opts.kitSettings?.get("targets.snapPx") ?? DEFAULT_SNAP_PX
|
|
672
702
|
});
|
|
673
703
|
}
|
|
674
704
|
};
|
|
675
705
|
}
|
|
676
|
-
function createPoseDescriptor(world) {
|
|
706
|
+
function createPoseDescriptor(world, viewId) {
|
|
677
707
|
const up = world.up ?? DEFAULT_UP;
|
|
678
708
|
const upAxis = groundAxes(up).up;
|
|
679
709
|
const specialized = /* @__PURE__ */ new WeakMap();
|
|
680
710
|
let lastCastable = null;
|
|
681
711
|
function castableViewport() {
|
|
682
|
-
const vp = world.viewport();
|
|
712
|
+
const vp = world.viewport(viewId);
|
|
683
713
|
const rect = rectOf(vp);
|
|
684
714
|
if (rayAt(vp, { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 })) lastCastable = vp;
|
|
685
715
|
return lastCastable;
|
|
686
716
|
}
|
|
687
717
|
function build3(worldBox) {
|
|
688
718
|
const boundsIn = (vp, pose) => projectAabbToScreen(worldBox(pose), viewProjectionOf(vp), rectOf(vp));
|
|
689
|
-
const boundsOf = (pose) => boundsIn(world.viewport(), pose);
|
|
719
|
+
const boundsOf = (pose) => boundsIn(world.viewport(viewId), pose);
|
|
690
720
|
const descriptor = {
|
|
691
721
|
forNode(node) {
|
|
692
722
|
let d = specialized.get(node);
|
|
@@ -719,8 +749,8 @@ function createPoseDescriptor(world) {
|
|
|
719
749
|
const ky = src.height === 0 ? 1 : dst.height / src.height;
|
|
720
750
|
const from = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
|
|
721
751
|
const to = {
|
|
722
|
-
x: dst.x + (from.x - src.x) * kx,
|
|
723
|
-
y: dst.y + (from.y - src.y) * ky
|
|
752
|
+
x: from.x + (dst.x - src.x) + (from.x - src.x) * (kx - 1),
|
|
753
|
+
y: from.y + (dst.y - src.y) + (from.y - src.y) * (ky - 1)
|
|
724
754
|
};
|
|
725
755
|
const plane = viewPlaneAt(vp.camera, pose.position);
|
|
726
756
|
const before = onPlane(vp, plane, from);
|
|
@@ -824,7 +854,7 @@ function createInsert(opts) {
|
|
|
824
854
|
const { u, v } = groundAxes(up);
|
|
825
855
|
return {
|
|
826
856
|
commit(bounds, extras, ends, select) {
|
|
827
|
-
const vp = opts.viewport();
|
|
857
|
+
const vp = opts.viewport(opts.viewId);
|
|
828
858
|
const hits = footprintPoints(bounds, ends, (p) => groundHit(vp, p, up));
|
|
829
859
|
if (hits.length === 0) return null;
|
|
830
860
|
let minU = Infinity, maxU = -Infinity, minV = Infinity, maxV = -Infinity;
|
|
@@ -940,7 +970,7 @@ function aimSpace3d(viewport, viewId, opts = {}) {
|
|
|
940
970
|
},
|
|
941
971
|
unproject(px) {
|
|
942
972
|
const hit = groundHit(viewport, { x: px.x + ox, y: px.y + oy }, up);
|
|
943
|
-
return hit && toAimPoint(hit, axes);
|
|
973
|
+
return hit && { ...toAimPoint(hit, axes), z: 0 };
|
|
944
974
|
}
|
|
945
975
|
};
|
|
946
976
|
}
|
|
@@ -949,8 +979,8 @@ function cameraOfAim3d(aim) {
|
|
|
949
979
|
}
|
|
950
980
|
var AXES = ["x", "y", "z"];
|
|
951
981
|
var BITS = [1, 2, 4];
|
|
952
|
-
var
|
|
953
|
-
var ACROSS = { x: [
|
|
982
|
+
var UNIT2 = { x: { x: 1, y: 0, z: 0 }, y: { x: 0, y: 1, z: 0 }, z: { x: 0, y: 0, z: 1 } };
|
|
983
|
+
var ACROSS = { x: [UNIT2.y, UNIT2.z], y: [UNIT2.x, UNIT2.z], z: [UNIT2.x, UNIT2.y] };
|
|
954
984
|
function boxesNear(world, q, r) {
|
|
955
985
|
return snapBoxes(world, q.exclude, q.probes.map(({ at: p }) => padQuery([p.x - r, p.y - r, p.z - r, p.x + r, p.y + r, p.z + r])));
|
|
956
986
|
}
|
|
@@ -1067,7 +1097,9 @@ function groundGridSource(opts) {
|
|
|
1067
1097
|
const up = normalize(opts.up ?? DEFAULT_UP);
|
|
1068
1098
|
const [u, v] = planeBasis(up);
|
|
1069
1099
|
const lines = (c) => {
|
|
1070
|
-
const
|
|
1100
|
+
const k = Math.round(c / opts.step);
|
|
1101
|
+
if (!Number.isSafeInteger(k)) return [];
|
|
1102
|
+
const near = k * opts.step;
|
|
1071
1103
|
return [near, near + (c >= near ? opts.step : -opts.step)];
|
|
1072
1104
|
};
|
|
1073
1105
|
return {
|
|
@@ -1134,9 +1166,10 @@ var HEAD = { lenRatio: 8, maxShare: 0.5, aspect: 7 / 16 };
|
|
|
1134
1166
|
var HEAD_OVERDRAW = 0.1;
|
|
1135
1167
|
function headFor(shaftHalf, linePx = Number.POSITIVE_INFINITY, head = HEAD) {
|
|
1136
1168
|
const wanted = shaftHalf * head.lenRatio;
|
|
1137
|
-
const
|
|
1169
|
+
const cap = head.maxShare === 0 ? 0 : head.maxShare * linePx;
|
|
1170
|
+
const headLen = Math.max(0, Math.min(wanted, cap));
|
|
1138
1171
|
const headHalf = headLen * head.aspect;
|
|
1139
|
-
const shrunk = wanted > 0 ? shaftHalf * headLen / wanted : shaftHalf;
|
|
1172
|
+
const shrunk = wanted > 0 ? shaftHalf * (headLen / wanted) : shaftHalf;
|
|
1140
1173
|
return { headLen, headHalf, shaftHalf: wanted > 0 ? Math.min(shrunk, headHalf) : shrunk };
|
|
1141
1174
|
}
|
|
1142
1175
|
function layoutLine(shaftHalf, length, pxPerUnit, head) {
|
|
@@ -1314,7 +1347,7 @@ void main() {
|
|
|
1314
1347
|
if (wanted > 0.0 && density > 0.0) {
|
|
1315
1348
|
headPx = max(0.0, min(wanted, a_shape.z * density * total));
|
|
1316
1349
|
headHalf = headPx * a_shape.w;
|
|
1317
|
-
shaft = min(shaftHalf * headPx / wanted, headHalf);
|
|
1350
|
+
shaft = min(shaftHalf * (headPx / wanted), headHalf);
|
|
1318
1351
|
shaftEnd = total - headPx / density * (1.0 - OVERDRAW);
|
|
1319
1352
|
}
|
|
1320
1353
|
|
|
@@ -1474,10 +1507,11 @@ function cameraStepper(dep, zero, relative, step) {
|
|
|
1474
1507
|
let reached = zero;
|
|
1475
1508
|
let written = origin;
|
|
1476
1509
|
let prior = origin;
|
|
1510
|
+
let caughtUp = false;
|
|
1477
1511
|
return (at) => {
|
|
1478
1512
|
if (!dep || !origin) return;
|
|
1479
1513
|
const now = dep.get();
|
|
1480
|
-
if (now !== written && now !== prior) {
|
|
1514
|
+
if (now !== written && (caughtUp || now !== prior)) {
|
|
1481
1515
|
origin = now;
|
|
1482
1516
|
from = reached;
|
|
1483
1517
|
}
|
|
@@ -1485,9 +1519,11 @@ function cameraStepper(dep, zero, relative, step) {
|
|
|
1485
1519
|
written = step(origin, relative(at, from), dep);
|
|
1486
1520
|
reached = at;
|
|
1487
1521
|
dep.set(written);
|
|
1522
|
+
caughtUp = dep.get() === written;
|
|
1488
1523
|
};
|
|
1489
1524
|
}
|
|
1490
1525
|
function dragCamera(ctx, kind, step) {
|
|
1526
|
+
if (!ctx.deps.camera3d) return {};
|
|
1491
1527
|
const apply = cameraStepper(ctx.deps.camera3d, { x: 0, y: 0 }, (a, b) => ({ x: a.x - b.x, y: a.y - b.y }), step);
|
|
1492
1528
|
return {
|
|
1493
1529
|
kind,
|
|
@@ -1550,13 +1586,14 @@ var dollyAction = {
|
|
|
1550
1586
|
timing: "immediate",
|
|
1551
1587
|
run(deps, params) {
|
|
1552
1588
|
const dep = deps.camera3d;
|
|
1553
|
-
if (!dep) return;
|
|
1589
|
+
if (!dep) return "pass";
|
|
1554
1590
|
const factor = typeof params?.scale === "number" ? 1 / params.scale : Math.exp(
|
|
1555
1591
|
(typeof params?.deltaY === "number" ? params.deltaY : 0) * (deps.kitSettings?.get("orbit3d.dollyRate") ?? DOLLY_RATE)
|
|
1556
1592
|
);
|
|
1557
|
-
if (!(factor > 0) || !Number.isFinite(factor)) return;
|
|
1593
|
+
if (!(factor > 0) || !Number.isFinite(factor) || factor === 1) return "pass";
|
|
1558
1594
|
const pane = dep.size();
|
|
1559
1595
|
dep.set(dollyToward(dep.get(), factor, paneAnchor(wheelPoint(params), dep, pane), pane, dep.limits?.()));
|
|
1596
|
+
return void 0;
|
|
1560
1597
|
}
|
|
1561
1598
|
}
|
|
1562
1599
|
};
|
|
@@ -1570,6 +1607,7 @@ var pinchDollyAction = {
|
|
|
1570
1607
|
timing: "ongoing",
|
|
1571
1608
|
start(ctx) {
|
|
1572
1609
|
const dep = ctx.deps.camera3d;
|
|
1610
|
+
if (!dep) return {};
|
|
1573
1611
|
const startSpread = ctx.multiTouch?.spread ?? 0;
|
|
1574
1612
|
const at = ctx.multiTouch?.centroid;
|
|
1575
1613
|
const apply = cameraStepper(dep, 1, (a, b) => a / b, (origin, factor, d) => {
|
|
@@ -1598,7 +1636,9 @@ var homeAction = {
|
|
|
1598
1636
|
run(deps) {
|
|
1599
1637
|
const dep = deps.camera3d;
|
|
1600
1638
|
const home = dep?.home?.();
|
|
1601
|
-
if (dep
|
|
1639
|
+
if (!dep || !home) return "pass";
|
|
1640
|
+
dep.set(home);
|
|
1641
|
+
return void 0;
|
|
1602
1642
|
}
|
|
1603
1643
|
}
|
|
1604
1644
|
};
|
|
@@ -1621,6 +1661,6 @@ var kernel3dKitSettingsSchema = pref.group("3D camera", {
|
|
|
1621
1661
|
})
|
|
1622
1662
|
});
|
|
1623
1663
|
|
|
1624
|
-
export { DEFAULT_ORBIT_LIMITS, HEAD, HEAD_OVERDRAW, LINE_FLOATS, MAX_PITCH, POSE3_COMPOSITION, UNIT_CUBE, aabbOfPose, aimOf3d, aimSpace3d, alignPlaneSource, boxSnapSource, cameraEye, cameraOfAim3d, cameraView, cameraViewProjection, clampCamera, collectOverlayBoxes, createAreaSelect, createCamera, createInsert, createLinePass, createNodeAtPoint, createPoseDescriptor, createSnap, dollyAction, dollyBy, dollyToward, groundGridSource, headFor, homeAction, kernel3dKitSettingsSchema, layoutLine, ndcToScreen, orbitAction, orbitBy, packLines, panAction, panBy, pinchDollyAction, pose3, poseMatrix, projectAabbToScreen, projectPoint, projectSnapMarks, rayThroughScreenPoint, screenBoxOf, screenToNdc, useOrbitTool, visibleRuns, worldPoseOf };
|
|
1664
|
+
export { DEFAULT_ORBIT_LIMITS, HEAD, HEAD_OVERDRAW, LINE_FLOATS, MAX_PITCH, POSE3_COMPOSITION, UNIT_CUBE, aabbOfPose, aimOf3d, aimSpace3d, alignPlaneSource, boxSnapSource, cameraEye, cameraOfAim3d, cameraView, cameraViewProjection, clampCamera, collectOverlayBoxes, createAreaSelect, createCamera, createInsert, createLinePass, createNodeAtPoint, createPickEvery, createPoseDescriptor, createSnap, dollyAction, dollyBy, dollyToward, groundGridSource, headFor, homeAction, kernel3dKitSettingsSchema, layoutLine, ndcToScreen, orbitAction, orbitBy, packLines, panAction, panBy, pinchDollyAction, pose3, poseMatrix, projectAabbToScreen, projectPoint, projectSnapMarks, rayThroughScreenPoint, screenBoxOf, screenToNdc, useOrbitTool, visibleRuns, worldPoseOf };
|
|
1625
1665
|
//# sourceMappingURL=index.js.map
|
|
1626
1666
|
//# sourceMappingURL=index.js.map
|