@viamrobotics/motion-tools 0.7.0 → 0.9.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/WorldObject.d.ts +2 -0
- package/dist/components/Camera.svelte +15 -17
- package/dist/components/CameraControls.svelte +11 -0
- package/dist/components/Focus.svelte +1 -1
- package/dist/components/Geometry.svelte +1 -1
- package/dist/components/Line.svelte +39 -0
- package/dist/components/Line.svelte.d.ts +7 -0
- package/dist/components/Pointclouds.svelte +3 -3
- package/dist/components/RefreshRate.svelte +4 -4
- package/dist/components/SceneProviders.svelte +4 -4
- package/dist/components/Shapes.svelte +12 -7
- package/dist/components/Tree/Settings.svelte +53 -12
- package/dist/hooks/{useShapes.svelte.d.ts → useDrawAPI.svelte.d.ts} +10 -2
- package/dist/hooks/{useShapes.svelte.js → useDrawAPI.svelte.js} +65 -4
- package/dist/hooks/useFrames.svelte.js +2 -13
- package/dist/hooks/useGeometries.svelte.js +22 -17
- package/dist/hooks/useMachineSettings.svelte.d.ts +8 -0
- package/dist/hooks/useMachineSettings.svelte.js +40 -0
- package/dist/hooks/useObjects.svelte.js +8 -7
- package/dist/hooks/usePointclouds.svelte.js +28 -21
- package/dist/hooks/usePose.svelte.js +3 -3
- package/dist/hooks/usePoses.svelte.js +2 -2
- package/dist/hooks/useSettings.svelte.d.ts +2 -0
- package/dist/hooks/useSettings.svelte.js +3 -1
- package/package.json +1 -1
- package/dist/hooks/useRefreshRates.svelte.d.ts +0 -5
- package/dist/hooks/useRefreshRates.svelte.js +0 -23
package/dist/WorldObject.d.ts
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { T } from '@threlte/core'
|
|
3
|
-
import { PerspectiveCamera, OrthographicCamera } from 'three'
|
|
4
3
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
5
4
|
|
|
6
5
|
let { children, ...rest } = $props()
|
|
7
6
|
|
|
8
7
|
const settings = useSettings()
|
|
9
8
|
const mode = $derived(settings.current.cameraMode)
|
|
10
|
-
|
|
11
|
-
const perspective = new PerspectiveCamera()
|
|
12
|
-
perspective.near = 0.01
|
|
13
|
-
perspective.up.set(0, 0, 1)
|
|
14
|
-
|
|
15
|
-
const orthographic = new OrthographicCamera()
|
|
16
|
-
orthographic.near = -100
|
|
17
|
-
orthographic.far = 100
|
|
18
|
-
orthographic.up.set(0, 0, 1)
|
|
19
|
-
orthographic.zoom = 200
|
|
20
9
|
</script>
|
|
21
10
|
|
|
22
11
|
{#if mode === 'perspective'}
|
|
23
|
-
<T
|
|
24
|
-
is={perspective}
|
|
12
|
+
<T.PerspectiveCamera
|
|
25
13
|
makeDefault
|
|
14
|
+
near={0.01}
|
|
15
|
+
up={[0, 0, 1]}
|
|
16
|
+
oncreate={(ref) => {
|
|
17
|
+
ref.lookAt(0, 0, 0)
|
|
18
|
+
}}
|
|
26
19
|
{...rest}
|
|
27
20
|
>
|
|
28
21
|
{@render children?.()}
|
|
29
|
-
</T>
|
|
22
|
+
</T.PerspectiveCamera>
|
|
30
23
|
{:else if mode === 'orthographic'}
|
|
31
|
-
<T
|
|
32
|
-
is={orthographic}
|
|
24
|
+
<T.OrthographicCamera
|
|
33
25
|
makeDefault
|
|
26
|
+
near={-100}
|
|
27
|
+
far={100}
|
|
28
|
+
up={[0, 0, 1]}
|
|
29
|
+
oncreate={(ref) => {
|
|
30
|
+
ref.lookAt(0, 0, 0)
|
|
31
|
+
}}
|
|
34
32
|
{...rest}
|
|
35
33
|
>
|
|
36
34
|
{@render children?.()}
|
|
37
|
-
</T>
|
|
35
|
+
</T.OrthographicCamera>
|
|
38
36
|
{/if}
|
|
@@ -4,10 +4,21 @@
|
|
|
4
4
|
import KeyboardControls from './KeyboardControls.svelte'
|
|
5
5
|
import Portal from './portal/Portal.svelte'
|
|
6
6
|
import Button from './dashboard/Button.svelte'
|
|
7
|
+
import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
7
8
|
|
|
9
|
+
const drawAPI = useDrawAPI()
|
|
8
10
|
const transformControls = useTransformControls()
|
|
9
11
|
|
|
10
12
|
let ref = $state.raw<CameraControlsRef>()
|
|
13
|
+
|
|
14
|
+
$effect(() => {
|
|
15
|
+
if (drawAPI.camera) {
|
|
16
|
+
const { position, lookAt, animate } = drawAPI.camera
|
|
17
|
+
ref?.setPosition(position.x, position.y, position.z, animate)
|
|
18
|
+
ref?.setLookAt(position.x, position.y, position.z, lookAt.x, lookAt.y, lookAt.z, animate)
|
|
19
|
+
drawAPI.clearCamera()
|
|
20
|
+
}
|
|
21
|
+
})
|
|
11
22
|
</script>
|
|
12
23
|
|
|
13
24
|
<Portal id="dashboard">
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { T } from '@threlte/core'
|
|
3
|
+
import { Instance, InstancedMesh } from '@threlte/extras'
|
|
4
|
+
import Frame from './Frame.svelte'
|
|
5
|
+
import type { WorldObject } from '../WorldObject'
|
|
6
|
+
import { useSettings } from '../hooks/useSettings.svelte'
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
object: WorldObject
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { object }: Props = $props()
|
|
13
|
+
|
|
14
|
+
const settings = useSettings()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<Frame
|
|
18
|
+
{...object}
|
|
19
|
+
metadata={{
|
|
20
|
+
...object.metadata,
|
|
21
|
+
lineWidth: settings.current.lineWidth,
|
|
22
|
+
}}
|
|
23
|
+
/>
|
|
24
|
+
|
|
25
|
+
{#if object.metadata.lineDotColor && object.metadata.points}
|
|
26
|
+
<InstancedMesh frustumCulled={false}>
|
|
27
|
+
<T.SphereGeometry />
|
|
28
|
+
<T.MeshBasicMaterial color={object.metadata.lineDotColor} />
|
|
29
|
+
|
|
30
|
+
{#each object.metadata.points as { x, y, z }, i (i)}
|
|
31
|
+
<Instance
|
|
32
|
+
position.x={x}
|
|
33
|
+
position.y={y}
|
|
34
|
+
position.z={z}
|
|
35
|
+
scale={Number(settings.current.lineDotSize)}
|
|
36
|
+
/>
|
|
37
|
+
{/each}
|
|
38
|
+
</InstancedMesh>
|
|
39
|
+
{/if}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Portal } from './portal'
|
|
3
3
|
import { usePointClouds } from '../hooks/usePointclouds.svelte'
|
|
4
|
-
import {
|
|
4
|
+
import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
5
5
|
import Pointcloud from './Pointcloud.svelte'
|
|
6
6
|
|
|
7
7
|
const points = usePointClouds()
|
|
8
|
-
const
|
|
8
|
+
const drawAPI = useDrawAPI()
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
{#each points.current as object (object.uuid)}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</Portal>
|
|
15
15
|
{/each}
|
|
16
16
|
|
|
17
|
-
{#each
|
|
17
|
+
{#each drawAPI.points as object (object.uuid)}
|
|
18
18
|
<Portal id={object.referenceFrame}>
|
|
19
19
|
<Pointcloud {object} />
|
|
20
20
|
</Portal>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Select } from '@viamrobotics/prime-core'
|
|
3
|
-
import {
|
|
3
|
+
import { useMachineSettings } from '../hooks/useMachineSettings.svelte'
|
|
4
4
|
import type { Snippet } from 'svelte'
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
let { name, children }: Props = $props()
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
const rate = $derived(
|
|
13
|
+
const { refreshRates } = useMachineSettings()
|
|
14
|
+
const rate = $derived(refreshRates.get(name))
|
|
15
15
|
</script>
|
|
16
16
|
|
|
17
17
|
<label class="flex flex-col gap-1">
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
onchange={(event: InputEvent) => {
|
|
21
21
|
if (event.target instanceof HTMLSelectElement) {
|
|
22
22
|
const { value } = event.target
|
|
23
|
-
|
|
23
|
+
refreshRates.set(name, Number.parseInt(value, 10))
|
|
24
24
|
}
|
|
25
25
|
}}
|
|
26
26
|
value={String(rate ?? '')}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { provideSelection } from '../hooks/useSelection.svelte'
|
|
7
7
|
import { provideStaticGeometries } from '../hooks/useStaticGeometries.svelte'
|
|
8
8
|
import { provideVisibility } from '../hooks/useVisibility.svelte'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { provideDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
10
|
+
import { provideMachineSettings } from '../hooks/useMachineSettings.svelte'
|
|
11
11
|
import { provideTransformControls } from '../hooks/useControls.svelte'
|
|
12
12
|
import type { Snippet } from 'svelte'
|
|
13
13
|
import { provideObjects } from '../hooks/useObjects.svelte'
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
provideSettings()
|
|
28
28
|
provideTransformControls()
|
|
29
29
|
provideVisibility()
|
|
30
|
-
|
|
30
|
+
provideMachineSettings()
|
|
31
31
|
provideLogs()
|
|
32
32
|
|
|
33
33
|
provideOrigin()
|
|
34
34
|
provideStaticGeometries()
|
|
35
|
-
|
|
35
|
+
provideDrawAPI()
|
|
36
36
|
|
|
37
37
|
provideFrames(() => partID.current)
|
|
38
38
|
provideGeometries(() => partID.current)
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { T } from '@threlte/core'
|
|
3
3
|
import { Portal, PortalTarget } from './portal'
|
|
4
|
-
import {
|
|
4
|
+
import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
5
5
|
import WorldObject from './WorldObject.svelte'
|
|
6
6
|
import Frame from './Frame.svelte'
|
|
7
|
+
import Line from './Line.svelte'
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
+
const drawAPI = useDrawAPI()
|
|
9
10
|
</script>
|
|
10
11
|
|
|
11
12
|
<T
|
|
12
|
-
name={
|
|
13
|
-
is={
|
|
13
|
+
name={drawAPI.object3ds.batchedArrow.object3d.name}
|
|
14
|
+
is={drawAPI.object3ds.batchedArrow.object3d}
|
|
14
15
|
dispose={false}
|
|
15
16
|
/>
|
|
16
17
|
|
|
17
|
-
{#each
|
|
18
|
+
{#each drawAPI.meshes as object (object.uuid)}
|
|
18
19
|
<Portal id={object.referenceFrame}>
|
|
19
20
|
<Frame
|
|
20
21
|
uuid={object.uuid}
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
</Portal>
|
|
29
30
|
{/each}
|
|
30
31
|
|
|
31
|
-
{#each
|
|
32
|
+
{#each drawAPI.nurbs as object (object.uuid)}
|
|
32
33
|
<Portal id={object.referenceFrame}>
|
|
33
34
|
<Frame
|
|
34
35
|
uuid={object.uuid}
|
|
@@ -42,8 +43,12 @@
|
|
|
42
43
|
</Portal>
|
|
43
44
|
{/each}
|
|
44
45
|
|
|
45
|
-
{#each
|
|
46
|
+
{#each drawAPI.models as object (object.uuid)}
|
|
46
47
|
<WorldObject {object}>
|
|
47
48
|
<PortalTarget id={object.name} />
|
|
48
49
|
</WorldObject>
|
|
49
50
|
{/each}
|
|
51
|
+
|
|
52
|
+
{#each drawAPI.lines as object (object.uuid)}
|
|
53
|
+
<Line {object} />
|
|
54
|
+
{/each}
|
|
@@ -4,8 +4,14 @@
|
|
|
4
4
|
import { useMotionClient } from '../../hooks/useMotionClient.svelte'
|
|
5
5
|
import Drawer from './Drawer.svelte'
|
|
6
6
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
7
|
+
import { useResourceNames } from '@viamrobotics/svelte-sdk'
|
|
8
|
+
import { usePartID } from '../../hooks/usePartID.svelte'
|
|
9
|
+
import { useMachineSettings } from '../../hooks/useMachineSettings.svelte'
|
|
7
10
|
|
|
11
|
+
const partID = usePartID()
|
|
12
|
+
const cameras = useResourceNames(() => partID.current, 'camera')
|
|
8
13
|
const settings = useSettings()
|
|
14
|
+
const { disabledCameras } = useMachineSettings()
|
|
9
15
|
const motionClient = useMotionClient()
|
|
10
16
|
</script>
|
|
11
17
|
|
|
@@ -14,20 +20,30 @@
|
|
|
14
20
|
defaultOpen
|
|
15
21
|
>
|
|
16
22
|
<div class="flex h-100 flex-col gap-2 overflow-scroll p-3">
|
|
17
|
-
<h3 class="text-
|
|
23
|
+
<h3 class="text-sm"><strong>Machine connection</strong></h3>
|
|
18
24
|
|
|
19
|
-
<RefreshRate name="Frames">
|
|
20
|
-
<option value="0">Do not fetch</option>
|
|
21
|
-
<option value="1">Fetch on reconfigure</option>
|
|
22
|
-
</RefreshRate>
|
|
23
|
-
<RefreshRate name="Pointclouds" />
|
|
24
25
|
<RefreshRate name="Geometries" />
|
|
25
26
|
<RefreshRate name="Poses" />
|
|
26
|
-
|
|
27
|
-
<
|
|
27
|
+
<RefreshRate name="Pointclouds" />
|
|
28
|
+
<div>
|
|
29
|
+
<div>Enabled pointcloud cameras</div>
|
|
30
|
+
{#each cameras.current as camera (camera)}
|
|
31
|
+
<div class="flex items-center justify-between gap-4 py-2">
|
|
32
|
+
{camera.name}
|
|
33
|
+
<Switch
|
|
34
|
+
on={disabledCameras.get(camera.name) !== true}
|
|
35
|
+
on:change={(event) => {
|
|
36
|
+
disabledCameras.set(camera.name, !event.detail)
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
{:else}
|
|
41
|
+
No cameras detected
|
|
42
|
+
{/each}
|
|
43
|
+
</div>
|
|
28
44
|
|
|
29
45
|
<label class="flex flex-col gap-1">
|
|
30
|
-
|
|
46
|
+
Motion client
|
|
31
47
|
<Select
|
|
32
48
|
onchange={(event: InputEvent) => {
|
|
33
49
|
if (event.target instanceof HTMLSelectElement) {
|
|
@@ -42,7 +58,7 @@
|
|
|
42
58
|
</Select>
|
|
43
59
|
</label>
|
|
44
60
|
|
|
45
|
-
<h3 class="text-
|
|
61
|
+
<h3 class="pt-2 text-sm"><strong>Pointclouds</strong></h3>
|
|
46
62
|
<div class="flex flex-col gap-2.5">
|
|
47
63
|
<label class="flex items-center justify-between gap-2">
|
|
48
64
|
Default point size
|
|
@@ -68,7 +84,7 @@
|
|
|
68
84
|
</label>
|
|
69
85
|
</div>
|
|
70
86
|
|
|
71
|
-
<h3 class="text-
|
|
87
|
+
<h3 class="pt-2 text-sm"><strong>Grid</strong></h3>
|
|
72
88
|
<div class="flex flex-col gap-2.5">
|
|
73
89
|
<label class="flex items-center justify-between gap-2">
|
|
74
90
|
Enabled <Switch bind:on={settings.current.grid} />
|
|
@@ -108,7 +124,32 @@
|
|
|
108
124
|
</label>
|
|
109
125
|
</div>
|
|
110
126
|
|
|
111
|
-
<h3 class="text-
|
|
127
|
+
<h3 class="pt-2 text-sm"><strong>Lines</strong></h3>
|
|
128
|
+
<div class="flex flex-col gap-2.5">
|
|
129
|
+
<label class="flex items-center justify-between gap-2">
|
|
130
|
+
Thickness
|
|
131
|
+
|
|
132
|
+
<div class="w-20">
|
|
133
|
+
<Input
|
|
134
|
+
bind:value={settings.current.lineWidth}
|
|
135
|
+
on:keydown={(event) => event.stopImmediatePropagation()}
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
</label>
|
|
139
|
+
|
|
140
|
+
<label class="flex items-center justify-between gap-2">
|
|
141
|
+
Dot size
|
|
142
|
+
|
|
143
|
+
<div class="w-20">
|
|
144
|
+
<Input
|
|
145
|
+
bind:value={settings.current.lineDotSize}
|
|
146
|
+
on:keydown={(event) => event.stopImmediatePropagation()}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</label>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<h3 class="pt-2 text-sm"><strong>Misc</strong></h3>
|
|
112
153
|
<div class="flex flex-col gap-2.5">
|
|
113
154
|
<label class="flex items-center justify-between gap-2">
|
|
114
155
|
Render stats <Switch bind:on={settings.current.renderStats} />
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { Vector3 } from 'three';
|
|
1
2
|
import { BatchedArrow } from '../three/BatchedArrow';
|
|
2
3
|
import { WorldObject, type PointsGeometry } from '../WorldObject';
|
|
3
4
|
type ConnectionStatus = 'connecting' | 'open' | 'closed';
|
|
4
5
|
interface Context {
|
|
5
6
|
points: WorldObject<PointsGeometry>[];
|
|
7
|
+
lines: WorldObject[];
|
|
6
8
|
meshes: WorldObject[];
|
|
7
9
|
poses: WorldObject[];
|
|
8
10
|
nurbs: WorldObject[];
|
|
@@ -11,7 +13,13 @@ interface Context {
|
|
|
11
13
|
object3ds: {
|
|
12
14
|
batchedArrow: BatchedArrow;
|
|
13
15
|
};
|
|
16
|
+
camera: {
|
|
17
|
+
position: Vector3;
|
|
18
|
+
lookAt: Vector3;
|
|
19
|
+
animate: boolean;
|
|
20
|
+
} | undefined;
|
|
21
|
+
clearCamera: () => void;
|
|
14
22
|
}
|
|
15
|
-
export declare const
|
|
16
|
-
export declare const
|
|
23
|
+
export declare const provideDrawAPI: () => void;
|
|
24
|
+
export declare const useDrawAPI: () => Context;
|
|
17
25
|
export {};
|
|
@@ -5,7 +5,7 @@ import { parsePcdInWorker } from '../loaders/pcd';
|
|
|
5
5
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
6
6
|
import { BatchedArrow } from '../three/BatchedArrow';
|
|
7
7
|
import { WorldObject } from '../WorldObject';
|
|
8
|
-
const key = Symbol('
|
|
8
|
+
const key = Symbol('draw-api-context-key');
|
|
9
9
|
const tryParse = (json) => {
|
|
10
10
|
try {
|
|
11
11
|
return JSON.parse(json);
|
|
@@ -31,7 +31,7 @@ class Float32Reader {
|
|
|
31
31
|
return result;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
export const
|
|
34
|
+
export const provideDrawAPI = () => {
|
|
35
35
|
let pointsIndex = 0;
|
|
36
36
|
let geometryIndex = 0;
|
|
37
37
|
let poseIndex = 0;
|
|
@@ -39,10 +39,12 @@ export const provideShapes = () => {
|
|
|
39
39
|
const maxReconnectDelay = 5_000;
|
|
40
40
|
let ws;
|
|
41
41
|
const points = $state([]);
|
|
42
|
+
const lines = $state([]);
|
|
42
43
|
const meshes = $state([]);
|
|
43
44
|
const poses = $state([]);
|
|
44
45
|
const nurbs = $state([]);
|
|
45
46
|
const models = $state([]);
|
|
47
|
+
let camera = $state.raw();
|
|
46
48
|
let connectionStatus = $state('connecting');
|
|
47
49
|
const color = new Color();
|
|
48
50
|
const direction = new Vector3();
|
|
@@ -172,11 +174,45 @@ export const provideShapes = () => {
|
|
|
172
174
|
: {
|
|
173
175
|
color: new Color(r, g, b).convertLinearToSRGB(),
|
|
174
176
|
};
|
|
175
|
-
points.push(new WorldObject(label
|
|
177
|
+
points.push(new WorldObject(label, undefined, undefined, {
|
|
176
178
|
case: 'points',
|
|
177
179
|
value: positions,
|
|
178
180
|
}, metadata));
|
|
179
181
|
};
|
|
182
|
+
const addLine = async (reader) => {
|
|
183
|
+
// Read label length
|
|
184
|
+
const labelLen = reader.read();
|
|
185
|
+
let label = '';
|
|
186
|
+
for (let i = 0; i < labelLen; i++) {
|
|
187
|
+
label += String.fromCharCode(reader.read());
|
|
188
|
+
}
|
|
189
|
+
// Read counts
|
|
190
|
+
const nPoints = reader.read();
|
|
191
|
+
// Read default color
|
|
192
|
+
const lineR = reader.read();
|
|
193
|
+
const lineG = reader.read();
|
|
194
|
+
const lineB = reader.read();
|
|
195
|
+
const dotR = reader.read();
|
|
196
|
+
const dotG = reader.read();
|
|
197
|
+
const dotB = reader.read();
|
|
198
|
+
// Read positions
|
|
199
|
+
const positions = new Float32Array(nPoints * 3);
|
|
200
|
+
for (let i = 0; i < nPoints * 3; i++) {
|
|
201
|
+
positions[i] = reader.read();
|
|
202
|
+
}
|
|
203
|
+
const points = [];
|
|
204
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
205
|
+
points.push(new Vector3(positions[i], positions[i + 1], positions[i + 2]));
|
|
206
|
+
}
|
|
207
|
+
lines.push(new WorldObject(label, undefined, undefined, {
|
|
208
|
+
case: 'line',
|
|
209
|
+
value: positions,
|
|
210
|
+
}, {
|
|
211
|
+
points,
|
|
212
|
+
color: lineR === -1 ? undefined : new Color().setRGB(lineR, lineG, lineB),
|
|
213
|
+
lineDotColor: dotR === -1 ? undefined : new Color().setRGB(dotR, dotG, dotB),
|
|
214
|
+
}));
|
|
215
|
+
};
|
|
180
216
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
217
|
const addGeometries = (geometries, colors, parent) => {
|
|
182
218
|
let i = 0;
|
|
@@ -224,10 +260,16 @@ export const provideShapes = () => {
|
|
|
224
260
|
models.splice(index, 1);
|
|
225
261
|
continue;
|
|
226
262
|
}
|
|
263
|
+
index = lines.findIndex((m) => m.name === name);
|
|
264
|
+
if (index !== -1) {
|
|
265
|
+
lines.splice(index, 1);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
227
268
|
}
|
|
228
269
|
};
|
|
229
270
|
const removeAll = () => {
|
|
230
271
|
points.splice(0, points.length);
|
|
272
|
+
lines.splice(0, lines.length);
|
|
231
273
|
meshes.splice(0, meshes.length);
|
|
232
274
|
nurbs.splice(0, nurbs.length);
|
|
233
275
|
models.splice(0, models.length);
|
|
@@ -270,6 +312,9 @@ export const provideShapes = () => {
|
|
|
270
312
|
return addPoses(reader);
|
|
271
313
|
}
|
|
272
314
|
else if (type === 2) {
|
|
315
|
+
return addLine(reader);
|
|
316
|
+
}
|
|
317
|
+
else if (type === 3) {
|
|
273
318
|
return addPCD(reader.buffer);
|
|
274
319
|
}
|
|
275
320
|
else {
|
|
@@ -279,6 +324,13 @@ export const provideShapes = () => {
|
|
|
279
324
|
const data = tryParse(event.data);
|
|
280
325
|
if (!data)
|
|
281
326
|
return;
|
|
327
|
+
if ('setCameraPose' in data) {
|
|
328
|
+
camera = {
|
|
329
|
+
position: new Vector3(data.Position.X, data.Position.Y, data.Position.Z),
|
|
330
|
+
lookAt: new Vector3(data.LookAt.X, data.LookAt.Y, data.LookAt.Z),
|
|
331
|
+
animate: data.Animate,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
282
334
|
if ('geometries' in data) {
|
|
283
335
|
return addGeometries(data.geometries, data.colors, data.parent);
|
|
284
336
|
}
|
|
@@ -310,6 +362,9 @@ export const provideShapes = () => {
|
|
|
310
362
|
get points() {
|
|
311
363
|
return points;
|
|
312
364
|
},
|
|
365
|
+
get lines() {
|
|
366
|
+
return lines;
|
|
367
|
+
},
|
|
313
368
|
get meshes() {
|
|
314
369
|
return meshes;
|
|
315
370
|
},
|
|
@@ -328,8 +383,14 @@ export const provideShapes = () => {
|
|
|
328
383
|
object3ds: {
|
|
329
384
|
batchedArrow,
|
|
330
385
|
},
|
|
386
|
+
get camera() {
|
|
387
|
+
return camera;
|
|
388
|
+
},
|
|
389
|
+
clearCamera: () => {
|
|
390
|
+
camera = undefined;
|
|
391
|
+
},
|
|
331
392
|
});
|
|
332
393
|
};
|
|
333
|
-
export const
|
|
394
|
+
export const useDrawAPI = () => {
|
|
334
395
|
return getContext(key);
|
|
335
396
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getContext, setContext, untrack } from 'svelte';
|
|
2
2
|
import { useRobotClient, createRobotQuery, useMachineStatus, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import { WorldObject } from '../WorldObject';
|
|
4
|
-
import { useRefreshRates } from './useRefreshRates.svelte';
|
|
5
4
|
import { observe } from '@threlte/core';
|
|
6
5
|
import { useLogs } from './useLogs.svelte';
|
|
7
6
|
import { resourceColors } from '../color';
|
|
@@ -11,24 +10,14 @@ export const provideFrames = (partID) => {
|
|
|
11
10
|
const client = useRobotClient(partID);
|
|
12
11
|
const machineStatus = useMachineStatus(partID);
|
|
13
12
|
const logs = useLogs();
|
|
14
|
-
const refreshRates = useRefreshRates();
|
|
15
|
-
if (!refreshRates.has('Frames')) {
|
|
16
|
-
refreshRates.set('Frames', 1);
|
|
17
|
-
}
|
|
18
13
|
const query = createRobotQuery(client, 'frameSystemConfig');
|
|
19
14
|
const revision = $derived(machineStatus.current?.config.revision);
|
|
20
|
-
const shouldFetch = $derived(refreshRates.get('Frames') === 1);
|
|
21
15
|
observe.pre(() => [revision], () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
logs.add('Fetching frames...');
|
|
25
|
-
}
|
|
16
|
+
untrack(() => query.current).refetch();
|
|
17
|
+
logs.add('Fetching frames...');
|
|
26
18
|
});
|
|
27
19
|
const current = $derived.by(() => {
|
|
28
20
|
const objects = [];
|
|
29
|
-
if (!shouldFetch) {
|
|
30
|
-
return objects;
|
|
31
|
-
}
|
|
32
21
|
for (const { frame } of query.current.data ?? []) {
|
|
33
22
|
if (frame === undefined) {
|
|
34
23
|
continue;
|
|
@@ -3,7 +3,7 @@ import { createQueries, queryOptions } from '@tanstack/svelte-query';
|
|
|
3
3
|
import { createResourceClient, useResourceNames } from '@viamrobotics/svelte-sdk';
|
|
4
4
|
import { setContext, getContext } from 'svelte';
|
|
5
5
|
import { fromStore, toStore } from 'svelte/store';
|
|
6
|
-
import {
|
|
6
|
+
import { useMachineSettings } from './useMachineSettings.svelte';
|
|
7
7
|
import { WorldObject } from '../WorldObject';
|
|
8
8
|
import { usePersistentUUIDs } from './usePersistentUUIDs.svelte';
|
|
9
9
|
import { useLogs } from './useLogs.svelte';
|
|
@@ -15,7 +15,7 @@ export const provideGeometries = (partID) => {
|
|
|
15
15
|
const cameras = useResourceNames(partID, 'camera');
|
|
16
16
|
const grippers = useResourceNames(partID, 'gripper');
|
|
17
17
|
const logs = useLogs();
|
|
18
|
-
const refreshRates =
|
|
18
|
+
const { refreshRates } = useMachineSettings();
|
|
19
19
|
const armClients = $derived(arms.current.map((arm) => createResourceClient(ArmClient, partID, () => arm.name)));
|
|
20
20
|
const gripperClients = $derived(grippers.current.map((gripper) => createResourceClient(GripperClient, partID, () => gripper.name)));
|
|
21
21
|
const cameraClients = $derived(cameras.current.map((camera) => createResourceClient(CameraClient, partID, () => camera.name)));
|
|
@@ -23,22 +23,27 @@ export const provideGeometries = (partID) => {
|
|
|
23
23
|
if (!refreshRates.has('Geometries')) {
|
|
24
24
|
refreshRates.set('Geometries', 1000);
|
|
25
25
|
}
|
|
26
|
-
const options = $derived
|
|
26
|
+
const options = $derived.by(() => {
|
|
27
27
|
const interval = refreshRates.get('Geometries');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const client of clients) {
|
|
30
|
+
const options = queryOptions({
|
|
31
|
+
enabled: interval !== -1 && client.current !== undefined,
|
|
32
|
+
refetchInterval: interval === 0 ? false : interval,
|
|
33
|
+
queryKey: ['partID', partID(), client.current?.name, 'getGeometries'],
|
|
34
|
+
queryFn: async () => {
|
|
35
|
+
if (!client.current) {
|
|
36
|
+
throw new Error('No client');
|
|
37
|
+
}
|
|
38
|
+
logs.add(`Fetching geometries for ${client.current.name}...`);
|
|
39
|
+
const geometries = await client.current.getGeometries();
|
|
40
|
+
return { name: client.current.name, geometries };
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
results.push(options);
|
|
44
|
+
}
|
|
45
|
+
return results;
|
|
46
|
+
});
|
|
42
47
|
const { updateUUIDs } = usePersistentUUIDs();
|
|
43
48
|
const queries = fromStore(createQueries({ queries: toStore(() => options) }));
|
|
44
49
|
const geometries = $derived.by(() => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
2
|
+
type Context = {
|
|
3
|
+
refreshRates: SvelteMap<string, number>;
|
|
4
|
+
disabledCameras: SvelteMap<string, boolean>;
|
|
5
|
+
};
|
|
6
|
+
export declare const provideMachineSettings: () => void;
|
|
7
|
+
export declare const useMachineSettings: () => Context;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { get, set } from 'idb-keyval';
|
|
2
|
+
import { getContext, setContext } from 'svelte';
|
|
3
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
4
|
+
const key = Symbol('polling-rate-context');
|
|
5
|
+
const refreshRatesKey = 'polling-rate';
|
|
6
|
+
const disabledCamerasKey = 'disabled-cameras';
|
|
7
|
+
const setFromEntries = (map, entries) => {
|
|
8
|
+
if (entries) {
|
|
9
|
+
for (const [key, value] of entries) {
|
|
10
|
+
map.set(key, value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export const provideMachineSettings = () => {
|
|
15
|
+
const refreshRates = new SvelteMap();
|
|
16
|
+
const disabledCameras = new SvelteMap();
|
|
17
|
+
get(refreshRatesKey).then((entries) => {
|
|
18
|
+
setFromEntries(refreshRates, entries);
|
|
19
|
+
});
|
|
20
|
+
get(disabledCamerasKey).then((entries) => {
|
|
21
|
+
setFromEntries(disabledCameras, entries);
|
|
22
|
+
});
|
|
23
|
+
$effect(() => {
|
|
24
|
+
set(refreshRatesKey, [...refreshRates.entries()]);
|
|
25
|
+
});
|
|
26
|
+
$effect(() => {
|
|
27
|
+
set(disabledCamerasKey, [...disabledCameras.entries()]);
|
|
28
|
+
});
|
|
29
|
+
setContext(key, {
|
|
30
|
+
get refreshRates() {
|
|
31
|
+
return refreshRates;
|
|
32
|
+
},
|
|
33
|
+
get disabledCameras() {
|
|
34
|
+
return disabledCameras;
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export const useMachineSettings = () => {
|
|
39
|
+
return getContext(key);
|
|
40
|
+
};
|
|
@@ -2,25 +2,26 @@ import { getContext, setContext } from 'svelte';
|
|
|
2
2
|
import { useFrames } from './useFrames.svelte';
|
|
3
3
|
import { useGeometries } from './useGeometries.svelte';
|
|
4
4
|
import { useStaticGeometries } from './useStaticGeometries.svelte';
|
|
5
|
-
import {
|
|
5
|
+
import { useDrawAPI } from './useDrawAPI.svelte';
|
|
6
6
|
import { usePointClouds } from './usePointclouds.svelte';
|
|
7
7
|
const key = Symbol('objects-context');
|
|
8
8
|
export const provideObjects = () => {
|
|
9
9
|
const frames = useFrames();
|
|
10
10
|
const geometries = useGeometries();
|
|
11
11
|
const statics = useStaticGeometries();
|
|
12
|
-
const
|
|
12
|
+
const drawAPI = useDrawAPI();
|
|
13
13
|
const points = usePointClouds();
|
|
14
14
|
const objects = $derived([
|
|
15
15
|
...frames.current,
|
|
16
16
|
...geometries.current,
|
|
17
17
|
...points.current,
|
|
18
|
-
...shapes.meshes,
|
|
19
|
-
...shapes.models,
|
|
20
|
-
...shapes.nurbs,
|
|
21
|
-
...shapes.points,
|
|
22
18
|
...statics.current,
|
|
23
|
-
...
|
|
19
|
+
...drawAPI.meshes,
|
|
20
|
+
...drawAPI.models,
|
|
21
|
+
...drawAPI.nurbs,
|
|
22
|
+
...drawAPI.points,
|
|
23
|
+
...drawAPI.lines,
|
|
24
|
+
...drawAPI.poses,
|
|
24
25
|
]);
|
|
25
26
|
setContext(key, {
|
|
26
27
|
get current() {
|
|
@@ -4,39 +4,46 @@ import { setContext, getContext } from 'svelte';
|
|
|
4
4
|
import { fromStore, toStore } from 'svelte/store';
|
|
5
5
|
import { createResourceClient, useResourceNames } from '@viamrobotics/svelte-sdk';
|
|
6
6
|
import { parsePcdInWorker } from '../loaders/pcd';
|
|
7
|
-
import {
|
|
7
|
+
import { useMachineSettings } from './useMachineSettings.svelte';
|
|
8
8
|
import { WorldObject } from '../WorldObject';
|
|
9
9
|
import { usePersistentUUIDs } from './usePersistentUUIDs.svelte';
|
|
10
10
|
import { useLogs } from './useLogs.svelte';
|
|
11
11
|
const key = Symbol('pointcloud-context');
|
|
12
12
|
export const providePointclouds = (partID) => {
|
|
13
13
|
const logs = useLogs();
|
|
14
|
-
const refreshRates =
|
|
14
|
+
const { refreshRates, disabledCameras } = useMachineSettings();
|
|
15
15
|
const cameras = useResourceNames(partID, 'camera');
|
|
16
16
|
if (!refreshRates.has('Pointclouds')) {
|
|
17
17
|
refreshRates.set('Pointclouds', -1);
|
|
18
18
|
}
|
|
19
19
|
const clients = $derived(cameras.current.map((camera) => createResourceClient(CameraClient, partID, () => camera.name)));
|
|
20
|
-
const options = $derived
|
|
21
|
-
const name = cameraClient.current?.name ?? '';
|
|
20
|
+
const options = $derived.by(() => {
|
|
22
21
|
const interval = refreshRates.get('Pointclouds');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const cameraClient of clients) {
|
|
24
|
+
const name = cameraClient.current?.name ?? '';
|
|
25
|
+
const options = queryOptions({
|
|
26
|
+
enabled: interval !== -1 &&
|
|
27
|
+
cameraClient.current !== undefined &&
|
|
28
|
+
disabledCameras.get(name) !== true,
|
|
29
|
+
refetchInterval: interval === 0 ? false : interval,
|
|
30
|
+
queryKey: ['partID', partID(), name, 'getPointCloud'],
|
|
31
|
+
queryFn: async () => {
|
|
32
|
+
if (!cameraClient.current) {
|
|
33
|
+
throw new Error('No camera client');
|
|
34
|
+
}
|
|
35
|
+
logs.add(`Fetching pointcloud for ${cameraClient.current.name}`);
|
|
36
|
+
const response = await cameraClient.current.getPointCloud();
|
|
37
|
+
if (!response)
|
|
38
|
+
return null;
|
|
39
|
+
const { positions, colors } = await parsePcdInWorker(new Uint8Array(response));
|
|
40
|
+
return new WorldObject(`${name}:pointcloud`, undefined, name, { case: 'points', value: positions }, colors ? { colors } : undefined);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
results.push(options);
|
|
44
|
+
}
|
|
45
|
+
return results;
|
|
46
|
+
});
|
|
40
47
|
const { updateUUIDs } = usePersistentUUIDs();
|
|
41
48
|
const queries = fromStore(createQueries({
|
|
42
49
|
queries: toStore(() => options),
|
|
@@ -2,17 +2,17 @@ import { createResourceClient, useResourceNames } from '@viamrobotics/svelte-sdk
|
|
|
2
2
|
import { usePartID } from './usePartID.svelte';
|
|
3
3
|
import { MotionClient } from '@viamrobotics/sdk';
|
|
4
4
|
import { createQuery, queryOptions } from '@tanstack/svelte-query';
|
|
5
|
-
import {
|
|
5
|
+
import { useMachineSettings } from './useMachineSettings.svelte';
|
|
6
6
|
import { fromStore, toStore } from 'svelte/store';
|
|
7
7
|
import { useMotionClient } from './useMotionClient.svelte';
|
|
8
8
|
export const usePose = (name, parent) => {
|
|
9
|
-
const refreshRates =
|
|
9
|
+
const { refreshRates } = useMachineSettings();
|
|
10
10
|
const partID = usePartID();
|
|
11
11
|
const motionClient = useMotionClient();
|
|
12
12
|
const resources = useResourceNames(() => partID.current);
|
|
13
13
|
const resource = $derived(resources.current.find((resource) => resource.name === name()));
|
|
14
14
|
const client = createResourceClient(MotionClient, () => partID.current, () => motionClient.current ?? '');
|
|
15
|
-
const interval = refreshRates.get('Poses');
|
|
15
|
+
const interval = $derived(refreshRates.get('Poses'));
|
|
16
16
|
const options = $derived(queryOptions({
|
|
17
17
|
enabled: interval !== -1 && client.current !== undefined && resource !== undefined,
|
|
18
18
|
refetchInterval: interval === 0 ? false : interval,
|
|
@@ -3,10 +3,10 @@ import { MotionClient, PoseInFrame, ResourceName } from '@viamrobotics/sdk';
|
|
|
3
3
|
import { createResourceClient, useResourceNames } from '@viamrobotics/svelte-sdk';
|
|
4
4
|
import { getContext, setContext } from 'svelte';
|
|
5
5
|
import { fromStore, toStore } from 'svelte/store';
|
|
6
|
-
import {
|
|
6
|
+
import { useMachineSettings } from './useMachineSettings.svelte';
|
|
7
7
|
const key = Symbol('poses-context');
|
|
8
8
|
export const providePoses = (partID) => {
|
|
9
|
-
const refreshRates =
|
|
9
|
+
const { refreshRates } = useMachineSettings();
|
|
10
10
|
const resources = useResourceNames(partID);
|
|
11
11
|
const components = $derived(resources.current.filter(({ type }) => type === 'component'));
|
|
12
12
|
const motionResources = useResourceNames(partID, 'motion');
|
package/package.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { get, set } from 'idb-keyval';
|
|
2
|
-
import { getContext, setContext } from 'svelte';
|
|
3
|
-
import { SvelteMap } from 'svelte/reactivity';
|
|
4
|
-
const key = Symbol('polling-rate-context');
|
|
5
|
-
const idbKey = 'polling-rate';
|
|
6
|
-
export const provideRefreshRates = () => {
|
|
7
|
-
const map = new SvelteMap();
|
|
8
|
-
get(idbKey).then((entries) => {
|
|
9
|
-
if (entries) {
|
|
10
|
-
for (const [key, value] of entries) {
|
|
11
|
-
map.set(key, value);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
$effect(() => {
|
|
16
|
-
set(idbKey, [...map.entries()]);
|
|
17
|
-
});
|
|
18
|
-
setContext(key, map);
|
|
19
|
-
return map;
|
|
20
|
-
};
|
|
21
|
-
export const useRefreshRates = () => {
|
|
22
|
-
return getContext(key);
|
|
23
|
-
};
|