@viamrobotics/motion-tools 1.15.2 → 1.15.4

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.
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">
2
2
  import type { CameraControlsRef } from '@threlte/extras'
3
3
 
4
- import { useTask } from '@threlte/core'
4
+ import { isInstanceOf, useTask } from '@threlte/core'
5
5
  import { PressedKeys } from 'runed'
6
- import { MathUtils } from 'three'
6
+ import { MathUtils, Vector3 } from 'three'
7
7
 
8
8
  import { useFocusedEntity, useSelectedEntity } from '../hooks/useSelection.svelte'
9
9
  import { useSettings } from '../hooks/useSettings.svelte'
@@ -35,7 +35,36 @@
35
35
  const left = $derived(keys.has('arrowleft'))
36
36
  const down = $derived(keys.has('arrowdown'))
37
37
  const right = $derived(keys.has('arrowright'))
38
- const any = $derived(w || s || a || d || r || f || up || left || down || right)
38
+ const anyKeysPressed = $derived(w || s || a || d || r || f || up || left || down || right)
39
+
40
+ const target = new Vector3()
41
+
42
+ const PERSPECTIVE_DISTANCE_FACTOR = 0.0001
43
+ const PERSPECTIVE_MIN_SPEED = 0.00001
44
+
45
+ const ORTHOGRAPHIC_ZOOM_FACTOR = 0.1
46
+ const ORTHOGRAPHIC_MIN_SPEED = 0.00005
47
+
48
+ const FALLBACK_SPEED = 0.001
49
+
50
+ const getMovementScale = () => {
51
+ const camera = cameraControls.camera
52
+
53
+ if (isInstanceOf(camera, 'PerspectiveCamera')) {
54
+ cameraControls.getTarget(target)
55
+
56
+ const distance = camera.position.distanceTo(target)
57
+ const scaled = distance * PERSPECTIVE_DISTANCE_FACTOR
58
+ return Math.max(scaled, PERSPECTIVE_MIN_SPEED)
59
+ }
60
+
61
+ if (isInstanceOf(camera, 'OrthographicCamera')) {
62
+ const scaled = ORTHOGRAPHIC_ZOOM_FACTOR / camera.zoom
63
+ return Math.max(scaled, ORTHOGRAPHIC_MIN_SPEED)
64
+ }
65
+
66
+ return FALLBACK_SPEED
67
+ }
39
68
 
40
69
  const { start, stop } = useTask(
41
70
  (delta) => {
@@ -46,44 +75,58 @@
46
75
  return
47
76
  }
48
77
 
78
+ const moveSpeed = getMovementScale() * dt
79
+ const rotateSpeed = 0.1 * MathUtils.DEG2RAD * dt
80
+ const tiltSpeed = 0.05 * MathUtils.DEG2RAD * dt
81
+ const dollySpeed = 0.005 * dt
82
+ const zoomSpeed = 0.5 * dt
83
+
49
84
  if (a) {
50
- cameraControls.truck(-0.01 * dt, 0, true)
85
+ cameraControls.truck(-moveSpeed * dt, 0, true)
51
86
  }
52
87
 
53
88
  if (d) {
54
- cameraControls.truck(0.01 * dt, 0, true)
89
+ cameraControls.truck(moveSpeed * dt, 0, true)
55
90
  }
56
91
 
57
92
  if (w) {
58
- cameraControls.forward(0.01 * dt, true)
93
+ cameraControls.forward(moveSpeed * dt, true)
59
94
  }
60
95
 
61
96
  if (s) {
62
- cameraControls.forward(-0.01 * dt, true)
97
+ cameraControls.forward(-moveSpeed * dt, true)
63
98
  }
64
99
 
65
100
  if (r) {
66
- cameraControls.dolly(0.01 * dt, true)
101
+ if (isInstanceOf(cameraControls.camera, 'PerspectiveCamera')) {
102
+ cameraControls.dolly(dollySpeed, true)
103
+ } else {
104
+ cameraControls.zoom(zoomSpeed, true)
105
+ }
67
106
  }
68
107
 
69
108
  if (f) {
70
- cameraControls.dolly(-0.01 * dt, true)
109
+ if (isInstanceOf(cameraControls.camera, 'PerspectiveCamera')) {
110
+ cameraControls.dolly(-dollySpeed, true)
111
+ } else {
112
+ cameraControls.zoom(-zoomSpeed, true)
113
+ }
71
114
  }
72
115
 
73
116
  if (left) {
74
- cameraControls.rotate(-0.1 * MathUtils.DEG2RAD * dt, 0, true)
117
+ cameraControls.rotate(-rotateSpeed, 0, true)
75
118
  }
76
119
 
77
120
  if (right) {
78
- cameraControls.rotate(0.1 * MathUtils.DEG2RAD * dt, 0, true)
121
+ cameraControls.rotate(rotateSpeed, 0, true)
79
122
  }
80
123
 
81
124
  if (up) {
82
- cameraControls.rotate(0, -0.05 * MathUtils.DEG2RAD * dt, true)
125
+ cameraControls.rotate(0, -tiltSpeed, true)
83
126
  }
84
127
 
85
128
  if (down) {
86
- cameraControls.rotate(0, 0.05 * MathUtils.DEG2RAD * dt, true)
129
+ cameraControls.rotate(0, tiltSpeed, true)
87
130
  }
88
131
  },
89
132
  {
@@ -93,7 +136,7 @@
93
136
  )
94
137
 
95
138
  $effect.pre(() => {
96
- if (any) {
139
+ if (anyKeysPressed) {
97
140
  start()
98
141
  } else {
99
142
  stop()
@@ -35,7 +35,7 @@
35
35
  intersection = event.intersections[0]
36
36
 
37
37
  // Only handle axis restrictions if a first point has been placed
38
- if (!p1) {
38
+ if (!p1 || !intersection) {
39
39
  return
40
40
  }
41
41
 
@@ -127,7 +127,7 @@
127
127
  {#if enabled}
128
128
  {#if intersection && step !== 'p2'}
129
129
  <MeasurePoint
130
- position={intersection?.point.toArray()}
130
+ position={intersection.point.toArray()}
131
131
  opacity={0.5}
132
132
  />
133
133
  {/if}
@@ -51,8 +51,9 @@
51
51
 
52
52
  keys.onKeys('-', () => {
53
53
  if (selectedCustomGeometry) {
54
- selectedCustomGeometry.destroy()
55
- entities.delete(selectedCustomGeometry)
54
+ const entity = selectedCustomGeometry
55
+ entity.destroy()
56
+ entities.delete(entity)
56
57
  selectedEntity.set()
57
58
  }
58
59
  })
@@ -6,7 +6,7 @@ const key = Symbol('anchors-context');
6
6
  export const provideAnchors = () => {
7
7
  const matrix4 = new Matrix4();
8
8
  const { renderer } = useThrelte();
9
- const { xrFrame, isPresenting } = useXR();
9
+ const { isPresenting } = useXR();
10
10
  const map = new WeakMap();
11
11
  let space = renderer.xr.getReferenceSpace();
12
12
  const createAnchor = (position, orientation) => {
@@ -14,14 +14,14 @@ export const provideAnchors = () => {
14
14
  if (space === null)
15
15
  return;
16
16
  const pose = new XRRigidTransform(position, orientation);
17
- return xrFrame.current.createAnchor?.(pose, space);
17
+ return renderer.xr.getFrame().createAnchor?.(pose, space);
18
18
  };
19
19
  const { start, stop } = useTask(() => {
20
20
  space ??= renderer.xr.getReferenceSpace();
21
21
  if (!space) {
22
22
  return;
23
23
  }
24
- const frame = xrFrame.current;
24
+ const frame = renderer.xr.getFrame();
25
25
  if (!frame.trackedAnchors) {
26
26
  return;
27
27
  }
@@ -1,4 +1,4 @@
1
1
  import { type QueryParameter, type QueryResult } from 'koota';
2
- export declare function useQuery<T extends QueryParameter[]>(...parameters: T): {
2
+ export declare const useQuery: <T extends QueryParameter[]>(...parameters: T) => {
3
3
  current: QueryResult<T>;
4
4
  };
@@ -1,49 +1,56 @@
1
- import { createQuery, $internal as internal } from 'koota';
2
- import { untrack } from 'svelte';
1
+ import { createQuery, $internal as internalKey } from 'koota';
2
+ import { createSubscriber } from 'svelte/reactivity';
3
3
  import { useWorld } from './useWorld';
4
- export function useQuery(...parameters) {
4
+ export const useQuery = (...parameters) => {
5
5
  const world = useWorld();
6
- const createdQuery = createQuery(...parameters);
7
- // Using internals to get the query data.
8
- const query = world[internal].queriesHashMap.get(createdQuery.hash);
9
- const initialQueryVersion = query?.version;
10
- let version = $state.raw(0);
11
- let entities = $state.raw(world.query(createdQuery));
12
- $effect(() => {
13
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
14
- version;
15
- // Compare the initial version to the current version to
16
- // see it the query has changed.
17
- const query = world[internal].queriesHashMap.get(createdQuery.hash);
18
- if (query?.version !== initialQueryVersion) {
19
- entities = world.query(createdQuery);
20
- }
21
- return untrack(() => {
22
- const unsubAdd = world.onQueryAdd(createdQuery, () => {
23
- entities = world.query(createdQuery);
24
- });
25
- const unsubRemove = world.onQueryRemove(createdQuery, () => {
26
- entities = world.query(createdQuery);
27
- });
28
- return () => {
29
- unsubAdd();
30
- unsubRemove();
31
- };
32
- });
33
- });
34
- const handler = () => {
35
- version += 1;
36
- };
37
- // Force reattaching event listeners when the world is reset.
38
- $effect(() => {
39
- world[internal].resetSubscriptions.add(handler);
6
+ const queryRef = createQuery(...parameters);
7
+ let cache = null;
8
+ const subscribe = createSubscriber((update) => {
9
+ let unsubAdd = () => { };
10
+ let unsubRemove = () => { };
11
+ const subscribe = () => {
12
+ unsubAdd = world.onQueryAdd(queryRef, update);
13
+ unsubRemove = world.onQueryRemove(queryRef, update);
14
+ // Check if query changed before subscriptions were attached
15
+ const query = world[internalKey].queriesHashMap.get(queryRef.hash);
16
+ if (query && cache && query.version !== cache.version) {
17
+ update();
18
+ }
19
+ };
20
+ const handleReset = () => {
21
+ cache = null;
22
+ unsubAdd();
23
+ unsubRemove();
24
+ subscribe();
25
+ update();
26
+ };
27
+ subscribe();
28
+ world[internalKey].resetSubscriptions.add(handleReset);
40
29
  return () => {
41
- world[internal].resetSubscriptions.delete(handler);
30
+ world[internalKey].resetSubscriptions.delete(handleReset);
31
+ unsubAdd();
32
+ unsubRemove();
42
33
  };
43
34
  });
35
+ const getResult = () => {
36
+ const query = world[internalKey].queriesHashMap.get(queryRef.hash);
37
+ if (query && cache?.hash === queryRef.hash && cache.version === query.version) {
38
+ return cache.result;
39
+ }
40
+ // eslint-disable-next-line unicorn/no-array-sort
41
+ const result = world.query(queryRef).sort();
42
+ const registeredQuery = world[internalKey].queriesHashMap.get(queryRef.hash);
43
+ cache = {
44
+ hash: queryRef.hash,
45
+ version: registeredQuery.version,
46
+ result,
47
+ };
48
+ return result;
49
+ };
44
50
  return {
45
51
  get current() {
46
- return entities;
52
+ subscribe();
53
+ return getResult();
47
54
  },
48
55
  };
49
- }
56
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "1.15.2",
3
+ "version": "1.15.4",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -25,10 +25,10 @@
25
25
  "@testing-library/jest-dom": "6.8.0",
26
26
  "@testing-library/svelte": "5.2.8",
27
27
  "@testing-library/user-event": "^14.6.1",
28
- "@threlte/core": "8.3.0",
29
- "@threlte/extras": "9.7.0",
30
- "@threlte/rapier": "3.2.0",
31
- "@threlte/xr": "1.0.8",
28
+ "@threlte/core": "8.5.0",
29
+ "@threlte/extras": "9.9.0",
30
+ "@threlte/rapier": "3.4.0",
31
+ "@threlte/xr": "1.4.0",
32
32
  "@types/bun": "1.2.21",
33
33
  "@types/earcut": "^3.0.0",
34
34
  "@types/lodash-es": "4.17.12",