@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
|
Binary file
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
import FileDrop from './FileDrop/FileDrop.svelte'
|
|
18
18
|
import { provideWeblabs } from '../hooks/useWeblabs.svelte'
|
|
19
19
|
import { providePartConfig } from '../hooks/usePartConfig.svelte'
|
|
20
|
-
import { useViamClient } from '@viamrobotics/svelte-sdk'
|
|
21
20
|
import LiveUpdatesBanner from './overlay/LiveUpdatesBanner.svelte'
|
|
22
21
|
import ArmPositions from './overlay/widgets/ArmPositions.svelte'
|
|
23
22
|
import { provideEnvironment } from '../hooks/useEnvironment.svelte'
|
|
@@ -31,12 +30,13 @@
|
|
|
31
30
|
import HoveredEntities from './hover/HoveredEntities.svelte'
|
|
32
31
|
import Settings from './overlay/settings/Settings.svelte'
|
|
33
32
|
import { useXR } from '@threlte/xr'
|
|
33
|
+
import Logs from './overlay/Logs.svelte'
|
|
34
34
|
|
|
35
35
|
interface LocalConfigProps {
|
|
36
|
-
|
|
36
|
+
current: Struct
|
|
37
|
+
isDirty: boolean
|
|
38
|
+
componentToFragId: Record<string, string>
|
|
37
39
|
setLocalPartConfig: (config: Struct) => void
|
|
38
|
-
isDirty: () => boolean
|
|
39
|
-
getComponentToFragId: () => Record<string, string>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
interface Props {
|
|
@@ -65,7 +65,6 @@
|
|
|
65
65
|
|
|
66
66
|
provideWorld()
|
|
67
67
|
|
|
68
|
-
const appClient = useViamClient()
|
|
69
68
|
const settings = provideSettings()
|
|
70
69
|
const environment = provideEnvironment()
|
|
71
70
|
const currentRobotCameraWidgets = $derived(settings.current.openCameraWidgets[partID] || [])
|
|
@@ -82,25 +81,10 @@
|
|
|
82
81
|
|
|
83
82
|
let root = $state.raw<HTMLElement>()
|
|
84
83
|
|
|
85
|
-
providePartConfig(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
isDirty: () => localConfigProps.isDirty(),
|
|
90
|
-
getLocalPartConfig: () => localConfigProps.getLocalPartConfig(),
|
|
91
|
-
setLocalPartConfig: (config: Struct) => localConfigProps.setLocalPartConfig(config),
|
|
92
|
-
getComponentToFragId: () => localConfigProps.getComponentToFragId(),
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
} else {
|
|
96
|
-
return {
|
|
97
|
-
standalonePartConfigProps: {
|
|
98
|
-
viamClient: () => appClient?.current,
|
|
99
|
-
partID: () => partID,
|
|
100
|
-
},
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
})
|
|
84
|
+
providePartConfig(
|
|
85
|
+
() => partID,
|
|
86
|
+
() => localConfigProps
|
|
87
|
+
)
|
|
104
88
|
|
|
105
89
|
$effect.pre(() => {
|
|
106
90
|
if (localConfigProps) {
|
|
@@ -137,7 +121,6 @@
|
|
|
137
121
|
<FileDrop />
|
|
138
122
|
<Dashboard {dashboard} />
|
|
139
123
|
<Details />
|
|
140
|
-
<Settings />
|
|
141
124
|
|
|
142
125
|
{#if environment.current.isStandalone}
|
|
143
126
|
<LiveUpdatesBanner />
|
|
@@ -158,6 +141,9 @@
|
|
|
158
141
|
{/if}
|
|
159
142
|
|
|
160
143
|
<PortalTarget id="dom" />
|
|
144
|
+
|
|
145
|
+
<Settings />
|
|
146
|
+
<Logs />
|
|
161
147
|
</div>
|
|
162
148
|
{/snippet}
|
|
163
149
|
</SceneProviders>
|
|
@@ -3,10 +3,10 @@ import type { Struct } from '@viamrobotics/sdk';
|
|
|
3
3
|
import type { CameraPose } from '../hooks/useControls.svelte';
|
|
4
4
|
import { type DrawConnectionConfig } from '../hooks/useDrawConnectionConfig.svelte';
|
|
5
5
|
interface LocalConfigProps {
|
|
6
|
-
|
|
6
|
+
current: Struct;
|
|
7
|
+
isDirty: boolean;
|
|
8
|
+
componentToFragId: Record<string, string>;
|
|
7
9
|
setLocalPartConfig: (config: Struct) => void;
|
|
8
|
-
isDirty: () => boolean;
|
|
9
|
-
getComponentToFragId: () => Record<string, string>;
|
|
10
10
|
}
|
|
11
11
|
interface Props {
|
|
12
12
|
partID?: string;
|
|
@@ -135,17 +135,17 @@
|
|
|
135
135
|
/>
|
|
136
136
|
{/if}
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
is={
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
138
|
+
{#if model && renderMode.includes('model')}
|
|
139
|
+
<T is={model} />
|
|
140
|
+
{/if}
|
|
141
|
+
|
|
142
|
+
{#if !model || renderMode.includes('colliders')}
|
|
143
|
+
<T
|
|
144
|
+
is={mesh}
|
|
145
|
+
name={entity}
|
|
146
|
+
userData.name={name}
|
|
147
|
+
renderOrder={renderOrder.current}
|
|
148
|
+
>
|
|
149
149
|
{#if linePositions.current}
|
|
150
150
|
<LineGeometry positions={linePositions.current} />
|
|
151
151
|
{:else if box.current}
|
|
@@ -168,40 +168,40 @@
|
|
|
168
168
|
{oncreate}
|
|
169
169
|
/>
|
|
170
170
|
{/if}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
171
|
+
|
|
172
|
+
{#if linePositions.current}
|
|
173
|
+
<T
|
|
174
|
+
is={LineMaterial}
|
|
175
|
+
{color}
|
|
176
|
+
width={lineWidth.current ? lineWidth.current * 0.001 : 0.5}
|
|
177
|
+
depthTest={materialProps.current?.depthTest ?? true}
|
|
178
|
+
/>
|
|
179
|
+
{:else}
|
|
180
|
+
{@const currentOpacity = opacity.current ?? 0.7}
|
|
181
|
+
<T.MeshToonMaterial
|
|
182
|
+
{color}
|
|
183
|
+
side={geometryType === 'buffer' ? DoubleSide : FrontSide}
|
|
184
|
+
transparent={currentOpacity < 1}
|
|
185
|
+
depthWrite={currentOpacity === 1}
|
|
186
|
+
opacity={currentOpacity}
|
|
187
|
+
depthTest={materialProps.current?.depthTest ?? true}
|
|
188
|
+
/>
|
|
189
|
+
|
|
190
|
+
{#if geo && (renderMode.includes('colliders') || !model)}
|
|
191
|
+
<T.LineSegments
|
|
192
|
+
raycast={() => null}
|
|
193
|
+
bvh={{ enabled: false }}
|
|
194
|
+
>
|
|
195
|
+
<T.EdgesGeometry args={[geo, 0]} />
|
|
196
|
+
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
197
|
+
</T.LineSegments>
|
|
198
|
+
{/if}
|
|
199
199
|
{/if}
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
</T>
|
|
201
|
+
{/if}
|
|
202
202
|
{:else if showAxesHelper.current}
|
|
203
203
|
<AxesHelper
|
|
204
|
-
name={
|
|
204
|
+
name={entity}
|
|
205
205
|
width={3}
|
|
206
206
|
length={0.1}
|
|
207
207
|
/>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ShaderMaterial, Vector3 } from 'three'
|
|
3
3
|
import { T } from '@threlte/core'
|
|
4
|
-
import { Grid, interactivity, PerfMonitor, PortalTarget } from '@threlte/extras'
|
|
4
|
+
import { Environment, Grid, interactivity, PerfMonitor, PortalTarget } from '@threlte/extras'
|
|
5
5
|
import Entities from './Entities.svelte'
|
|
6
6
|
import Selected from './Selected.svelte'
|
|
7
7
|
import Focus from './Focus.svelte'
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import PointerMissBox from './PointerMissBox.svelte'
|
|
19
19
|
import BatchedArrows from './BatchedArrows.svelte'
|
|
20
20
|
import Arrows from './Arrows/ArrowGroups.svelte'
|
|
21
|
+
import hdrImage from '../assets/ferndale_studio_11_1k.hdr'
|
|
21
22
|
|
|
22
23
|
interface Props {
|
|
23
24
|
children?: Snippet
|
|
@@ -54,6 +55,8 @@
|
|
|
54
55
|
<PerfMonitor anchorX="right" />
|
|
55
56
|
{/if}
|
|
56
57
|
|
|
58
|
+
<Environment url={hdrImage} />
|
|
59
|
+
|
|
57
60
|
<T.Group
|
|
58
61
|
position={origin.position}
|
|
59
62
|
rotation.x={$isPresenting ? -Math.PI / 2 : 0}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { provide3DModels } from '../hooks/use3DModels.svelte'
|
|
24
24
|
import { providePointcloudObjects } from '../hooks/usePointcloudObjects.svelte'
|
|
25
25
|
import { provideLinkedEntities } from '../hooks/useLinked.svelte'
|
|
26
|
+
import { provideConfigFrames } from '../hooks/useConfigFrames.svelte'
|
|
26
27
|
|
|
27
28
|
interface Props {
|
|
28
29
|
cameraPose?: CameraPose
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
provideDrawAPI()
|
|
44
45
|
|
|
45
46
|
provideResourceByName(() => partID.current)
|
|
47
|
+
provideConfigFrames()
|
|
46
48
|
provideFrames(() => partID.current)
|
|
47
49
|
provideGeometries(() => partID.current)
|
|
48
50
|
provide3DModels(() => partID.current)
|
|
@@ -15,19 +15,17 @@
|
|
|
15
15
|
const selectedObject3d = useSelectedObject3d()
|
|
16
16
|
|
|
17
17
|
const object = $derived.by(() => {
|
|
18
|
-
if (!
|
|
19
|
-
return
|
|
18
|
+
if (!selectedObject3d.current) {
|
|
19
|
+
return
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// Create a clone in the case of meshes, which could be frames with geometries,
|
|
23
23
|
// so that our bounding box doesn't include children
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (result) {
|
|
27
|
-
selectedObject3d.current?.getWorldPosition(result.position)
|
|
28
|
-
selectedObject3d.current?.getWorldQuaternion(result.quaternion)
|
|
29
|
-
return result
|
|
24
|
+
if (isInstanceOf(selectedObject3d.current, 'Mesh')) {
|
|
25
|
+
return selectedObject3d.current?.clone(false)
|
|
30
26
|
}
|
|
27
|
+
|
|
28
|
+
return selectedObject3d.current
|
|
31
29
|
})
|
|
32
30
|
|
|
33
31
|
const { start, stop } = useTask(
|
|
@@ -44,7 +42,9 @@
|
|
|
44
42
|
mesh.getBoundingBoxAt(selectedEntity.instance, box3)
|
|
45
43
|
obb.fromBox3(box3)
|
|
46
44
|
obbHelper.setFromOBB(obb)
|
|
47
|
-
} else {
|
|
45
|
+
} else if (isInstanceOf(selectedObject3d.current, 'Mesh')) {
|
|
46
|
+
selectedObject3d.current?.getWorldPosition(object.position)
|
|
47
|
+
selectedObject3d.current?.getWorldQuaternion(object.quaternion)
|
|
48
48
|
obbHelper.setFromObject(object)
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
const entity = world.spawn(
|
|
40
40
|
traits.Name(`custom geometry ${++index}`),
|
|
41
41
|
traits.Pose,
|
|
42
|
-
traits.Box({ x:
|
|
42
|
+
traits.Box({ x: 100, y: 100, z: 100 }),
|
|
43
43
|
traits.Removable
|
|
44
44
|
)
|
|
45
45
|
|
|
@@ -87,7 +87,10 @@
|
|
|
87
87
|
ref.quaternion.copy(quaternion)
|
|
88
88
|
entity.set(traits.Pose, pose)
|
|
89
89
|
} else if (box && mode === 'scale') {
|
|
90
|
-
|
|
90
|
+
box.x *= ref.scale.x
|
|
91
|
+
box.y *= ref.scale.y
|
|
92
|
+
box.z *= ref.scale.z
|
|
93
|
+
entity.set(traits.Box, box)
|
|
91
94
|
ref.scale.setScalar(1)
|
|
92
95
|
}
|
|
93
96
|
}}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
useFocusedObject3d,
|
|
22
22
|
useSelectedObject3d,
|
|
23
23
|
} from '../../hooks/useSelection.svelte'
|
|
24
|
-
import {
|
|
24
|
+
import { useConfigFrames } from '../../hooks/useConfigFrames.svelte'
|
|
25
25
|
import { usePartConfig } from '../../hooks/usePartConfig.svelte'
|
|
26
26
|
import { FrameConfigUpdater } from '../../FrameConfigUpdater.svelte'
|
|
27
27
|
import { useEnvironment } from '../../hooks/useEnvironment.svelte'
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
const world = useWorld()
|
|
38
38
|
const controls = useCameraControls()
|
|
39
39
|
const resourceByName = useResourceByName()
|
|
40
|
-
const
|
|
40
|
+
const configFrames = useConfigFrames()
|
|
41
41
|
const partConfig = usePartConfig()
|
|
42
42
|
const selectedEntity = useSelectedEntity()
|
|
43
43
|
const selectedObject3d = useSelectedObject3d()
|
|
@@ -402,7 +402,7 @@
|
|
|
402
402
|
{@render ParentFrame({
|
|
403
403
|
ariaLabel: 'parent frame name',
|
|
404
404
|
value: parent.current ?? 'world',
|
|
405
|
-
options:
|
|
405
|
+
options: configFrames.getParentFrameOptions(name.current ?? ''),
|
|
406
406
|
onChange: (value) => {
|
|
407
407
|
detailConfigUpdater.setFrameParent(entity, value)
|
|
408
408
|
},
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
defaultSize?: { width: number; height: number }
|
|
11
11
|
defaultPosition?: { x: number; y: number }
|
|
12
12
|
exitable?: boolean
|
|
13
|
+
persistRect?: boolean
|
|
13
14
|
strategy?: 'absolute' | 'fixed'
|
|
14
15
|
isOpen?: boolean
|
|
15
16
|
children: Snippet
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
title = '',
|
|
20
21
|
defaultSize = { width: 700, height: 500 },
|
|
21
22
|
exitable = true,
|
|
23
|
+
persistRect = true,
|
|
22
24
|
isOpen = $bindable(false),
|
|
23
25
|
children,
|
|
24
26
|
...props
|
|
@@ -30,6 +32,7 @@
|
|
|
30
32
|
defaultSize,
|
|
31
33
|
resizable: false,
|
|
32
34
|
allowOverflow: false,
|
|
35
|
+
persistRect,
|
|
33
36
|
open: isOpen,
|
|
34
37
|
...props,
|
|
35
38
|
}))
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
if (event.key.toLowerCase() === 's') {
|
|
18
18
|
event.preventDefault()
|
|
19
19
|
event.stopImmediatePropagation()
|
|
20
|
-
partConfig.
|
|
20
|
+
partConfig.save()
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<Button
|
|
44
44
|
class="cursor-pointer text-blue-600"
|
|
45
45
|
onclick={() => {
|
|
46
|
-
partConfig.
|
|
46
|
+
partConfig.discardChanges()
|
|
47
47
|
}}
|
|
48
48
|
>
|
|
49
49
|
Discard
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
aria-label="Save"
|
|
55
55
|
class="cursor-pointer text-blue-600"
|
|
56
56
|
onclick={() => {
|
|
57
|
-
partConfig.
|
|
57
|
+
partConfig.save()
|
|
58
58
|
}}
|
|
59
59
|
>
|
|
60
60
|
<div class="flex gap-2">
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Portal } from '@threlte/extras'
|
|
3
|
+
import { useLogs } from '../../hooks/useLogs.svelte'
|
|
4
|
+
import FloatingPanel from './FloatingPanel.svelte'
|
|
5
|
+
import DashboardButton from './dashboard/Button.svelte'
|
|
6
|
+
import { PersistedState } from 'runed'
|
|
7
|
+
|
|
8
|
+
const logs = useLogs()
|
|
9
|
+
|
|
10
|
+
const isOpen = new PersistedState('logs-is-open', false)
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Portal id="dashboard">
|
|
14
|
+
<fieldset class="relative">
|
|
15
|
+
<DashboardButton
|
|
16
|
+
active
|
|
17
|
+
icon="article"
|
|
18
|
+
description="Logs"
|
|
19
|
+
onclick={() => {
|
|
20
|
+
isOpen.current = !isOpen.current
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
{#if logs.warnings.length > 0}
|
|
24
|
+
<span
|
|
25
|
+
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 w-4 rounded-full bg-yellow-700 text-center text-[10px] text-white"
|
|
26
|
+
>
|
|
27
|
+
{logs.warnings.length}
|
|
28
|
+
</span>
|
|
29
|
+
{/if}
|
|
30
|
+
|
|
31
|
+
{#if logs.errors.length > 0}
|
|
32
|
+
<span
|
|
33
|
+
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 rounded-full bg-red-700 px-1.25 text-center text-[10px] text-white"
|
|
34
|
+
>
|
|
35
|
+
{logs.errors.length}
|
|
36
|
+
</span>
|
|
37
|
+
{/if}
|
|
38
|
+
</fieldset>
|
|
39
|
+
</Portal>
|
|
40
|
+
|
|
41
|
+
<FloatingPanel
|
|
42
|
+
title="Logs"
|
|
43
|
+
bind:isOpen={isOpen.current}
|
|
44
|
+
defaultSize={{ width: 240, height: 315 }}
|
|
45
|
+
>
|
|
46
|
+
<div class="flex h-70 flex-col gap-2 overflow-auto p-3 text-xs">
|
|
47
|
+
{#each logs.current as log (log.uuid)}
|
|
48
|
+
<div>
|
|
49
|
+
<div class="flex flex-wrap items-center gap-1.5">
|
|
50
|
+
<div
|
|
51
|
+
class={[
|
|
52
|
+
'h-2 w-2 rounded-full',
|
|
53
|
+
{
|
|
54
|
+
'bg-danger-dark': log.level === 'error',
|
|
55
|
+
'bg-amber-300': log.level === 'warn',
|
|
56
|
+
'bg-blue-400': log.level === 'info',
|
|
57
|
+
},
|
|
58
|
+
]}
|
|
59
|
+
></div>
|
|
60
|
+
<div class="text-subtle-2">{log.timestamp}</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div>
|
|
63
|
+
{#if log.count > 1}
|
|
64
|
+
<span class="mr-1 rounded bg-green-700 px-1 py-0.5 text-xs text-white">
|
|
65
|
+
{log.count}
|
|
66
|
+
</span>
|
|
67
|
+
{/if}
|
|
68
|
+
{log.message}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
{:else}
|
|
72
|
+
No logs
|
|
73
|
+
{/each}
|
|
74
|
+
</div>
|
|
75
|
+
</FloatingPanel>
|
|
@@ -7,8 +7,17 @@ export declare const resource: {
|
|
|
7
7
|
y: number;
|
|
8
8
|
z: number;
|
|
9
9
|
};
|
|
10
|
+
orientation: {
|
|
11
|
+
type: "ov_degrees";
|
|
12
|
+
value: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
z: number;
|
|
16
|
+
th: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
10
19
|
geometry: {
|
|
11
|
-
type:
|
|
20
|
+
type: "box";
|
|
12
21
|
x: number;
|
|
13
22
|
y: number;
|
|
14
23
|
z: number;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import Tree from './Tree.svelte'
|
|
4
4
|
import { useSelectedEntity } from '../../../hooks/useSelection.svelte'
|
|
5
5
|
import { provideTreeExpandedContext } from './useExpanded.svelte'
|
|
6
|
-
import Logs from './Logs.svelte'
|
|
7
6
|
import AddFrames from './AddFrames.svelte'
|
|
8
7
|
import { useEnvironment } from '../../../hooks/useEnvironment.svelte'
|
|
9
8
|
import { usePartID } from '../../../hooks/usePartID.svelte'
|
|
@@ -82,6 +81,4 @@
|
|
|
82
81
|
{#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
|
|
83
82
|
<AddFrames />
|
|
84
83
|
{/if}
|
|
85
|
-
|
|
86
|
-
<Logs />
|
|
87
84
|
</div>
|
|
@@ -4,6 +4,7 @@ import { getContext, setContext } from 'svelte';
|
|
|
4
4
|
import { useSettings } from './useSettings.svelte';
|
|
5
5
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
6
6
|
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
|
|
7
|
+
import { isInstanceOf } from '@threlte/core';
|
|
7
8
|
const gltfLoader = new GLTFLoader();
|
|
8
9
|
const dracoLoader = new DRACOLoader();
|
|
9
10
|
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
|
|
@@ -38,6 +39,15 @@ export const provide3DModels = (partID) => {
|
|
|
38
39
|
const arrayBuffer = model.mesh.buffer.slice(model.mesh.byteOffset, model.mesh.byteOffset + model.mesh.byteLength);
|
|
39
40
|
const gltfModel = await gltfLoader.parseAsync(arrayBuffer, '');
|
|
40
41
|
next[prefix][id] = gltfModel.scene;
|
|
42
|
+
gltfModel.scene.traverse((object) => {
|
|
43
|
+
if (isInstanceOf(object, 'Mesh')) {
|
|
44
|
+
const { material } = object;
|
|
45
|
+
if (isInstanceOf(material, 'MeshStandardMaterial')) {
|
|
46
|
+
material.roughness = 0.3;
|
|
47
|
+
material.metalness = 0.1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
41
51
|
}
|
|
42
52
|
current = next;
|
|
43
53
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Transform } from '@viamrobotics/sdk';
|
|
2
|
+
interface ConfigFramesContext {
|
|
3
|
+
unsetFrames: string[];
|
|
4
|
+
current: Record<string, Transform>;
|
|
5
|
+
getParentFrameOptions: (componentName: string) => string[];
|
|
6
|
+
}
|
|
7
|
+
export declare const provideConfigFrames: () => void;
|
|
8
|
+
export declare const useConfigFrames: () => ConfigFramesContext;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useEnvironment } from './useEnvironment.svelte';
|
|
2
|
+
import { usePartConfig } from './usePartConfig.svelte';
|
|
3
|
+
import { createTransformFromFrame } from '../frame';
|
|
4
|
+
import { Transform } from '@viamrobotics/sdk';
|
|
5
|
+
import { getContext, setContext } from 'svelte';
|
|
6
|
+
const key = Symbol('config-frames-context');
|
|
7
|
+
export const provideConfigFrames = () => {
|
|
8
|
+
const environment = useEnvironment();
|
|
9
|
+
const partConfig = usePartConfig();
|
|
10
|
+
$effect(() => {
|
|
11
|
+
if (partConfig.isDirty) {
|
|
12
|
+
environment.current.viewerMode = 'edit';
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
environment.current.viewerMode = 'monitor';
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const [configFrames, configUnsetFrameNames] = $derived.by(() => {
|
|
19
|
+
const { components } = partConfig.current;
|
|
20
|
+
const results = {};
|
|
21
|
+
const unsetResults = [];
|
|
22
|
+
for (const { name, frame } of components ?? []) {
|
|
23
|
+
if (!frame) {
|
|
24
|
+
unsetResults.push(name);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
results[name] = createTransformFromFrame(name, frame);
|
|
28
|
+
}
|
|
29
|
+
return [results, unsetResults];
|
|
30
|
+
});
|
|
31
|
+
const [fragmentFrames, fragmentUnsetFrameNames] = $derived.by(() => {
|
|
32
|
+
const { fragment_mods: fragmentMods = [] } = partConfig.current;
|
|
33
|
+
const fragmentDefinedComponents = Object.keys(partConfig.componentNameToFragmentId);
|
|
34
|
+
const results = {};
|
|
35
|
+
const unsetResults = [];
|
|
36
|
+
// deal with fragment defined components
|
|
37
|
+
for (const fragmentComponentName of fragmentDefinedComponents || []) {
|
|
38
|
+
const fragmentId = partConfig.componentNameToFragmentId[fragmentComponentName];
|
|
39
|
+
const fragmentMod = fragmentMods?.find((mod) => mod.fragment_id === fragmentId);
|
|
40
|
+
if (!fragmentMod) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const setComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$set']?.[`components.${fragmentComponentName}.frame`] !== undefined);
|
|
44
|
+
const unsetComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$unset']?.[`components.${fragmentComponentName}.frame`] !== undefined);
|
|
45
|
+
if (setComponentModIndex < unsetComponentModIndex) {
|
|
46
|
+
unsetResults.push(fragmentComponentName);
|
|
47
|
+
}
|
|
48
|
+
else if (unsetComponentModIndex < setComponentModIndex) {
|
|
49
|
+
const frameData = fragmentMod.mods[setComponentModIndex]['$set'][`components.${fragmentComponentName}.frame`];
|
|
50
|
+
results[fragmentComponentName] = createTransformFromFrame(fragmentComponentName, frameData);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [results, unsetResults];
|
|
54
|
+
});
|
|
55
|
+
const frames = $derived.by(() => {
|
|
56
|
+
const result = {
|
|
57
|
+
...configFrames,
|
|
58
|
+
...fragmentFrames,
|
|
59
|
+
};
|
|
60
|
+
return result;
|
|
61
|
+
});
|
|
62
|
+
const frameValues = $derived(Object.values(frames));
|
|
63
|
+
const getParentFrameOptions = (componentName) => {
|
|
64
|
+
const validFrames = new Set(frameValues.map((frame) => frame.referenceFrame));
|
|
65
|
+
validFrames.add('world');
|
|
66
|
+
const frameNameQueue = [componentName];
|
|
67
|
+
while (frameNameQueue.length > 0) {
|
|
68
|
+
const frameName = frameNameQueue.shift();
|
|
69
|
+
if (frameName) {
|
|
70
|
+
validFrames.delete(frameName);
|
|
71
|
+
const filteredFrames = frameValues.filter((frame) => frame.poseInObserverFrame?.referenceFrame === frameName);
|
|
72
|
+
for (const frame of filteredFrames) {
|
|
73
|
+
frameNameQueue.push(frame.referenceFrame);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Array.from(validFrames);
|
|
78
|
+
};
|
|
79
|
+
const unsetFrames = $derived([...new Set([...configUnsetFrameNames, ...fragmentUnsetFrameNames])]);
|
|
80
|
+
setContext(key, {
|
|
81
|
+
getParentFrameOptions,
|
|
82
|
+
get unsetFrames() {
|
|
83
|
+
return unsetFrames;
|
|
84
|
+
},
|
|
85
|
+
get current() {
|
|
86
|
+
return frames;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
export const useConfigFrames = () => {
|
|
91
|
+
return getContext(key);
|
|
92
|
+
};
|
|
@@ -6,13 +6,13 @@ export const provideFramelessComponents = () => {
|
|
|
6
6
|
const partConfig = usePartConfig();
|
|
7
7
|
const frames = useFrames();
|
|
8
8
|
const current = $derived.by(() => {
|
|
9
|
-
const components = partConfig.
|
|
9
|
+
const { components } = partConfig.current;
|
|
10
10
|
const partComponentsWIthNoFrame = components
|
|
11
11
|
?.filter((component) => component.frame === undefined)
|
|
12
12
|
.map((component) => component.name) ?? [];
|
|
13
13
|
const fragmentComponentsWithNoFrame = [];
|
|
14
14
|
for (const fragmentComponentName of Object.keys(partConfig.componentNameToFragmentId)) {
|
|
15
|
-
if (frames.current.find((frame) => frame.
|
|
15
|
+
if (frames.current.find((frame) => frame.referenceFrame === fragmentComponentName)) {
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
18
|
fragmentComponentsWithNoFrame.push(fragmentComponentName);
|