@viamrobotics/motion-tools 1.29.1 → 1.31.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/components/App.svelte +4 -10
- package/dist/components/App.svelte.d.ts +2 -1
- package/dist/components/SelectedTransformControls.svelte +10 -1
- package/dist/components/overlay/AddFrames.svelte +1 -1
- package/dist/components/overlay/Details.svelte +18 -1
- package/dist/components/overlay/Logs.svelte +1 -1
- package/dist/components/overlay/dashboard/Button.svelte +1 -1
- package/dist/components/overlay/settings/Settings.svelte +1 -5
- package/dist/hooks/useConfigFrames.svelte.js +3 -3
- package/dist/hooks/useFramelessComponents.svelte.js +1 -1
- package/dist/hooks/usePartConfig.svelte.d.ts +6 -2
- package/dist/hooks/usePartConfig.svelte.js +23 -11
- package/dist/hooks/useSettings.svelte.d.ts +0 -1
- package/dist/hooks/useSettings.svelte.js +0 -1
- package/dist/lib.d.ts +1 -0
- package/dist/lib.js +1 -0
- package/dist/loaders/pcd/worker.inline.d.ts +1 -1
- package/dist/loaders/pcd/worker.inline.js +1 -1
- package/dist/loaders/pcd/worker.js +3 -1
- package/dist/plugins/Debug/Debug.svelte +5 -0
- package/dist/plugins/Debug/Debug.svelte.d.ts +18 -0
- package/dist/plugins/Selection/Ellipse.svelte +21 -16
- package/dist/plugins/Selection/Lasso.svelte +21 -16
- package/dist/plugins/Selection/relations.d.ts +6 -0
- package/dist/plugins/Selection/relations.js +7 -0
- package/dist/plugins/Selection/traits.d.ts +0 -5
- package/dist/plugins/Selection/traits.js +1 -6
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.js +3 -0
- package/dist/snapshot.d.ts +14 -0
- package/dist/snapshot.js +23 -0
- package/package.json +9 -3
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import type { Entity } from 'koota'
|
|
4
4
|
import type { Snippet } from 'svelte'
|
|
5
5
|
|
|
6
|
-
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
|
7
6
|
import { Canvas } from '@threlte/core'
|
|
8
7
|
import { PortalTarget } from '@threlte/extras'
|
|
9
8
|
import { useXR } from '@threlte/xr'
|
|
@@ -11,6 +10,8 @@
|
|
|
11
10
|
import { primeTheme } from '@viamrobotics/tweakpane-config'
|
|
12
11
|
import { ThemeUtils } from 'svelte-tweakpane-ui'
|
|
13
12
|
|
|
13
|
+
import type { FragmentInfo } from '../hooks/usePartConfig.svelte'
|
|
14
|
+
|
|
14
15
|
import Controls from './overlay/controls/Controls.svelte'
|
|
15
16
|
import Dashboard from './overlay/dashboard/Dashboard.svelte'
|
|
16
17
|
import Details from './overlay/Details.svelte'
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
interface LocalConfigProps {
|
|
41
42
|
current: Struct
|
|
42
43
|
isDirty: boolean
|
|
43
|
-
|
|
44
|
+
componentNameToFragmentInfo: Record<string, FragmentInfo>
|
|
44
45
|
setLocalPartConfig: (config: Struct) => void
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -111,18 +112,11 @@
|
|
|
111
112
|
})
|
|
112
113
|
</script>
|
|
113
114
|
|
|
114
|
-
{#if settings.current.enableQueryDevtools}
|
|
115
|
-
<SvelteQueryDevtools initialIsOpen />
|
|
116
|
-
{/if}
|
|
117
|
-
|
|
118
115
|
<div
|
|
119
116
|
class="relative h-full w-full overflow-hidden dark:bg-white"
|
|
120
117
|
bind:this={root}
|
|
121
118
|
>
|
|
122
|
-
<Canvas
|
|
123
|
-
renderMode="on-demand"
|
|
124
|
-
dpr={[1, 2]}
|
|
125
|
-
>
|
|
119
|
+
<Canvas renderMode="on-demand">
|
|
126
120
|
<SceneProviders>
|
|
127
121
|
{#snippet children({ focus })}
|
|
128
122
|
<Scene>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Struct } from '@viamrobotics/sdk';
|
|
2
2
|
import type { Entity } from 'koota';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { FragmentInfo } from '../hooks/usePartConfig.svelte';
|
|
4
5
|
import { type CameraPose } from '../hooks/useControls.svelte';
|
|
5
6
|
interface LocalConfigProps {
|
|
6
7
|
current: Struct;
|
|
7
8
|
isDirty: boolean;
|
|
8
|
-
|
|
9
|
+
componentNameToFragmentInfo: Record<string, FragmentInfo>;
|
|
9
10
|
setLocalPartConfig: (config: Struct) => void;
|
|
10
11
|
}
|
|
11
12
|
interface Props {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { useTransformControls } from '../hooks/useControls.svelte'
|
|
9
9
|
import { useEnvironment } from '../hooks/useEnvironment.svelte'
|
|
10
10
|
import { useFrameEditSession } from '../hooks/useFrameEditSession.svelte'
|
|
11
|
+
import { usePartConfig } from '../hooks/usePartConfig.svelte'
|
|
11
12
|
import { useSelectedEntity, useSelectedObject3d } from '../hooks/useSelection.svelte'
|
|
12
13
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
13
14
|
import {
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
|
|
22
23
|
const settings = useSettings()
|
|
23
24
|
const environment = useEnvironment()
|
|
25
|
+
const partConfig = usePartConfig()
|
|
24
26
|
const transformControls = useTransformControls()
|
|
25
27
|
const selectedEntity = useSelectedEntity()
|
|
26
28
|
const selectedObject3d = useSelectedObject3d()
|
|
@@ -29,14 +31,21 @@
|
|
|
29
31
|
const mode = $derived(settings.current.transformMode)
|
|
30
32
|
const entity = $derived(selectedEntity.current)
|
|
31
33
|
const transformable = useTrait(() => entity, traits.Transformable)
|
|
34
|
+
const invisible = useTrait(() => entity, traits.InheritedInvisible)
|
|
32
35
|
const configMatrix = useTrait(() => entity, traits.Matrix)
|
|
33
36
|
const liveMatrix = useTrait(() => entity, traits.LiveMatrix)
|
|
34
37
|
const box = useTrait(() => entity, traits.Box)
|
|
35
38
|
const sphere = useTrait(() => entity, traits.Sphere)
|
|
36
39
|
const capsule = useTrait(() => entity, traits.Capsule)
|
|
40
|
+
const name = useTrait(() => entity, traits.Name)
|
|
37
41
|
const hasScalableGeometry = $derived(
|
|
38
42
|
box.current !== undefined || sphere.current !== undefined || capsule.current !== undefined
|
|
39
43
|
)
|
|
44
|
+
const isFragmentComponentWithVariables = $derived(
|
|
45
|
+
name.current &&
|
|
46
|
+
Object.keys(partConfig.componentNameToFragmentInfo?.[name.current]?.variables ?? {}).length >
|
|
47
|
+
0
|
|
48
|
+
)
|
|
40
49
|
|
|
41
50
|
// Mesh sets name={entity} on its inner mesh, so useSelectedObject3d resolves
|
|
42
51
|
// to that mesh — not the parent Frame Group we actually want to drive. Walk
|
|
@@ -241,7 +250,7 @@
|
|
|
241
250
|
}
|
|
242
251
|
</script>
|
|
243
252
|
|
|
244
|
-
{#if ref && entity && activeMode}
|
|
253
|
+
{#if ref && entity && activeMode && !isFragmentComponentWithVariables && !invisible.current}
|
|
245
254
|
{#key entity}
|
|
246
255
|
<TransformControls
|
|
247
256
|
object={ref}
|
|
@@ -109,7 +109,14 @@
|
|
|
109
109
|
|
|
110
110
|
const isFrameNode = $derived(!!framesAPI.current)
|
|
111
111
|
const isGeometry = $derived(!!geometriesAPI.current)
|
|
112
|
-
const
|
|
112
|
+
const isFragmentComponentWithVariables = $derived(
|
|
113
|
+
name.current &&
|
|
114
|
+
Object.keys(partConfig.componentNameToFragmentInfo?.[name.current]?.variables ?? {}).length >
|
|
115
|
+
0
|
|
116
|
+
)
|
|
117
|
+
const showEditFrameOptions = $derived(
|
|
118
|
+
isFrameNode && partConfig.hasEditPermissions && !isFragmentComponentWithVariables
|
|
119
|
+
)
|
|
113
120
|
const showRelationshipOptions = $derived(points.current || arrows.current)
|
|
114
121
|
const resourceName = $derived(name.current ? resourceByName.current[name.current] : undefined)
|
|
115
122
|
const displayType = $derived(isFrameNode ? resourceName?.subtype : isGeometry ? 'geometry' : '')
|
|
@@ -406,6 +413,16 @@
|
|
|
406
413
|
|
|
407
414
|
<div class="border-medium -mx-2 w-[100%+0.5rem] border-b"></div>
|
|
408
415
|
|
|
416
|
+
{#if isFragmentComponentWithVariables}
|
|
417
|
+
<p
|
|
418
|
+
class="mt-2 rounded border-l-4 border-yellow-600 bg-yellow-50 px-2 py-1.5 text-yellow-900"
|
|
419
|
+
data-testid="fragment-variables-warning"
|
|
420
|
+
role="status"
|
|
421
|
+
>
|
|
422
|
+
This component is from a fragment with variables, editing frames in 3D scene is disabled
|
|
423
|
+
</p>
|
|
424
|
+
{/if}
|
|
425
|
+
|
|
409
426
|
<h3
|
|
410
427
|
class="text-subtle-2 flex justify-between py-2"
|
|
411
428
|
data-testid="details-header"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
class={[
|
|
35
35
|
className,
|
|
36
36
|
'relative block rounded-md border',
|
|
37
|
-
active ? '
|
|
37
|
+
active ? 'z-4 border-[#666] bg-[#666] text-white' : 'border-gray-5 text-gray-8 bg-white',
|
|
38
38
|
]}
|
|
39
39
|
aria-describedby={tooltipID}
|
|
40
40
|
>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
<Portal id="dashboard">
|
|
63
63
|
<fieldset>
|
|
64
64
|
<DashboardButton
|
|
65
|
-
active
|
|
65
|
+
active={isOpen.current}
|
|
66
66
|
icon="cog"
|
|
67
67
|
description="Settings"
|
|
68
68
|
onclick={() => {
|
|
@@ -278,10 +278,6 @@
|
|
|
278
278
|
|
|
279
279
|
{#snippet Stats()}
|
|
280
280
|
<div class="flex w-full flex-col gap-2.5 text-xs">
|
|
281
|
-
<label class="flex items-center justify-between gap-2">
|
|
282
|
-
Query devtools <Switch bind:on={settings.current.enableQueryDevtools} />
|
|
283
|
-
</label>
|
|
284
|
-
|
|
285
281
|
<label class="flex items-center justify-between gap-2">
|
|
286
282
|
Render stats <Switch bind:on={settings.current.renderStats} />
|
|
287
283
|
</label>
|
|
@@ -25,12 +25,12 @@ export const provideConfigFrames = () => {
|
|
|
25
25
|
});
|
|
26
26
|
const [fragmentFrames, fragmentUnsetFrameNames] = $derived.by(() => {
|
|
27
27
|
const { fragment_mods: fragmentMods = [] } = partConfig.current;
|
|
28
|
-
const fragmentDefinedComponents = Object.keys(partConfig.
|
|
28
|
+
const fragmentDefinedComponents = Object.keys(partConfig.componentNameToFragmentInfo ?? {});
|
|
29
29
|
const results = {};
|
|
30
30
|
const unsetResults = [];
|
|
31
31
|
// deal with fragment defined components
|
|
32
32
|
for (const fragmentComponentName of fragmentDefinedComponents || []) {
|
|
33
|
-
const fragmentId = partConfig.
|
|
33
|
+
const fragmentId = partConfig.componentNameToFragmentInfo[fragmentComponentName].id;
|
|
34
34
|
const fragmentMod = fragmentMods?.find((mod) => mod.fragment_id === fragmentId);
|
|
35
35
|
if (!fragmentMod) {
|
|
36
36
|
continue;
|
|
@@ -64,7 +64,7 @@ export const provideConfigFrames = () => {
|
|
|
64
64
|
* any whose frame the user has $unset.
|
|
65
65
|
*/
|
|
66
66
|
const unsetFragmentNames = new Set(fragmentUnsetFrameNames);
|
|
67
|
-
for (const name of Object.keys(partConfig.
|
|
67
|
+
for (const name of Object.keys(partConfig.componentNameToFragmentInfo)) {
|
|
68
68
|
if (!unsetFragmentNames.has(name)) {
|
|
69
69
|
validFrames.add(name);
|
|
70
70
|
}
|
|
@@ -11,7 +11,7 @@ export const provideFramelessComponents = () => {
|
|
|
11
11
|
?.filter((component) => component.frame === undefined)
|
|
12
12
|
.map((component) => component.name) ?? [];
|
|
13
13
|
const fragmentComponentsWithNoFrame = new Set(partComponentsWIthNoFrame);
|
|
14
|
-
for (const fragmentComponentName of Object.keys(partConfig.
|
|
14
|
+
for (const fragmentComponentName of Object.keys(partConfig.componentNameToFragmentInfo)) {
|
|
15
15
|
if (frames.current.some((frame) => frame.referenceFrame === fragmentComponentName)) {
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
@@ -11,12 +11,16 @@ export interface PartConfig {
|
|
|
11
11
|
mods: any[];
|
|
12
12
|
}[];
|
|
13
13
|
}
|
|
14
|
+
export type FragmentInfo = {
|
|
15
|
+
id: string;
|
|
16
|
+
variables: Record<string, string>;
|
|
17
|
+
};
|
|
14
18
|
interface PartConfigContext {
|
|
15
19
|
current: PartConfig;
|
|
16
20
|
isDirty: boolean;
|
|
17
21
|
hasPendingSave: boolean;
|
|
18
22
|
hasEditPermissions: boolean;
|
|
19
|
-
|
|
23
|
+
componentNameToFragmentInfo: Record<string, FragmentInfo>;
|
|
20
24
|
updateFrame: (componentName: string, referenceFrame: string, pose: Pose, geometry?: Frame['geometry']) => void;
|
|
21
25
|
deleteFrame: (componentName: string) => void;
|
|
22
26
|
createFrame: (componentName: string) => void;
|
|
@@ -30,7 +34,7 @@ export declare const usePartConfig: () => PartConfigContext;
|
|
|
30
34
|
interface AppEmbeddedPartConfigProps {
|
|
31
35
|
current: Struct;
|
|
32
36
|
isDirty: boolean;
|
|
33
|
-
|
|
37
|
+
componentNameToFragmentInfo: Record<string, FragmentInfo>;
|
|
34
38
|
setLocalPartConfig: (config: Struct) => void;
|
|
35
39
|
}
|
|
36
40
|
export {};
|
|
@@ -155,8 +155,8 @@ export const providePartConfig = (partID, params) => {
|
|
|
155
155
|
get current() {
|
|
156
156
|
return current;
|
|
157
157
|
},
|
|
158
|
-
get
|
|
159
|
-
return config.
|
|
158
|
+
get componentNameToFragmentInfo() {
|
|
159
|
+
return config.componentNameToFragmentInfo;
|
|
160
160
|
},
|
|
161
161
|
get isDirty() {
|
|
162
162
|
return config.isDirty;
|
|
@@ -168,7 +168,7 @@ export const providePartConfig = (partID, params) => {
|
|
|
168
168
|
return config.hasEditPermissions;
|
|
169
169
|
},
|
|
170
170
|
updateFrame: (componentName, referenceFrame, framePosition, frameGeometry) => {
|
|
171
|
-
const fragmentId = config.
|
|
171
|
+
const fragmentId = config.componentNameToFragmentInfo[componentName]?.id;
|
|
172
172
|
if (fragmentId === undefined) {
|
|
173
173
|
updatePartFrame(componentName, referenceFrame, framePosition, frameGeometry);
|
|
174
174
|
}
|
|
@@ -177,7 +177,7 @@ export const providePartConfig = (partID, params) => {
|
|
|
177
177
|
}
|
|
178
178
|
},
|
|
179
179
|
deleteFrame: (componentName) => {
|
|
180
|
-
const fragmentId = config.
|
|
180
|
+
const fragmentId = config.componentNameToFragmentInfo[componentName]?.id;
|
|
181
181
|
if (fragmentId === undefined) {
|
|
182
182
|
deletePartFrame(componentName);
|
|
183
183
|
}
|
|
@@ -186,7 +186,7 @@ export const providePartConfig = (partID, params) => {
|
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
188
|
createFrame: (componentName) => {
|
|
189
|
-
const fragmentId = config.
|
|
189
|
+
const fragmentId = config.componentNameToFragmentInfo[componentName]?.id;
|
|
190
190
|
if (fragmentId === undefined) {
|
|
191
191
|
createPartFrame(componentName);
|
|
192
192
|
}
|
|
@@ -244,8 +244,8 @@ const useEmbeddedPartConfig = (props) => {
|
|
|
244
244
|
get current() {
|
|
245
245
|
return props.current ?? new Struct();
|
|
246
246
|
},
|
|
247
|
-
get
|
|
248
|
-
return props.
|
|
247
|
+
get componentNameToFragmentInfo() {
|
|
248
|
+
return props.componentNameToFragmentInfo;
|
|
249
249
|
},
|
|
250
250
|
set(config) {
|
|
251
251
|
const struct = Struct.fromJson(config);
|
|
@@ -287,7 +287,16 @@ const useStandalonePartConfig = (partID) => {
|
|
|
287
287
|
const id = typeof fragmentId === 'string' ? fragmentId : fragmentId.id;
|
|
288
288
|
return createAppQuery('getFragment', () => [id], { refetchInterval: false });
|
|
289
289
|
}));
|
|
290
|
-
const
|
|
290
|
+
const fragmentIdToVariables = $derived.by(() => {
|
|
291
|
+
const results = {};
|
|
292
|
+
for (const fragment of configJSON?.fragments ?? []) {
|
|
293
|
+
const id = typeof fragment === 'string' ? fragment : fragment.id;
|
|
294
|
+
const variables = typeof fragment === 'string' ? {} : fragment.variables;
|
|
295
|
+
results[id] = variables;
|
|
296
|
+
}
|
|
297
|
+
return results;
|
|
298
|
+
});
|
|
299
|
+
const componentNameToFragmentInfo = $derived.by(() => {
|
|
291
300
|
const results = {};
|
|
292
301
|
for (const query of fragmentQueries) {
|
|
293
302
|
if (!query.data) {
|
|
@@ -300,7 +309,10 @@ const useStandalonePartConfig = (partID) => {
|
|
|
300
309
|
if (component.kind.case === 'structValue') {
|
|
301
310
|
const componentName = component.kind.value.fields['name']?.kind;
|
|
302
311
|
if (componentName.case === 'stringValue') {
|
|
303
|
-
results[componentName.value] =
|
|
312
|
+
results[componentName.value] = {
|
|
313
|
+
id: fragmentId,
|
|
314
|
+
variables: fragmentIdToVariables[fragmentId] ?? {},
|
|
315
|
+
};
|
|
304
316
|
}
|
|
305
317
|
}
|
|
306
318
|
}
|
|
@@ -340,8 +352,8 @@ const useStandalonePartConfig = (partID) => {
|
|
|
340
352
|
get hasEditPermissions() {
|
|
341
353
|
return hasEditPermissions;
|
|
342
354
|
},
|
|
343
|
-
get
|
|
344
|
-
return
|
|
355
|
+
get componentNameToFragmentInfo() {
|
|
356
|
+
return componentNameToFragmentInfo;
|
|
345
357
|
},
|
|
346
358
|
set(config) {
|
|
347
359
|
current = Struct.fromJson(config);
|
|
@@ -23,7 +23,6 @@ export interface Settings {
|
|
|
23
23
|
enableMeasureAxisY: boolean;
|
|
24
24
|
enableMeasureAxisZ: boolean;
|
|
25
25
|
enableLabels: boolean;
|
|
26
|
-
enableQueryDevtools: boolean;
|
|
27
26
|
enableArmPositionsWidget: boolean;
|
|
28
27
|
openCameraWidgets: Record<string, string[]>;
|
|
29
28
|
openFramePovWidgets: Record<string, string[]>;
|
package/dist/lib.d.ts
CHANGED
package/dist/lib.js
CHANGED
|
@@ -13,3 +13,4 @@ export { OrientationVector } from './three/OrientationVector';
|
|
|
13
13
|
export { parsePcdInWorker } from './loaders/pcd';
|
|
14
14
|
export { createBinaryPCD } from './pcd';
|
|
15
15
|
export { metadataFromStruct } from './metadata';
|
|
16
|
+
export { decodeDrawnSnapshotPointClouds } from './snapshot';
|