@viamrobotics/motion-tools 1.12.2 → 1.13.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/assets/ferndale_studio_11_1k.hdr +0 -0
- package/dist/components/App.svelte +11 -25
- package/dist/components/App.svelte.d.ts +3 -3
- package/dist/components/Geometry.svelte +42 -42
- package/dist/components/Scene.svelte +4 -1
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Selected.svelte +9 -9
- package/dist/components/StaticGeometries.svelte +5 -2
- package/dist/components/overlay/Details.svelte +3 -3
- package/dist/components/overlay/FloatingPanel.svelte +3 -0
- package/dist/components/overlay/FloatingPanel.svelte.d.ts +1 -0
- package/dist/components/overlay/LiveUpdatesBanner.svelte +3 -3
- package/dist/components/overlay/Logs.svelte +75 -0
- package/dist/components/overlay/__tests__/__fixtures__/resource.d.ts +10 -1
- package/dist/components/overlay/__tests__/__fixtures__/resource.js +1 -0
- package/dist/components/overlay/dashboard/Dashboard.svelte +1 -1
- package/dist/components/overlay/left-pane/TreeContainer.svelte +0 -3
- package/dist/hooks/use3DModels.svelte.js +10 -0
- package/dist/hooks/useConfigFrames.svelte.d.ts +9 -0
- package/dist/hooks/useConfigFrames.svelte.js +92 -0
- package/dist/hooks/useFramelessComponents.svelte.js +2 -2
- package/dist/hooks/useFrames.svelte.d.ts +1 -6
- package/dist/hooks/useFrames.svelte.js +39 -145
- package/dist/hooks/usePartConfig.svelte.d.ts +10 -19
- package/dist/hooks/usePartConfig.svelte.js +138 -165
- package/dist/hooks/useVisibility.svelte.js +0 -12
- package/package.json +1 -1
- package/dist/components/overlay/left-pane/Logs.svelte +0 -52
- /package/dist/components/overlay/{left-pane/Logs.svelte.d.ts → Logs.svelte.d.ts} +0 -0
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Transform } from '@viamrobotics/sdk';
|
|
2
|
-
interface FrameTransform {
|
|
3
|
-
type: 'machine' | 'config' | 'fragment';
|
|
4
|
-
transform: Transform;
|
|
5
|
-
}
|
|
6
2
|
interface FramesContext {
|
|
7
|
-
current:
|
|
8
|
-
getParentFrameOptions: (componentName: string) => string[];
|
|
3
|
+
current: Transform[];
|
|
9
4
|
}
|
|
10
5
|
export declare const provideFrames: (partID: () => string) => void;
|
|
11
6
|
export declare const useFrames: () => FramesContext;
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { getContext, setContext, untrack } from 'svelte';
|
|
2
|
-
import { Transform } from '@viamrobotics/sdk';
|
|
3
|
-
import { useRobotClient, createRobotQuery, useMachineStatus } from '@viamrobotics/svelte-sdk';
|
|
2
|
+
import { MachineConnectionEvent, Transform } from '@viamrobotics/sdk';
|
|
3
|
+
import { useRobotClient, createRobotQuery, useMachineStatus, useConnectionStatus, } from '@viamrobotics/svelte-sdk';
|
|
4
4
|
import { useLogs } from './useLogs.svelte';
|
|
5
5
|
import { resourceNameToColor } from '../color';
|
|
6
|
-
import { createTransformFromFrame } from '../frame';
|
|
7
|
-
import { usePartConfig } from './usePartConfig.svelte';
|
|
8
6
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
9
7
|
import { createPose } from '../transform';
|
|
10
8
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
11
9
|
import { traits, useWorld } from '../ecs';
|
|
10
|
+
import { useConfigFrames } from './useConfigFrames.svelte';
|
|
12
11
|
const key = Symbol('frames-context');
|
|
13
12
|
export const provideFrames = (partID) => {
|
|
13
|
+
const configFrames = useConfigFrames();
|
|
14
14
|
const environment = useEnvironment();
|
|
15
15
|
const world = useWorld();
|
|
16
16
|
const resourceByName = useResourceByName();
|
|
17
17
|
const client = useRobotClient(partID);
|
|
18
|
+
const connectionStatus = useConnectionStatus(partID);
|
|
18
19
|
const machineStatus = useMachineStatus(partID);
|
|
19
20
|
const logs = useLogs();
|
|
21
|
+
const isEditMode = $derived(environment.current.viewerMode === 'edit');
|
|
20
22
|
const query = createRobotQuery(client, 'frameSystemConfig', () => ({
|
|
21
|
-
enabled: partID() !== '' &&
|
|
23
|
+
enabled: partID() !== '' && !isEditMode,
|
|
22
24
|
}));
|
|
23
25
|
const revision = $derived(machineStatus.current?.config?.revision);
|
|
24
|
-
const partConfig = usePartConfig();
|
|
25
26
|
$effect(() => {
|
|
26
27
|
if (query.isFetching) {
|
|
27
28
|
logs.add('Fetching frames...');
|
|
@@ -30,131 +31,40 @@ export const provideFrames = (partID) => {
|
|
|
30
31
|
logs.add(`Frames: ${query.error.message}`, 'error');
|
|
31
32
|
}
|
|
32
33
|
});
|
|
33
|
-
$
|
|
34
|
-
if (partConfig.isDirty) {
|
|
35
|
-
environment.current.viewerMode = 'edit';
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
environment.current.viewerMode = 'monitor';
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
const machineFrames = $derived.by(() => {
|
|
34
|
+
const frames = $derived.by(() => {
|
|
42
35
|
const frames = {};
|
|
43
36
|
for (const { frame } of query.data ?? []) {
|
|
44
37
|
if (frame === undefined) {
|
|
45
38
|
continue;
|
|
46
39
|
}
|
|
47
|
-
frames[frame.referenceFrame] =
|
|
48
|
-
type: 'machine',
|
|
49
|
-
transform: frame,
|
|
50
|
-
};
|
|
40
|
+
frames[frame.referenceFrame] = frame;
|
|
51
41
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const results = {};
|
|
57
|
-
const unsetResults = [];
|
|
58
|
-
for (const { name, frame } of components ?? []) {
|
|
59
|
-
if (!frame) {
|
|
60
|
-
unsetResults.push(name);
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
results[name] = {
|
|
64
|
-
type: 'config',
|
|
65
|
-
transform: createTransformFromFrame(name, frame),
|
|
42
|
+
if (isEditMode || connectionStatus.current === MachineConnectionEvent.DISCONNECTED) {
|
|
43
|
+
const mergedFrames = {
|
|
44
|
+
...frames,
|
|
45
|
+
...configFrames.current,
|
|
66
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Remove frames that have just been deleted locally for optimistic updates,
|
|
49
|
+
* or frames that have been removed by fragment overrides
|
|
50
|
+
*/
|
|
51
|
+
for (const name of configFrames.unsetFrames) {
|
|
52
|
+
delete mergedFrames[name];
|
|
53
|
+
}
|
|
54
|
+
return mergedFrames;
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const unsetResults = [];
|
|
75
|
-
// deal with fragment defined components
|
|
76
|
-
for (const fragmentComponentName of fragmentDefinedComponents || []) {
|
|
77
|
-
const fragmentId = partConfig.componentNameToFragmentId[fragmentComponentName];
|
|
78
|
-
const fragmentMod = fragmentMods?.find((mod) => mod.fragment_id === fragmentId);
|
|
79
|
-
if (!fragmentMod) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
const setComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$set']?.[`components.${fragmentComponentName}.frame`] !== undefined);
|
|
83
|
-
const unsetComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$unset']?.[`components.${fragmentComponentName}.frame`] !== undefined);
|
|
84
|
-
if (setComponentModIndex < unsetComponentModIndex) {
|
|
85
|
-
unsetResults.push(fragmentComponentName);
|
|
86
|
-
}
|
|
87
|
-
else if (unsetComponentModIndex < setComponentModIndex) {
|
|
88
|
-
const frameData = fragmentMod.mods[setComponentModIndex]['$set'][`components.${fragmentComponentName}.frame`];
|
|
89
|
-
results[fragmentComponentName] = {
|
|
90
|
-
type: 'fragment',
|
|
91
|
-
transform: createTransformFromFrame(fragmentComponentName, frameData),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return [results, unsetResults];
|
|
96
|
-
});
|
|
97
|
-
const frames = $derived.by(() => {
|
|
98
|
-
const result = {
|
|
99
|
-
...machineFrames,
|
|
100
|
-
...configFrames,
|
|
101
|
-
...fragmentFrames,
|
|
102
|
-
};
|
|
103
|
-
// Remove frames that have just been deleted locally for optimistic updates
|
|
104
|
-
for (const name of configUnsetFrameNames) {
|
|
105
|
-
delete result[name];
|
|
106
|
-
}
|
|
107
|
-
// Remove frames that have been removed by fragment overrides
|
|
108
|
-
for (const name of fragmentUnsetFrameNames) {
|
|
109
|
-
delete result[name];
|
|
110
|
-
}
|
|
111
|
-
return result;
|
|
56
|
+
/**
|
|
57
|
+
* If we're not in edit mode and we have a robot connection,
|
|
58
|
+
* we only use frames reported by the machine
|
|
59
|
+
*
|
|
60
|
+
*/
|
|
61
|
+
return frames;
|
|
112
62
|
});
|
|
113
63
|
const current = $derived(Object.values(frames));
|
|
114
64
|
const entities = new Map();
|
|
115
65
|
$effect.pre(() => {
|
|
116
66
|
if (revision) {
|
|
117
|
-
untrack(
|
|
118
|
-
await query.refetch();
|
|
119
|
-
for (const [name, machineFrame] of Object.entries(machineFrames)) {
|
|
120
|
-
if (machineFrame === undefined) {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
const existing = entities.get(name);
|
|
124
|
-
if (existing) {
|
|
125
|
-
const pose = createPose(machineFrame.transform.poseInObserverFrame?.pose);
|
|
126
|
-
existing.set(traits.Pose, pose);
|
|
127
|
-
if (environment.current.viewerMode === 'monitor') {
|
|
128
|
-
// if we are in monitor mode, we want the network pose to overwrite any leftover edited poses
|
|
129
|
-
existing.set(traits.EditedPose, pose);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
$effect.pre(() => {
|
|
137
|
-
for (const [name, configFrame] of Object.entries(configFrames)) {
|
|
138
|
-
if (configFrame === undefined) {
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
const existing = entities.get(name);
|
|
142
|
-
if (existing) {
|
|
143
|
-
const pose = createPose(configFrame.transform.poseInObserverFrame?.pose);
|
|
144
|
-
existing.set(traits.EditedPose, pose);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
$effect.pre(() => {
|
|
149
|
-
for (const [name, fragmentFrame] of Object.entries(fragmentFrames)) {
|
|
150
|
-
if (fragmentFrame === undefined) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
const existing = entities.get(name);
|
|
154
|
-
if (existing) {
|
|
155
|
-
const pose = createPose(fragmentFrame.transform.poseInObserverFrame?.pose);
|
|
156
|
-
existing.set(traits.EditedPose, pose);
|
|
157
|
-
}
|
|
67
|
+
untrack(() => query.refetch());
|
|
158
68
|
}
|
|
159
69
|
});
|
|
160
70
|
$effect.pre(() => {
|
|
@@ -162,13 +72,13 @@ export const provideFrames = (partID) => {
|
|
|
162
72
|
if (frame === undefined) {
|
|
163
73
|
continue;
|
|
164
74
|
}
|
|
165
|
-
const name = frame.
|
|
166
|
-
const parent = frame.
|
|
167
|
-
const pose = createPose(frame.
|
|
168
|
-
const center = frame.
|
|
169
|
-
? createPose(frame.
|
|
75
|
+
const name = frame.referenceFrame;
|
|
76
|
+
const parent = frame.poseInObserverFrame?.referenceFrame;
|
|
77
|
+
const pose = createPose(frame.poseInObserverFrame?.pose);
|
|
78
|
+
const center = frame.physicalObject?.center
|
|
79
|
+
? createPose(frame.physicalObject.center)
|
|
170
80
|
: undefined;
|
|
171
|
-
const resourceName = resourceByName.current[frame.
|
|
81
|
+
const resourceName = resourceByName.current[frame.referenceFrame];
|
|
172
82
|
const color = resourceNameToColor(resourceName);
|
|
173
83
|
const existing = entities.get(name);
|
|
174
84
|
if (existing) {
|
|
@@ -188,10 +98,11 @@ export const provideFrames = (partID) => {
|
|
|
188
98
|
existing.set(traits.Center, center);
|
|
189
99
|
}
|
|
190
100
|
existing.remove(traits.Box, traits.Sphere, traits.BufferGeometry, traits.Capsule);
|
|
191
|
-
if (frame.
|
|
192
|
-
const geometry = traits.Geometry(frame.
|
|
101
|
+
if (frame.physicalObject) {
|
|
102
|
+
const geometry = traits.Geometry(frame.physicalObject);
|
|
193
103
|
existing.add(geometry);
|
|
194
104
|
}
|
|
105
|
+
existing.set(traits.EditedPose, pose);
|
|
195
106
|
continue;
|
|
196
107
|
}
|
|
197
108
|
const entityTraits = [
|
|
@@ -210,8 +121,8 @@ export const provideFrames = (partID) => {
|
|
|
210
121
|
if (center) {
|
|
211
122
|
entityTraits.push(traits.Center(center));
|
|
212
123
|
}
|
|
213
|
-
if (frame.
|
|
214
|
-
entityTraits.push(traits.Geometry(frame.
|
|
124
|
+
if (frame.physicalObject) {
|
|
125
|
+
entityTraits.push(traits.Geometry(frame.physicalObject));
|
|
215
126
|
}
|
|
216
127
|
const entity = world.spawn(...entityTraits);
|
|
217
128
|
entities.set(name, entity);
|
|
@@ -224,24 +135,7 @@ export const provideFrames = (partID) => {
|
|
|
224
135
|
}
|
|
225
136
|
}
|
|
226
137
|
});
|
|
227
|
-
const getParentFrameOptions = (componentName) => {
|
|
228
|
-
const validFrames = new Set(current.map((frame) => frame.transform.referenceFrame));
|
|
229
|
-
validFrames.add('world');
|
|
230
|
-
const frameNameQueue = [componentName];
|
|
231
|
-
while (frameNameQueue.length > 0) {
|
|
232
|
-
const frameName = frameNameQueue.shift();
|
|
233
|
-
if (frameName) {
|
|
234
|
-
validFrames.delete(frameName);
|
|
235
|
-
const frames = current.filter((frame) => frame.transform.poseInObserverFrame?.referenceFrame === frameName);
|
|
236
|
-
for (const frame of frames) {
|
|
237
|
-
frameNameQueue.push(frame.transform.referenceFrame);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return Array.from(validFrames);
|
|
242
|
-
};
|
|
243
138
|
setContext(key, {
|
|
244
|
-
getParentFrameOptions,
|
|
245
139
|
get current() {
|
|
246
140
|
return current;
|
|
247
141
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type Frame } from '../frame';
|
|
2
2
|
import { Struct, Pose } from '@viamrobotics/sdk';
|
|
3
|
-
import type { ViamClient } from '@viamrobotics/sdk';
|
|
4
3
|
export interface PartConfig {
|
|
5
4
|
components: {
|
|
6
5
|
name: string;
|
|
@@ -11,31 +10,23 @@ export interface PartConfig {
|
|
|
11
10
|
mods: any[];
|
|
12
11
|
}[];
|
|
13
12
|
}
|
|
14
|
-
interface PartConfigParams {
|
|
15
|
-
appEmbeddedPartConfigProps?: AppEmbeddedPartConfigProps;
|
|
16
|
-
standalonePartConfigProps?: StandalonePartConfigProps;
|
|
17
|
-
}
|
|
18
13
|
interface PartConfigContext {
|
|
14
|
+
current: PartConfig;
|
|
15
|
+
isDirty: boolean;
|
|
16
|
+
hasEditPermissions: boolean;
|
|
17
|
+
componentNameToFragmentId: Record<string, string>;
|
|
19
18
|
updateFrame: (componentName: string, referenceFrame: string, pose: Pose, geometry?: Frame['geometry']) => void;
|
|
20
|
-
saveLocalPartConfig: () => void;
|
|
21
|
-
resetLocalPartConfig: () => void;
|
|
22
19
|
deleteFrame: (componentName: string) => void;
|
|
23
20
|
createFrame: (componentName: string) => void;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
isDirty: boolean;
|
|
27
|
-
hasEditPermissions: boolean;
|
|
21
|
+
save: () => void;
|
|
22
|
+
discardChanges: () => void;
|
|
28
23
|
}
|
|
29
|
-
export declare const providePartConfig: (params: () =>
|
|
24
|
+
export declare const providePartConfig: (partID: () => string, params: () => AppEmbeddedPartConfigProps | undefined) => void;
|
|
30
25
|
export declare const usePartConfig: () => PartConfigContext;
|
|
31
26
|
interface AppEmbeddedPartConfigProps {
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
current: Struct;
|
|
28
|
+
isDirty: boolean;
|
|
29
|
+
componentToFragId: Record<string, string>;
|
|
34
30
|
setLocalPartConfig: (config: Struct) => void;
|
|
35
|
-
getComponentToFragId: () => Record<string, string>;
|
|
36
|
-
}
|
|
37
|
-
interface StandalonePartConfigProps {
|
|
38
|
-
viamClient: () => ViamClient | undefined;
|
|
39
|
-
partID: () => string;
|
|
40
31
|
}
|
|
41
32
|
export {};
|