@viamrobotics/motion-tools 0.14.2 → 0.14.5
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/{Detail.svelte.d.ts → FrameConfigUpdater.svelte.d.ts} +4 -17
- package/dist/{Detail.svelte.js → FrameConfigUpdater.svelte.js} +10 -49
- package/dist/components/App.svelte +38 -40
- package/dist/components/AxesHelper.svelte +0 -1
- package/dist/components/Details.svelte +49 -5
- package/dist/components/Geometry.svelte +35 -8
- package/dist/components/LiveUpdatesBanner.svelte +1 -1
- package/dist/components/Tree/AddFrames.svelte +1 -1
- package/dist/components/Tree/Drawer.svelte +4 -2
- package/dist/components/Tree/Drawer.svelte.d.ts +1 -0
- package/dist/components/Tree/Logs.svelte +53 -4
- package/dist/components/Tree/TreeContainer.svelte +5 -2
- package/dist/components/WorldObjects.svelte +15 -0
- package/dist/components/weblab/WeblabActive.svelte +3 -3
- package/dist/frame.d.ts +76 -0
- package/dist/frame.js +12 -0
- package/dist/geometry.d.ts +2 -0
- package/dist/geometry.js +8 -0
- package/dist/hooks/useDrawAPI.svelte.d.ts +1 -0
- package/dist/hooks/useDrawAPI.svelte.js +56 -0
- package/dist/hooks/useFrames.svelte.js +3 -11
- package/dist/hooks/useGeometries.svelte.d.ts +1 -0
- package/dist/hooks/useGeometries.svelte.js +12 -2
- package/dist/hooks/useLogs.svelte.d.ts +3 -0
- package/dist/hooks/useLogs.svelte.js +40 -9
- package/dist/hooks/useObjects.svelte.js +1 -0
- package/dist/hooks/usePartConfig.svelte.d.ts +2 -32
- package/dist/hooks/usePartConfig.svelte.js +63 -69
- package/dist/hooks/usePointclouds.svelte.d.ts +1 -0
- package/dist/hooks/usePointclouds.svelte.js +5 -0
- package/dist/hooks/useStaticGeometries.svelte.js +1 -1
- package/dist/hooks/useWeblabs.svelte.d.ts +4 -7
- package/dist/hooks/useWeblabs.svelte.js +43 -18
- package/dist/three/OrientationVector.d.ts +1 -1
- package/dist/transform.d.ts +2 -4
- package/dist/transform.js +28 -41
- package/package.json +2 -2
- package/dist/components/weblab/WeblabProvider.svelte +0 -8
- package/dist/components/weblab/WeblabProvider.svelte.d.ts +0 -5
|
@@ -1,20 +1,14 @@
|
|
|
1
|
+
import type { Frame } from './frame';
|
|
1
2
|
import type { WorldObject } from './lib';
|
|
2
3
|
import type { Geometries } from './WorldObject.svelte';
|
|
3
4
|
import type { Pose } from '@viamrobotics/sdk';
|
|
4
5
|
type UpdateFrameCallback = {
|
|
5
|
-
(componentName: string, referenceFrame: string, pose: Pose, geometry?:
|
|
6
|
-
type: 'none' | 'box' | 'sphere' | 'capsule';
|
|
7
|
-
r?: number;
|
|
8
|
-
l?: number;
|
|
9
|
-
x?: number;
|
|
10
|
-
y?: number;
|
|
11
|
-
z?: number;
|
|
12
|
-
}): void;
|
|
6
|
+
(componentName: string, referenceFrame: string, pose: Pose, geometry?: Frame['geometry']): void;
|
|
13
7
|
};
|
|
14
8
|
type RemoveFrameCallback = {
|
|
15
9
|
(componentName: string): void;
|
|
16
10
|
};
|
|
17
|
-
export declare class
|
|
11
|
+
export declare class FrameConfigUpdater {
|
|
18
12
|
private object;
|
|
19
13
|
private referenceFrame;
|
|
20
14
|
private updateFrame;
|
|
@@ -31,14 +25,7 @@ export declare class DetailConfigUpdater {
|
|
|
31
25
|
oZ?: number;
|
|
32
26
|
theta?: number;
|
|
33
27
|
}) => void;
|
|
34
|
-
updateGeometry: (geometry:
|
|
35
|
-
type: "none" | "box" | "sphere" | "capsule";
|
|
36
|
-
r?: number;
|
|
37
|
-
l?: number;
|
|
38
|
-
x?: number;
|
|
39
|
-
y?: number;
|
|
40
|
-
z?: number;
|
|
41
|
-
}) => void;
|
|
28
|
+
updateGeometry: (geometry: Partial<Frame["geometry"]>) => void;
|
|
42
29
|
setFrameParent: (parentName: string) => void;
|
|
43
30
|
deleteFrame: () => void;
|
|
44
31
|
setGeometryType: (type: "none" | "box" | "sphere" | "capsule") => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { createPose } from './transform';
|
|
2
|
+
export class FrameConfigUpdater {
|
|
2
3
|
object;
|
|
3
4
|
referenceFrame;
|
|
4
5
|
updateFrame;
|
|
@@ -49,7 +50,7 @@ export class DetailConfigUpdater {
|
|
|
49
50
|
if (!object)
|
|
50
51
|
return;
|
|
51
52
|
let geometryObject;
|
|
52
|
-
if (geometry
|
|
53
|
+
if (geometry?.type === 'box') {
|
|
53
54
|
const currentGeometry = object.geometry?.geometryType.value;
|
|
54
55
|
geometryObject = {
|
|
55
56
|
type: 'box',
|
|
@@ -58,14 +59,14 @@ export class DetailConfigUpdater {
|
|
|
58
59
|
z: geometry.z ?? currentGeometry?.dimsMm?.z,
|
|
59
60
|
};
|
|
60
61
|
}
|
|
61
|
-
else if (geometry
|
|
62
|
+
else if (geometry?.type === 'sphere') {
|
|
62
63
|
const currentGeometry = object.geometry?.geometryType.value;
|
|
63
64
|
geometryObject = {
|
|
64
65
|
type: 'sphere',
|
|
65
66
|
r: geometry.r ?? currentGeometry?.radiusMm,
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
|
-
else if (geometry
|
|
69
|
+
else if (geometry?.type === 'capsule') {
|
|
69
70
|
const currentGeometry = object.geometry?.geometryType.value;
|
|
70
71
|
geometryObject = {
|
|
71
72
|
type: 'capsule',
|
|
@@ -73,29 +74,13 @@ export class DetailConfigUpdater {
|
|
|
73
74
|
l: geometry.l ?? currentGeometry?.lengthMm,
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
|
-
this.updateFrame(object.name ?? '', this.referenceFrame(),
|
|
77
|
-
x: object.localEditedPose.x,
|
|
78
|
-
y: object.localEditedPose.y,
|
|
79
|
-
z: object.localEditedPose.z,
|
|
80
|
-
oX: object.localEditedPose.oX,
|
|
81
|
-
oY: object.localEditedPose.oY,
|
|
82
|
-
oZ: object.localEditedPose.oZ,
|
|
83
|
-
theta: object.localEditedPose.theta,
|
|
84
|
-
}, { ...geometryObject });
|
|
77
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), createPose(object.localEditedPose), geometryObject);
|
|
85
78
|
};
|
|
86
79
|
setFrameParent = (parentName) => {
|
|
87
80
|
const object = this.object();
|
|
88
81
|
if (!object)
|
|
89
82
|
return;
|
|
90
|
-
this.updateFrame(object.name ?? '', parentName,
|
|
91
|
-
x: object.localEditedPose.x,
|
|
92
|
-
y: object.localEditedPose.y,
|
|
93
|
-
z: object.localEditedPose.z,
|
|
94
|
-
oX: object.localEditedPose.oX,
|
|
95
|
-
oY: object.localEditedPose.oY,
|
|
96
|
-
oZ: object.localEditedPose.oZ,
|
|
97
|
-
theta: object.localEditedPose.theta,
|
|
98
|
-
});
|
|
83
|
+
this.updateFrame(object.name ?? '', parentName, createPose(object.localEditedPose));
|
|
99
84
|
};
|
|
100
85
|
deleteFrame = () => {
|
|
101
86
|
const object = this.object();
|
|
@@ -108,37 +93,13 @@ export class DetailConfigUpdater {
|
|
|
108
93
|
if (!object)
|
|
109
94
|
return;
|
|
110
95
|
if (type === 'none') {
|
|
111
|
-
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
112
|
-
x: object.localEditedPose.x,
|
|
113
|
-
y: object.localEditedPose.y,
|
|
114
|
-
z: object.localEditedPose.z,
|
|
115
|
-
oX: object.localEditedPose.oX,
|
|
116
|
-
oY: object.localEditedPose.oY,
|
|
117
|
-
oZ: object.localEditedPose.oZ,
|
|
118
|
-
theta: object.localEditedPose.theta,
|
|
119
|
-
}, { type: 'none' });
|
|
96
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), createPose(object.localEditedPose), { type: 'none' });
|
|
120
97
|
}
|
|
121
98
|
else if (type === 'box') {
|
|
122
|
-
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
123
|
-
x: object.localEditedPose.x,
|
|
124
|
-
y: object.localEditedPose.y,
|
|
125
|
-
z: object.localEditedPose.z,
|
|
126
|
-
oX: object.localEditedPose.oX,
|
|
127
|
-
oY: object.localEditedPose.oY,
|
|
128
|
-
oZ: object.localEditedPose.oZ,
|
|
129
|
-
theta: object.localEditedPose.theta,
|
|
130
|
-
}, { type: 'box', x: 100, y: 100, z: 100 });
|
|
99
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), createPose(object.localEditedPose), { type: 'box', x: 100, y: 100, z: 100 });
|
|
131
100
|
}
|
|
132
101
|
else if (type === 'sphere') {
|
|
133
|
-
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
134
|
-
x: object.localEditedPose.x,
|
|
135
|
-
y: object.localEditedPose.y,
|
|
136
|
-
z: object.localEditedPose.z,
|
|
137
|
-
oX: object.localEditedPose.oX,
|
|
138
|
-
oY: object.localEditedPose.oY,
|
|
139
|
-
oZ: object.localEditedPose.oZ,
|
|
140
|
-
theta: object.localEditedPose.theta,
|
|
141
|
-
}, { type: 'sphere', r: 100 });
|
|
102
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), createPose(object.localEditedPose), { type: 'sphere', r: 100 });
|
|
142
103
|
}
|
|
143
104
|
else if (type === 'capsule') {
|
|
144
105
|
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
|
5
5
|
import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
|
|
6
6
|
import type { Struct } from '@viamrobotics/sdk'
|
|
7
|
-
|
|
8
7
|
import Scene from './Scene.svelte'
|
|
9
8
|
import TreeContainer from './Tree/TreeContainer.svelte'
|
|
10
9
|
import Details from './Details.svelte'
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
import { domPortal } from '../portal'
|
|
17
16
|
import { provideSettings } from '../hooks/useSettings.svelte'
|
|
18
17
|
import FileDrop from './FileDrop.svelte'
|
|
19
|
-
import
|
|
18
|
+
import { provideWeblabs } from '../hooks/useWeblabs.svelte'
|
|
20
19
|
import { providePartConfig } from '../hooks/usePartConfig.svelte'
|
|
21
20
|
import { useViamClient } from '@viamrobotics/svelte-sdk'
|
|
22
21
|
import LiveUpdatesBanner from './LiveUpdatesBanner.svelte'
|
|
@@ -54,6 +53,7 @@
|
|
|
54
53
|
|
|
55
54
|
createPartIDContext(() => partID)
|
|
56
55
|
|
|
56
|
+
provideWeblabs()
|
|
57
57
|
provideToast()
|
|
58
58
|
|
|
59
59
|
let root = $state.raw<HTMLElement>()
|
|
@@ -83,41 +83,39 @@
|
|
|
83
83
|
<SvelteQueryDevtools initialIsOpen />
|
|
84
84
|
{/if}
|
|
85
85
|
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
>
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
</div>
|
|
123
|
-
</WeblabProvider>
|
|
86
|
+
<div
|
|
87
|
+
class="relative h-full w-full overflow-hidden"
|
|
88
|
+
bind:this={root}
|
|
89
|
+
>
|
|
90
|
+
<Canvas renderMode="always">
|
|
91
|
+
<World>
|
|
92
|
+
<SceneProviders>
|
|
93
|
+
{#snippet children({ focus })}
|
|
94
|
+
<Scene>
|
|
95
|
+
{@render appChildren?.()}
|
|
96
|
+
</Scene>
|
|
97
|
+
|
|
98
|
+
<XR {@attach domPortal(root)} />
|
|
99
|
+
|
|
100
|
+
<Dashboard {@attach domPortal(root)} />
|
|
101
|
+
<Details {@attach domPortal(root)} />
|
|
102
|
+
{#if environment.current.isStandalone}
|
|
103
|
+
<LiveUpdatesBanner {@attach domPortal(root)} />
|
|
104
|
+
{/if}
|
|
105
|
+
|
|
106
|
+
{#if !focus}
|
|
107
|
+
<TreeContainer {@attach domPortal(root)} />
|
|
108
|
+
{/if}
|
|
109
|
+
|
|
110
|
+
{#if !focus && settings.current.enableArmPositionsWidget}
|
|
111
|
+
<ArmPositions {@attach domPortal(root)} />
|
|
112
|
+
{/if}
|
|
113
|
+
|
|
114
|
+
<FileDrop {@attach domPortal(root)} />
|
|
115
|
+
{/snippet}
|
|
116
|
+
</SceneProviders>
|
|
117
|
+
</World>
|
|
118
|
+
</Canvas>
|
|
119
|
+
|
|
120
|
+
<ToastContainer />
|
|
121
|
+
</div>
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
import WeblabActive from './weblab/WeblabActive.svelte'
|
|
26
26
|
import { useFrames } from '../hooks/useFrames.svelte'
|
|
27
27
|
import { usePartConfig } from '../hooks/usePartConfig.svelte'
|
|
28
|
-
import {
|
|
28
|
+
import { FrameConfigUpdater } from '../FrameConfigUpdater.svelte'
|
|
29
|
+
import { useWeblabs } from '../hooks/useWeblabs.svelte'
|
|
29
30
|
|
|
30
31
|
const { ...rest } = $props()
|
|
31
32
|
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
const partConfig = usePartConfig()
|
|
37
38
|
const selectedObject = useSelectedObject()
|
|
38
39
|
const selectedObject3d = useSelectedObject3d()
|
|
40
|
+
const weblab = useWeblabs()
|
|
39
41
|
|
|
40
42
|
const object = $derived(focusedObject.current ?? selectedObject.current)
|
|
41
43
|
const object3d = $derived(focusedObject3d.current ?? selectedObject3d.current)
|
|
@@ -57,7 +59,7 @@
|
|
|
57
59
|
|
|
58
60
|
const draggable = useDraggable('details')
|
|
59
61
|
|
|
60
|
-
const detailConfigUpdater
|
|
62
|
+
const detailConfigUpdater = new FrameConfigUpdater(
|
|
61
63
|
() => object,
|
|
62
64
|
partConfig.updateFrame,
|
|
63
65
|
partConfig.deleteFrame,
|
|
@@ -99,6 +101,48 @@
|
|
|
99
101
|
stop()
|
|
100
102
|
}
|
|
101
103
|
})
|
|
104
|
+
|
|
105
|
+
const getCopyClipboardText = () => {
|
|
106
|
+
if (weblab.isActive('MOTION_TOOLS_EDIT_FRAME')) {
|
|
107
|
+
return JSON.stringify(
|
|
108
|
+
{
|
|
109
|
+
worldPosition: worldPosition,
|
|
110
|
+
worldOrientation: worldOrientation,
|
|
111
|
+
localPosition: {
|
|
112
|
+
x: localPose?.x,
|
|
113
|
+
y: localPose?.y,
|
|
114
|
+
z: localPose?.z,
|
|
115
|
+
},
|
|
116
|
+
localOrientation: {
|
|
117
|
+
x: localPose?.oX,
|
|
118
|
+
y: localPose?.oY,
|
|
119
|
+
z: localPose?.oZ,
|
|
120
|
+
th: localPose?.theta,
|
|
121
|
+
},
|
|
122
|
+
geometry: {
|
|
123
|
+
type: geometryType,
|
|
124
|
+
value: object?.geometry?.geometryType.value,
|
|
125
|
+
},
|
|
126
|
+
parentFrame: referenceFrame,
|
|
127
|
+
},
|
|
128
|
+
null,
|
|
129
|
+
2
|
|
130
|
+
)
|
|
131
|
+
} else {
|
|
132
|
+
return JSON.stringify(
|
|
133
|
+
{
|
|
134
|
+
worldPosition: worldPosition,
|
|
135
|
+
worldOrientation: worldOrientation,
|
|
136
|
+
geometry: {
|
|
137
|
+
type: geometryType,
|
|
138
|
+
value: object?.geometry?.geometryType.value,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
null,
|
|
142
|
+
2
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
102
146
|
</script>
|
|
103
147
|
|
|
104
148
|
{#snippet ImmutableField({
|
|
@@ -199,7 +243,7 @@
|
|
|
199
243
|
|
|
200
244
|
<button
|
|
201
245
|
onclick={async () => {
|
|
202
|
-
navigator.clipboard.writeText(
|
|
246
|
+
navigator.clipboard.writeText(getCopyClipboardText())
|
|
203
247
|
copied = true
|
|
204
248
|
setTimeout(() => (copied = false), 1000)
|
|
205
249
|
}}
|
|
@@ -430,7 +474,7 @@
|
|
|
430
474
|
<div class="flex items-center gap-2">
|
|
431
475
|
{@render GeometryAttribute({
|
|
432
476
|
label: 'r',
|
|
433
|
-
ariaLabel: 'sphere dimensions radius value
|
|
477
|
+
ariaLabel: 'sphere dimensions radius value',
|
|
434
478
|
value: radiusMm ? radiusMm.toFixed(2) : '-',
|
|
435
479
|
onInput: (value) =>
|
|
436
480
|
detailConfigUpdater.updateGeometry({ type: 'sphere', r: parseFloat(value) }),
|
|
@@ -523,7 +567,7 @@
|
|
|
523
567
|
<Button
|
|
524
568
|
variant="danger"
|
|
525
569
|
class="mt-2 w-full"
|
|
526
|
-
onclick={() => detailConfigUpdater.deleteFrame()}>Delete
|
|
570
|
+
onclick={() => detailConfigUpdater.deleteFrame()}>Delete frame</Button
|
|
527
571
|
>
|
|
528
572
|
{/if}
|
|
529
573
|
</WeblabActive>
|
|
@@ -65,18 +65,38 @@
|
|
|
65
65
|
const oncreate = (ref: BufferGeometry) => {
|
|
66
66
|
geo = ref
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
const parsePlyInput = (mesh: string | Uint8Array): BufferGeometry => {
|
|
70
|
+
// Case 1: already a base64 or ASCII string
|
|
71
|
+
if (typeof mesh === 'string') {
|
|
72
|
+
return plyLoader.parse(atob(mesh))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Case 2: detect text vs binary PLY in Uint8Array
|
|
76
|
+
const header = new TextDecoder().decode(mesh.slice(0, 50))
|
|
77
|
+
const isAscii = header.includes('format ascii')
|
|
78
|
+
|
|
79
|
+
// Case 3: text-mode PLY → decode bytes to string
|
|
80
|
+
if (isAscii) {
|
|
81
|
+
const text = new TextDecoder().decode(mesh)
|
|
82
|
+
return plyLoader.parse(text)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Case 4: binary PLY → pass ArrayBuffer directly
|
|
86
|
+
return plyLoader.parse(mesh.buffer as ArrayBuffer)
|
|
87
|
+
}
|
|
68
88
|
</script>
|
|
69
89
|
|
|
70
90
|
<T
|
|
71
91
|
is={group}
|
|
72
92
|
{...rest}
|
|
73
93
|
>
|
|
74
|
-
<AxesHelper
|
|
75
|
-
width={3}
|
|
76
|
-
length={0.1}
|
|
77
|
-
/>
|
|
78
|
-
|
|
79
94
|
{#if geometry?.geometryType}
|
|
95
|
+
<AxesHelper
|
|
96
|
+
width={3}
|
|
97
|
+
length={0.1}
|
|
98
|
+
/>
|
|
99
|
+
|
|
80
100
|
<T
|
|
81
101
|
is={mesh}
|
|
82
102
|
{name}
|
|
@@ -84,8 +104,8 @@
|
|
|
84
104
|
bvh={{ enabled: false }}
|
|
85
105
|
>
|
|
86
106
|
{#if geometry.geometryType.case === 'mesh'}
|
|
87
|
-
{@const mesh = geometry.geometryType.value.mesh
|
|
88
|
-
{@const meshGeometry =
|
|
107
|
+
{@const mesh = geometry.geometryType.value.mesh}
|
|
108
|
+
{@const meshGeometry = parsePlyInput(mesh)}
|
|
89
109
|
<T
|
|
90
110
|
is={meshGeometry}
|
|
91
111
|
{oncreate}
|
|
@@ -111,7 +131,7 @@
|
|
|
111
131
|
args={[radiusMm * 0.001, lengthMm * 0.001]}
|
|
112
132
|
{oncreate}
|
|
113
133
|
/>
|
|
114
|
-
{
|
|
134
|
+
{/if}
|
|
115
135
|
|
|
116
136
|
{#if geometry.geometryType.case === 'line'}
|
|
117
137
|
<MeshLineMaterial
|
|
@@ -137,6 +157,13 @@
|
|
|
137
157
|
{/if}
|
|
138
158
|
{/if}
|
|
139
159
|
</T>
|
|
160
|
+
{:else}
|
|
161
|
+
<AxesHelper
|
|
162
|
+
{name}
|
|
163
|
+
{uuid}
|
|
164
|
+
width={3}
|
|
165
|
+
length={0.1}
|
|
166
|
+
/>
|
|
140
167
|
{/if}
|
|
141
168
|
|
|
142
169
|
{@render children?.({ ref: group })}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<Drawer name="Add frames">
|
|
12
|
-
<div class="flex h-64
|
|
12
|
+
<div class="flex max-h-64 flex-col gap-2 overflow-auto p-3">
|
|
13
13
|
{#if framelessComponents.current.length > 0}
|
|
14
14
|
<ul class="space-y-1">
|
|
15
15
|
{#each framelessComponents.current as component (component)}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
name: string
|
|
8
8
|
defaultOpen?: boolean
|
|
9
9
|
children: Snippet
|
|
10
|
+
titleAlert?: Snippet
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
let { name, children, defaultOpen = false }: Props = $props()
|
|
13
|
+
let { name, children, titleAlert, defaultOpen = false }: Props = $props()
|
|
13
14
|
|
|
14
15
|
const expanded = $derived(new PersistedState(`${name}-expanded`, defaultOpen))
|
|
15
16
|
</script>
|
|
@@ -24,9 +25,10 @@
|
|
|
24
25
|
label="unfold more icon"
|
|
25
26
|
variant="ghost"
|
|
26
27
|
cx="size-6"
|
|
27
|
-
|
|
28
|
+
onclick={() => (expanded.current = !expanded.current)}
|
|
28
29
|
/>
|
|
29
30
|
{name}
|
|
31
|
+
{@render titleAlert?.()}
|
|
30
32
|
</h3>
|
|
31
33
|
</button>
|
|
32
34
|
|
|
@@ -1,14 +1,56 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { useFrames } from '../../hooks/useFrames.svelte'
|
|
3
|
+
import { useGeometries } from '../../hooks/useGeometries.svelte'
|
|
2
4
|
import { useLogs } from '../../hooks/useLogs.svelte'
|
|
5
|
+
import { usePointClouds } from '../../hooks/usePointclouds.svelte'
|
|
3
6
|
import Drawer from './Drawer.svelte'
|
|
4
7
|
|
|
8
|
+
const frames = useFrames()
|
|
9
|
+
const geometries = useGeometries()
|
|
10
|
+
const pointclouds = usePointClouds()
|
|
5
11
|
const logs = useLogs()
|
|
6
|
-
|
|
12
|
+
|
|
13
|
+
$effect(() => {
|
|
14
|
+
if (frames.error) {
|
|
15
|
+
const message = `Frames: ${frames.error.message}`
|
|
16
|
+
logs.add(message, 'error')
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
if (geometries.errors.length > 0) {
|
|
22
|
+
for (const error of geometries.errors) {
|
|
23
|
+
logs.add(`Geometries: ${error.message}`, 'error')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
if (pointclouds.errors.length > 0) {
|
|
30
|
+
for (const error of pointclouds.errors) {
|
|
31
|
+
logs.add(`Pointclouds: ${error.message}`, 'error')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
7
35
|
</script>
|
|
8
36
|
|
|
9
37
|
<Drawer name="Logs">
|
|
10
|
-
|
|
11
|
-
{#
|
|
38
|
+
{#snippet titleAlert()}
|
|
39
|
+
{#if logs.warnings.length > 0}
|
|
40
|
+
<span class="mr-1 rounded bg-yellow-700 px-1 py-0.5 text-xs text-white">
|
|
41
|
+
{logs.warnings.length}
|
|
42
|
+
</span>
|
|
43
|
+
{/if}
|
|
44
|
+
|
|
45
|
+
{#if logs.errors.length > 0}
|
|
46
|
+
<span class="mr-1 rounded bg-red-700 px-1 py-0.5 text-xs text-white">
|
|
47
|
+
{logs.errors.length}
|
|
48
|
+
</span>
|
|
49
|
+
{/if}
|
|
50
|
+
{/snippet}
|
|
51
|
+
|
|
52
|
+
<div class="flex h-64 flex-col gap-2 overflow-auto p-3">
|
|
53
|
+
{#each logs.current as log (log.uuid)}
|
|
12
54
|
<div>
|
|
13
55
|
<div class="flex flex-wrap items-center gap-1.5">
|
|
14
56
|
<div
|
|
@@ -23,7 +65,14 @@
|
|
|
23
65
|
></div>
|
|
24
66
|
<div class="text-subtle-2">{log.timestamp}</div>
|
|
25
67
|
</div>
|
|
26
|
-
<div>
|
|
68
|
+
<div>
|
|
69
|
+
{#if log.count > 1}
|
|
70
|
+
<span class="mr-1 rounded bg-green-700 px-1 py-0.5 text-xs text-white">
|
|
71
|
+
{log.count}
|
|
72
|
+
</span>
|
|
73
|
+
{/if}
|
|
74
|
+
{log.message}
|
|
75
|
+
</div>
|
|
27
76
|
</div>
|
|
28
77
|
{:else}
|
|
29
78
|
No logs
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
import Widgets from './Widgets.svelte'
|
|
14
14
|
import AddFrames from './AddFrames.svelte'
|
|
15
15
|
import { useEnvironment } from '../../hooks/useEnvironment.svelte'
|
|
16
|
+
import { usePartID } from '../../hooks/usePartID.svelte'
|
|
16
17
|
const { ...rest } = $props()
|
|
17
18
|
|
|
18
19
|
provideTreeExpandedContext()
|
|
19
20
|
|
|
21
|
+
const partID = usePartID()
|
|
20
22
|
const selected = useSelected()
|
|
21
23
|
const objects = useObjects()
|
|
22
24
|
const draggable = useDraggable('treeview')
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
</script>
|
|
41
43
|
|
|
42
44
|
<div
|
|
43
|
-
class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 overflow-y-auto border text-xs"
|
|
45
|
+
class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 w-60 overflow-y-auto border text-xs"
|
|
44
46
|
style:transform="translate({draggable.current.x}px, {draggable.current.y}px)"
|
|
45
47
|
{...rest}
|
|
46
48
|
>
|
|
@@ -56,9 +58,10 @@
|
|
|
56
58
|
/>
|
|
57
59
|
{/key}
|
|
58
60
|
|
|
59
|
-
{#if environment.current.isStandalone}
|
|
61
|
+
{#if environment.current.isStandalone && partID.current}
|
|
60
62
|
<AddFrames />
|
|
61
63
|
{/if}
|
|
64
|
+
|
|
62
65
|
<Logs />
|
|
63
66
|
<Settings />
|
|
64
67
|
<Widgets />
|
|
@@ -74,6 +74,21 @@
|
|
|
74
74
|
</Portal>
|
|
75
75
|
{/each}
|
|
76
76
|
|
|
77
|
+
{#each drawAPI.frames as object (object.uuid)}
|
|
78
|
+
<Portal id={object.referenceFrame}>
|
|
79
|
+
<Frame
|
|
80
|
+
uuid={object.uuid}
|
|
81
|
+
name={object.name}
|
|
82
|
+
pose={object.pose}
|
|
83
|
+
geometry={object.geometry}
|
|
84
|
+
metadata={object.metadata}
|
|
85
|
+
>
|
|
86
|
+
<PortalTarget id={object.name} />
|
|
87
|
+
<Label text={object.name} />
|
|
88
|
+
</Frame>
|
|
89
|
+
</Portal>
|
|
90
|
+
{/each}
|
|
91
|
+
|
|
77
92
|
{#each drawAPI.points as object (object.uuid)}
|
|
78
93
|
<Portal id={object.referenceFrame}>
|
|
79
94
|
<Pointcloud {object}>
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
}
|
|
10
10
|
let { experiment, children, renderIfActive = true }: Props = $props()
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const weblabs = useWeblabs()
|
|
13
13
|
|
|
14
14
|
$effect.pre(() => {
|
|
15
|
-
|
|
15
|
+
weblabs.load([experiment])
|
|
16
16
|
})
|
|
17
17
|
</script>
|
|
18
18
|
|
|
19
|
-
{#if
|
|
19
|
+
{#if weblabs.isActive(experiment) === renderIfActive}
|
|
20
20
|
{@render children()}
|
|
21
21
|
{/if}
|