@viamrobotics/motion-tools 0.19.2 → 1.0.2
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/README.md +56 -26
- package/dist/FrameConfigUpdater.svelte.d.ts +11 -17
- package/dist/FrameConfigUpdater.svelte.js +109 -109
- package/dist/WorldObject.svelte.js +2 -15
- package/dist/common/v1/common_pb.d.ts +950 -0
- package/dist/common/v1/common_pb.js +1399 -0
- package/dist/components/App.svelte +37 -21
- package/dist/components/App.svelte.d.ts +1 -0
- package/dist/components/BatchedArrows.svelte +102 -0
- package/dist/components/BatchedArrows.svelte.d.ts +3 -0
- package/dist/components/CameraControls.svelte +2 -3
- package/dist/components/Details.svelte +364 -365
- package/dist/components/Entities.svelte +73 -0
- package/dist/components/{WorldObjects.svelte.d.ts → Entities.svelte.d.ts} +3 -3
- package/dist/components/FileDrop.svelte +9 -23
- package/dist/components/Focus.svelte +2 -3
- package/dist/components/Frame.svelte +41 -22
- package/dist/components/Frame.svelte.d.ts +4 -6
- package/dist/components/GLTF.svelte +36 -0
- package/dist/components/GLTF.svelte.d.ts +11 -0
- package/dist/components/Geometry2.svelte +201 -0
- package/dist/components/Geometry2.svelte.d.ts +18 -0
- package/dist/components/KeyboardControls.svelte +3 -3
- package/dist/components/Line.svelte +10 -13
- package/dist/components/Line.svelte.d.ts +2 -2
- package/dist/components/LiveUpdatesBanner.svelte +51 -15
- package/dist/components/MeasureTool.svelte +4 -5
- package/dist/components/Pointcloud.svelte +27 -14
- package/dist/components/Pointcloud.svelte.d.ts +2 -2
- package/dist/components/PointerMissBox.svelte +3 -3
- package/dist/components/Pose.svelte +31 -6
- package/dist/components/Pose.svelte.d.ts +2 -2
- package/dist/components/Scene.svelte +7 -6
- package/dist/components/SceneProviders.svelte +0 -6
- package/dist/components/Selected.svelte +22 -16
- package/dist/components/StaticGeometries.svelte +51 -27
- package/dist/components/Tree/Tree.svelte +28 -22
- package/dist/components/Tree/Tree.svelte.d.ts +2 -3
- package/dist/components/Tree/TreeContainer.svelte +72 -40
- package/dist/components/Tree/Widgets.svelte +2 -5
- package/dist/components/Tree/buildTree.d.ts +3 -6
- package/dist/components/Tree/buildTree.js +19 -39
- package/dist/components/__tests__/__fixtures__/entity.d.ts +2 -0
- package/dist/components/__tests__/__fixtures__/entity.js +20 -0
- package/dist/components/__tests__/__fixtures__/resource.d.ts +17 -0
- package/dist/components/__tests__/__fixtures__/resource.js +13 -0
- package/dist/components/dashboard/Dashboard.svelte +5 -3
- package/dist/components/dashboard/Dashboard.svelte.d.ts +7 -2
- package/dist/components/widgets/ArmPositions.svelte +19 -7
- package/dist/draw/v1/drawing_pb.d.ts +341 -0
- package/dist/draw/v1/drawing_pb.js +417 -0
- package/dist/draw/v1/metadata_pb.d.ts +23 -0
- package/dist/draw/v1/metadata_pb.js +39 -0
- package/dist/draw/v1/scene_pb.d.ts +230 -0
- package/dist/draw/v1/scene_pb.js +298 -0
- package/dist/draw/v1/snapshot_pb.d.ts +42 -0
- package/dist/draw/v1/snapshot_pb.js +61 -0
- package/dist/draw/v1/transforms_pb.d.ts +23 -0
- package/dist/draw/v1/transforms_pb.js +39 -0
- package/dist/ecs/index.d.ts +4 -0
- package/dist/ecs/index.js +4 -0
- package/dist/ecs/traits.d.ts +128 -0
- package/dist/ecs/traits.js +81 -0
- package/dist/ecs/useQuery.svelte.d.ts +4 -0
- package/dist/ecs/useQuery.svelte.js +49 -0
- package/dist/ecs/useTrait.svelte.d.ts +19 -0
- package/dist/ecs/useTrait.svelte.js +40 -0
- package/dist/ecs/useWorld.d.ts +4 -0
- package/dist/ecs/useWorld.js +10 -0
- package/dist/geometry.js +6 -6
- package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte +41 -0
- package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte.d.ts +6 -0
- package/dist/hooks/use3DModels.svelte.js +6 -4
- package/dist/hooks/useDrawAPI.svelte.d.ts +0 -10
- package/dist/hooks/useDrawAPI.svelte.js +143 -267
- package/dist/hooks/useFramelessComponents.svelte.js +1 -1
- package/dist/hooks/useFrames.svelte.d.ts +6 -2
- package/dist/hooks/useFrames.svelte.js +123 -19
- package/dist/hooks/useGeometries.svelte.d.ts +0 -2
- package/dist/hooks/useGeometries.svelte.js +49 -25
- package/dist/hooks/useObjectEvents.svelte.d.ts +3 -2
- package/dist/hooks/useObjectEvents.svelte.js +11 -7
- package/dist/hooks/usePartConfig.svelte.d.ts +1 -1
- package/dist/hooks/usePartConfig.svelte.js +2 -1
- package/dist/hooks/usePointclouds.svelte.d.ts +0 -2
- package/dist/hooks/usePointclouds.svelte.js +52 -21
- package/dist/hooks/usePose.svelte.js +15 -7
- package/dist/hooks/useResizable.svelte.d.ts +12 -0
- package/dist/hooks/useResizable.svelte.js +45 -0
- package/dist/hooks/useResourceByName.svelte.js +8 -5
- package/dist/hooks/useSelection.svelte.d.ts +13 -23
- package/dist/hooks/useSelection.svelte.js +45 -65
- package/dist/hooks/useVisibility.svelte.d.ts +2 -1
- package/dist/hooks/useWeblabs.svelte.d.ts +0 -1
- package/dist/hooks/useWeblabs.svelte.js +0 -1
- package/dist/hooks/useWorldState.svelte.d.ts +9 -0
- package/dist/hooks/useWorldState.svelte.js +158 -107
- package/dist/lib.d.ts +1 -0
- package/dist/lib.js +2 -0
- package/dist/three/BatchedArrow.d.ts +2 -3
- package/dist/three/BatchedArrow.js +3 -11
- package/dist/three/CapsuleGeometry.d.ts +1 -1
- package/dist/three/CapsuleGeometry.js +3 -1
- package/dist/transform.js +0 -15
- package/package.json +12 -7
- package/dist/components/WorldObject.svelte +0 -28
- package/dist/components/WorldObject.svelte.d.ts +0 -11
- package/dist/components/WorldObjects.svelte +0 -159
- package/dist/components/WorldState.svelte +0 -92
- package/dist/components/WorldState.svelte.d.ts +0 -7
- package/dist/components/__tests__/__fixtures__/worldObject.svelte.d.ts +0 -2
- package/dist/components/__tests__/__fixtures__/worldObject.svelte.js +0 -35
- package/dist/components/portal/Portal.svelte +0 -25
- package/dist/components/portal/Portal.svelte.d.ts +0 -8
- package/dist/components/portal/PortalTarget.svelte +0 -18
- package/dist/components/portal/PortalTarget.svelte.d.ts +0 -6
- package/dist/components/portal/index.d.ts +0 -2
- package/dist/components/portal/index.js +0 -2
- package/dist/components/portal/usePortalContext.svelte.d.ts +0 -5
- package/dist/components/portal/usePortalContext.svelte.js +0 -5
- package/dist/hooks/useArrows.svelte.d.ts +0 -3
- package/dist/hooks/useArrows.svelte.js +0 -9
- package/dist/hooks/useDraggable.svelte.d.ts +0 -10
- package/dist/hooks/useDraggable.svelte.js +0 -36
- package/dist/hooks/useObjects.svelte.d.ts +0 -7
- package/dist/hooks/useObjects.svelte.js +0 -35
- package/dist/hooks/usePersistentUUIDs.svelte.d.ts +0 -5
- package/dist/hooks/usePersistentUUIDs.svelte.js +0 -13
- package/dist/hooks/useResourceByName.svelte.d.ts +0 -7
- package/dist/hooks/useStaticGeometries.svelte.d.ts +0 -9
- package/dist/hooks/useStaticGeometries.svelte.js +0 -47
- package/dist/workers/worldStateWorker.d.ts +0 -1
- package/dist/workers/worldStateWorker.js +0 -114
- package/dist/world-state-messages.d.ts +0 -23
- package/dist/world-state-messages.js +0 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
lang="ts"
|
|
4
4
|
>
|
|
5
5
|
import { OrientationVector } from '../three/OrientationVector'
|
|
6
|
-
import { Quaternion, Vector3, MathUtils } from 'three'
|
|
6
|
+
import { Quaternion, Vector3, MathUtils, type Vector2Like } from 'three'
|
|
7
7
|
|
|
8
8
|
const vec3 = new Vector3()
|
|
9
9
|
const quaternion = new Quaternion()
|
|
@@ -11,68 +11,81 @@
|
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
13
|
<script lang="ts">
|
|
14
|
+
import { draggable } from '@neodrag/svelte'
|
|
14
15
|
import { Check, Copy } from 'lucide-svelte'
|
|
15
16
|
import { useTask } from '@threlte/core'
|
|
16
17
|
import { Button, Icon, Select, Input } from '@viamrobotics/prime-core'
|
|
17
18
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
useFocused,
|
|
19
|
+
useSelectedEntity,
|
|
20
|
+
useFocusedEntity,
|
|
21
21
|
useFocusedObject3d,
|
|
22
22
|
useSelectedObject3d,
|
|
23
23
|
} from '../hooks/useSelection.svelte'
|
|
24
|
-
import { useDraggable } from '../hooks/useDraggable.svelte'
|
|
25
|
-
import WeblabActive from './weblab/WeblabActive.svelte'
|
|
26
24
|
import { useFrames } from '../hooks/useFrames.svelte'
|
|
27
25
|
import { usePartConfig } from '../hooks/usePartConfig.svelte'
|
|
28
26
|
import { FrameConfigUpdater } from '../FrameConfigUpdater.svelte'
|
|
29
|
-
import { useWeblabs } from '../hooks/useWeblabs.svelte'
|
|
30
|
-
import { WEBLABS_EXPERIMENTS } from '../hooks/useWeblabs.svelte'
|
|
31
27
|
import { useEnvironment } from '../hooks/useEnvironment.svelte'
|
|
28
|
+
import { traits, useTrait } from '../ecs'
|
|
29
|
+
import { useResourceByName } from '../hooks/useResourceByName.svelte'
|
|
30
|
+
import { PersistedState } from 'runed'
|
|
32
31
|
|
|
33
32
|
const { ...rest } = $props()
|
|
34
33
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
const dragPosition = new PersistedState<Vector2Like | undefined>(
|
|
35
|
+
'details-drag-position',
|
|
36
|
+
undefined
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const resourceByName = useResourceByName()
|
|
38
40
|
const frames = useFrames()
|
|
39
41
|
const partConfig = usePartConfig()
|
|
40
|
-
const
|
|
42
|
+
const selectedEntity = useSelectedEntity()
|
|
41
43
|
const selectedObject3d = useSelectedObject3d()
|
|
42
|
-
const weblab = useWeblabs()
|
|
43
44
|
const environment = useEnvironment()
|
|
44
|
-
const
|
|
45
|
+
const focusedEntity = useFocusedEntity()
|
|
46
|
+
const focusedObject3d = useFocusedObject3d()
|
|
47
|
+
const entity = $derived(focusedEntity.current ?? selectedEntity.current)
|
|
45
48
|
const object3d = $derived(focusedObject3d.current ?? selectedObject3d.current)
|
|
46
49
|
const worldPosition = $state({ x: 0, y: 0, z: 0 })
|
|
47
50
|
const worldOrientation = $state({ x: 0, y: 0, z: 1, th: 0 })
|
|
48
|
-
let geometryType = $derived.by(
|
|
49
|
-
() =>
|
|
50
|
-
(object?.geometry?.geometryType.case as 'none' | 'box' | 'sphere' | 'capsule' | undefined) ??
|
|
51
|
-
'none'
|
|
52
|
-
)
|
|
53
51
|
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
)
|
|
52
|
+
const name = useTrait(() => entity, traits.Name)
|
|
53
|
+
const parent = useTrait(() => entity, traits.Parent)
|
|
54
|
+
const localPose = useTrait(() => entity, traits.EditedPose)
|
|
55
|
+
const box = useTrait(() => entity, traits.Box)
|
|
56
|
+
const sphere = useTrait(() => entity, traits.Sphere)
|
|
57
|
+
const capsule = useTrait(() => entity, traits.Capsule)
|
|
58
|
+
|
|
59
|
+
const framesAPI = useTrait(() => entity, traits.FramesAPI)
|
|
60
|
+
const isFrameNode = $derived(!!framesAPI.current)
|
|
61
|
+
|
|
60
62
|
const showEditFrameOptions = $derived(isFrameNode && partConfig.hasEditPermissions)
|
|
63
|
+
|
|
64
|
+
const resourceName = $derived(name.current ? resourceByName.current[name.current] : undefined)
|
|
65
|
+
|
|
66
|
+
let geometryType = $derived.by<'box' | 'sphere' | 'capsule' | 'none'>(() => {
|
|
67
|
+
if (box.current) return 'box'
|
|
68
|
+
if (sphere.current) return 'sphere'
|
|
69
|
+
if (capsule.current) return 'capsule'
|
|
70
|
+
return 'none'
|
|
71
|
+
})
|
|
72
|
+
|
|
61
73
|
let copied = $state(false)
|
|
62
74
|
|
|
63
|
-
|
|
75
|
+
let dragElement = $state.raw<HTMLElement>()
|
|
64
76
|
|
|
65
|
-
const detailConfigUpdater = new FrameConfigUpdater(
|
|
66
|
-
() => object,
|
|
67
|
-
partConfig.updateFrame,
|
|
68
|
-
partConfig.deleteFrame,
|
|
69
|
-
() => referenceFrame
|
|
70
|
-
)
|
|
77
|
+
const detailConfigUpdater = new FrameConfigUpdater(partConfig.updateFrame, partConfig.deleteFrame)
|
|
71
78
|
|
|
72
79
|
const setGeometryType = (type: 'none' | 'box' | 'sphere' | 'capsule') => {
|
|
73
|
-
if (type === geometryType)
|
|
80
|
+
if (type === geometryType) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
geometryType = type
|
|
75
|
-
|
|
85
|
+
|
|
86
|
+
if (entity) {
|
|
87
|
+
detailConfigUpdater.setGeometryType(entity, type)
|
|
88
|
+
}
|
|
76
89
|
}
|
|
77
90
|
|
|
78
91
|
const { start, stop } = useTask(
|
|
@@ -109,45 +122,43 @@
|
|
|
109
122
|
})
|
|
110
123
|
|
|
111
124
|
const getCopyClipboardText = () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
z: localPose?.z,
|
|
121
|
-
},
|
|
122
|
-
localOrientation: {
|
|
123
|
-
x: localPose?.oX,
|
|
124
|
-
y: localPose?.oY,
|
|
125
|
-
z: localPose?.oZ,
|
|
126
|
-
th: localPose?.theta,
|
|
127
|
-
},
|
|
128
|
-
geometry: {
|
|
129
|
-
type: geometryType,
|
|
130
|
-
value: object?.geometry?.geometryType.value,
|
|
131
|
-
},
|
|
132
|
-
parentFrame: referenceFrame,
|
|
125
|
+
return JSON.stringify(
|
|
126
|
+
{
|
|
127
|
+
worldPosition: worldPosition,
|
|
128
|
+
worldOrientation: worldOrientation,
|
|
129
|
+
localPosition: {
|
|
130
|
+
x: localPose.current?.x,
|
|
131
|
+
y: localPose.current?.y,
|
|
132
|
+
z: localPose.current?.z,
|
|
133
133
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
worldPosition: worldPosition,
|
|
141
|
-
worldOrientation: worldOrientation,
|
|
142
|
-
geometry: {
|
|
143
|
-
type: geometryType,
|
|
144
|
-
value: object?.geometry?.geometryType.value,
|
|
145
|
-
},
|
|
134
|
+
localOrientation: {
|
|
135
|
+
x: localPose.current?.oX,
|
|
136
|
+
y: localPose.current?.oY,
|
|
137
|
+
z: localPose.current?.oZ,
|
|
138
|
+
th: localPose.current?.theta,
|
|
146
139
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
geometry: {
|
|
141
|
+
type: geometryType,
|
|
142
|
+
value: box.current ?? capsule.current ?? sphere.current,
|
|
143
|
+
},
|
|
144
|
+
parentFrame: parent.current ?? 'world',
|
|
145
|
+
},
|
|
146
|
+
null,
|
|
147
|
+
2
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const isIntermediateInput = (input: string) => {
|
|
152
|
+
if (input === '0') return false
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
input.startsWith('0') ||
|
|
156
|
+
input.startsWith('.') ||
|
|
157
|
+
input.startsWith('-0') ||
|
|
158
|
+
input.startsWith('-.') ||
|
|
159
|
+
(input.includes('.') && input.endsWith('0')) ||
|
|
160
|
+
input.endsWith('.')
|
|
161
|
+
)
|
|
151
162
|
}
|
|
152
163
|
</script>
|
|
153
164
|
|
|
@@ -157,7 +168,7 @@
|
|
|
157
168
|
ariaLabel,
|
|
158
169
|
}: {
|
|
159
170
|
label?: string
|
|
160
|
-
value
|
|
171
|
+
value?: number | string
|
|
161
172
|
ariaLabel: string
|
|
162
173
|
})}
|
|
163
174
|
<div>
|
|
@@ -168,7 +179,7 @@
|
|
|
168
179
|
{label}
|
|
169
180
|
</span>
|
|
170
181
|
|
|
171
|
-
{value}
|
|
182
|
+
{typeof value === 'number' ? value.toFixed(2) : (value ?? '-')}
|
|
172
183
|
</div>
|
|
173
184
|
{/snippet}
|
|
174
185
|
|
|
@@ -179,16 +190,14 @@
|
|
|
179
190
|
onInput,
|
|
180
191
|
}: {
|
|
181
192
|
label: string
|
|
182
|
-
value
|
|
193
|
+
value?: number
|
|
183
194
|
ariaLabel: string
|
|
184
195
|
onInput: (value: string) => void
|
|
185
196
|
})}
|
|
186
197
|
<div class="flex items-center gap-1">
|
|
187
198
|
<span class="text-subtle-2">{label}</span>
|
|
188
199
|
<Input
|
|
189
|
-
type="number"
|
|
190
200
|
aria-label={`mutable ${ariaLabel}`}
|
|
191
|
-
class="max-w-24 min-w-0 flex-1 rounded border px-1 py-0.5 text-xs"
|
|
192
201
|
{value}
|
|
193
202
|
on:input={(event) => onInput((event.target as HTMLInputElement).value)}
|
|
194
203
|
/>
|
|
@@ -219,23 +228,31 @@
|
|
|
219
228
|
</Select>
|
|
220
229
|
{/snippet}
|
|
221
230
|
|
|
222
|
-
{#if
|
|
231
|
+
{#if entity}
|
|
232
|
+
{@const ParentFrame = showEditFrameOptions ? DropDownField : ImmutableField}
|
|
233
|
+
{@const ScalarAttribute = showEditFrameOptions ? MutableField : ImmutableField}
|
|
234
|
+
|
|
223
235
|
<div
|
|
224
|
-
class="border-medium bg-extralight absolute top-0 right-0 z-
|
|
236
|
+
class="border-medium bg-extralight absolute top-0 right-0 z-10 m-2 {showEditFrameOptions
|
|
225
237
|
? 'w-80'
|
|
226
238
|
: 'w-60'} border p-2 text-xs"
|
|
227
|
-
|
|
239
|
+
use:draggable={{
|
|
240
|
+
bounds: 'body',
|
|
241
|
+
handle: dragElement,
|
|
242
|
+
defaultPosition: dragPosition.current,
|
|
243
|
+
onDragEnd(data) {
|
|
244
|
+
dragPosition.current = { x: data.offsetX, y: data.offsetY }
|
|
245
|
+
},
|
|
246
|
+
}}
|
|
228
247
|
{...rest}
|
|
229
248
|
>
|
|
230
249
|
<div class="flex items-center justify-between gap-2 pb-2">
|
|
231
250
|
<div class="flex items-center gap-1">
|
|
232
|
-
<button
|
|
233
|
-
onmousedown={draggable.onDragStart}
|
|
234
|
-
onmouseup={draggable.onDragEnd}
|
|
235
|
-
>
|
|
251
|
+
<button bind:this={dragElement}>
|
|
236
252
|
<Icon name="drag" />
|
|
237
253
|
</button>
|
|
238
|
-
{
|
|
254
|
+
<strong>{name.current}</strong>
|
|
255
|
+
<span class="text-subtle-2">{resourceName?.subtype}</span>
|
|
239
256
|
</div>
|
|
240
257
|
</div>
|
|
241
258
|
|
|
@@ -263,302 +280,284 @@
|
|
|
263
280
|
</h3>
|
|
264
281
|
|
|
265
282
|
<div class="flex flex-col gap-2.5">
|
|
266
|
-
|
|
267
|
-
<
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
<div
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
<
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
<
|
|
281
|
-
|
|
282
|
-
{worldPosition.z.toFixed(2)}
|
|
283
|
-
</div>
|
|
283
|
+
<div>
|
|
284
|
+
<strong class="font-semibold">world position</strong>
|
|
285
|
+
<span class="text-subtle-2">(mm)</span>
|
|
286
|
+
|
|
287
|
+
<div class="flex gap-3">
|
|
288
|
+
<div>
|
|
289
|
+
<span class="text-subtle-2">x</span>
|
|
290
|
+
{(worldPosition.x * 1000).toFixed(2)}
|
|
291
|
+
</div>
|
|
292
|
+
<div>
|
|
293
|
+
<span class="text-subtle-2">y</span>
|
|
294
|
+
{(worldPosition.y * 1000).toFixed(2)}
|
|
295
|
+
</div>
|
|
296
|
+
<div>
|
|
297
|
+
<span class="text-subtle-2">z</span>
|
|
298
|
+
{(worldPosition.z * 1000).toFixed(2)}
|
|
284
299
|
</div>
|
|
285
300
|
</div>
|
|
286
|
-
|
|
301
|
+
</div>
|
|
287
302
|
|
|
288
|
-
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
<div
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
<
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
{MathUtils.radToDeg(worldOrientation.th).toFixed(2)}
|
|
308
|
-
</div>
|
|
303
|
+
<div>
|
|
304
|
+
<strong class="font-semibold">world orientation</strong>
|
|
305
|
+
<span class="text-subtle-2">(deg)</span>
|
|
306
|
+
<div class="flex gap-3">
|
|
307
|
+
<div>
|
|
308
|
+
<span class="text-subtle-2">x</span>
|
|
309
|
+
{worldOrientation.x.toFixed(2)}
|
|
310
|
+
</div>
|
|
311
|
+
<div>
|
|
312
|
+
<span class="text-subtle-2">y</span>
|
|
313
|
+
{worldOrientation.y.toFixed(2)}
|
|
314
|
+
</div>
|
|
315
|
+
<div>
|
|
316
|
+
<span class="text-subtle-2">z</span>
|
|
317
|
+
{worldOrientation.z.toFixed(2)}
|
|
318
|
+
</div>
|
|
319
|
+
<div>
|
|
320
|
+
<span class="text-subtle-2">th</span>
|
|
321
|
+
{MathUtils.radToDeg(worldOrientation.th).toFixed(2)}
|
|
309
322
|
</div>
|
|
310
323
|
</div>
|
|
311
|
-
|
|
324
|
+
</div>
|
|
312
325
|
|
|
313
|
-
<
|
|
314
|
-
|
|
326
|
+
<div>
|
|
327
|
+
<strong class="font-semibold">parent frame</strong>
|
|
328
|
+
<div class="mt-0.5 flex gap-3">
|
|
329
|
+
{@render ParentFrame({
|
|
330
|
+
ariaLabel: 'parent frame name',
|
|
331
|
+
value: parent.current ?? 'world',
|
|
332
|
+
options: frames.getParentFrameOptions(name.current ?? ''),
|
|
333
|
+
onChange: (value) => {
|
|
334
|
+
detailConfigUpdater.setFrameParent(entity, value)
|
|
335
|
+
},
|
|
336
|
+
})}
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
315
339
|
|
|
340
|
+
{#if localPose.current}
|
|
316
341
|
<div>
|
|
317
|
-
<strong class="font-semibold">
|
|
318
|
-
<
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
342
|
+
<strong class="font-semibold">local position</strong>
|
|
343
|
+
<span class="text-subtle-2">(mm)</span>
|
|
344
|
+
|
|
345
|
+
<div class="mt-0.5 flex gap-3">
|
|
346
|
+
{@render ScalarAttribute({
|
|
347
|
+
label: 'x',
|
|
348
|
+
ariaLabel: 'local position x coordinate',
|
|
349
|
+
value: localPose.current.x,
|
|
350
|
+
onInput: (value) => {
|
|
351
|
+
if (isIntermediateInput(value)) return
|
|
352
|
+
detailConfigUpdater.updateLocalPosition(entity, { x: Number.parseFloat(value) })
|
|
353
|
+
},
|
|
354
|
+
})}
|
|
355
|
+
{@render ScalarAttribute({
|
|
356
|
+
label: 'y',
|
|
357
|
+
ariaLabel: 'local position y coordinate',
|
|
358
|
+
value: localPose.current.y,
|
|
359
|
+
onInput: (value) => {
|
|
360
|
+
if (isIntermediateInput(value)) return
|
|
361
|
+
detailConfigUpdater.updateLocalPosition(entity, { y: Number.parseFloat(value) })
|
|
362
|
+
},
|
|
363
|
+
})}
|
|
364
|
+
{@render ScalarAttribute({
|
|
365
|
+
label: 'z',
|
|
366
|
+
ariaLabel: 'local position z coordinate',
|
|
367
|
+
value: localPose.current.z,
|
|
368
|
+
onInput: (value) => {
|
|
369
|
+
if (isIntermediateInput(value)) return
|
|
370
|
+
detailConfigUpdater.updateLocalPosition(entity, { z: Number.parseFloat(value) })
|
|
371
|
+
},
|
|
324
372
|
})}
|
|
325
373
|
</div>
|
|
326
374
|
</div>
|
|
327
375
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
<
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
376
|
+
<div>
|
|
377
|
+
<strong class="font-semibold">local orientation</strong>
|
|
378
|
+
<span class="text-subtle-2">(deg)</span>
|
|
379
|
+
<div class="flex {showEditFrameOptions ? 'gap-2' : 'gap-3'} mt-0.5">
|
|
380
|
+
{@render ScalarAttribute({
|
|
381
|
+
label: 'x',
|
|
382
|
+
ariaLabel: 'local orientation x coordinate',
|
|
383
|
+
value: localPose.current?.oX,
|
|
384
|
+
onInput: (value) => {
|
|
385
|
+
if (isIntermediateInput(value)) return
|
|
386
|
+
detailConfigUpdater.updateLocalOrientation(entity, { oX: Number.parseFloat(value) })
|
|
387
|
+
},
|
|
388
|
+
})}
|
|
389
|
+
{@render ScalarAttribute({
|
|
390
|
+
label: 'y',
|
|
391
|
+
ariaLabel: 'local orientation y coordinate',
|
|
392
|
+
value: localPose.current?.oY,
|
|
393
|
+
onInput: (value) => {
|
|
394
|
+
if (isIntermediateInput(value)) return
|
|
395
|
+
detailConfigUpdater.updateLocalOrientation(entity, { oY: Number.parseFloat(value) })
|
|
396
|
+
},
|
|
397
|
+
})}
|
|
398
|
+
{@render ScalarAttribute({
|
|
399
|
+
label: 'z',
|
|
400
|
+
ariaLabel: 'local orientation z coordinate',
|
|
401
|
+
value: localPose.current?.oZ,
|
|
402
|
+
onInput: (value) => {
|
|
403
|
+
if (isIntermediateInput(value)) return
|
|
404
|
+
detailConfigUpdater.updateLocalOrientation(entity, { oZ: Number.parseFloat(value) })
|
|
405
|
+
},
|
|
406
|
+
})}
|
|
407
|
+
{@render ScalarAttribute({
|
|
408
|
+
label: 'th',
|
|
409
|
+
ariaLabel: 'local orientation theta degrees',
|
|
410
|
+
value: localPose.current?.theta,
|
|
411
|
+
onInput: (value) => {
|
|
412
|
+
if (isIntermediateInput(value)) return
|
|
413
|
+
detailConfigUpdater.updateLocalOrientation(entity, {
|
|
414
|
+
theta: Number.parseFloat(value),
|
|
415
|
+
})
|
|
416
|
+
},
|
|
417
|
+
})}
|
|
357
418
|
</div>
|
|
419
|
+
</div>
|
|
420
|
+
{/if}
|
|
358
421
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
</div>
|
|
422
|
+
{#if showEditFrameOptions}
|
|
423
|
+
<div>
|
|
424
|
+
<strong class="font-semibold">geometry</strong>
|
|
425
|
+
<div class="mt-0.5 grid grid-cols-4 gap-1">
|
|
426
|
+
<Button
|
|
427
|
+
variant={geometryType === 'none' ? 'dark' : 'primary'}
|
|
428
|
+
class="h-6 px-2 py-1 text-xs"
|
|
429
|
+
onclick={() => setGeometryType('none')}
|
|
430
|
+
>
|
|
431
|
+
None
|
|
432
|
+
</Button>
|
|
433
|
+
<Button
|
|
434
|
+
variant={geometryType === 'box' ? 'dark' : 'primary'}
|
|
435
|
+
class="h-6 px-2 py-1 text-xs"
|
|
436
|
+
onclick={() => setGeometryType('box')}
|
|
437
|
+
>
|
|
438
|
+
Box
|
|
439
|
+
</Button>
|
|
440
|
+
<Button
|
|
441
|
+
variant={geometryType === 'sphere' ? 'dark' : 'primary'}
|
|
442
|
+
class="h-6 px-2 py-1 text-xs"
|
|
443
|
+
onclick={() => setGeometryType('sphere')}
|
|
444
|
+
>
|
|
445
|
+
Sphere
|
|
446
|
+
</Button>
|
|
447
|
+
<Button
|
|
448
|
+
variant={geometryType === 'capsule' ? 'dark' : 'primary'}
|
|
449
|
+
class="h-6 px-2 py-1 text-xs"
|
|
450
|
+
onclick={() => setGeometryType('capsule')}
|
|
451
|
+
>
|
|
452
|
+
Capsule
|
|
453
|
+
</Button>
|
|
392
454
|
</div>
|
|
393
|
-
|
|
455
|
+
</div>
|
|
456
|
+
{/if}
|
|
394
457
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
458
|
+
{#if box.current}
|
|
459
|
+
<div>
|
|
460
|
+
<strong class="font-semibold"> dimensions </strong>
|
|
461
|
+
<span class="text-subtle-2">(box) (mm)</span>
|
|
462
|
+
<div class="mt-0.5 flex items-center gap-2">
|
|
463
|
+
{@render ScalarAttribute({
|
|
464
|
+
label: 'x',
|
|
465
|
+
ariaLabel: 'box dimensions x value input',
|
|
466
|
+
value: box.current.x,
|
|
467
|
+
onInput: (value) => {
|
|
468
|
+
if (isIntermediateInput(value)) return
|
|
469
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
470
|
+
type: 'box',
|
|
471
|
+
x: Number.parseFloat(value),
|
|
472
|
+
})
|
|
473
|
+
},
|
|
474
|
+
})}
|
|
475
|
+
{@render ScalarAttribute({
|
|
476
|
+
label: 'y',
|
|
477
|
+
ariaLabel: 'box dimensions y value input',
|
|
478
|
+
value: box.current.y,
|
|
479
|
+
onInput: (value) => {
|
|
480
|
+
if (isIntermediateInput(value)) return
|
|
481
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
482
|
+
type: 'box',
|
|
483
|
+
y: Number.parseFloat(value),
|
|
484
|
+
})
|
|
485
|
+
},
|
|
486
|
+
})}
|
|
487
|
+
{@render ScalarAttribute({
|
|
488
|
+
label: 'z',
|
|
489
|
+
ariaLabel: 'box dimensions z value input',
|
|
490
|
+
value: box.current.z,
|
|
491
|
+
onInput: (value) => {
|
|
492
|
+
if (isIntermediateInput(value)) return
|
|
493
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
494
|
+
type: 'box',
|
|
495
|
+
z: Number.parseFloat(value),
|
|
496
|
+
})
|
|
497
|
+
},
|
|
498
|
+
})}
|
|
420
499
|
</div>
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
ariaLabel: 'capsule dimensions length value input',
|
|
473
|
-
value: lengthMm ? lengthMm.toFixed(2) : '-',
|
|
474
|
-
onInput: (value) =>
|
|
475
|
-
detailConfigUpdater.updateGeometry({ type: 'capsule', l: parseFloat(value) }),
|
|
476
|
-
})}
|
|
477
|
-
</div>
|
|
478
|
-
</div>
|
|
479
|
-
{/if}
|
|
480
|
-
{#if geometryType === 'sphere'}
|
|
481
|
-
{@const { radiusMm } = object?.geometry?.geometryType.value as { radiusMm: number }}
|
|
482
|
-
<div>
|
|
483
|
-
<strong class="font-semibold">dimensions (sphere)</strong>
|
|
484
|
-
<div class="flex items-center gap-2">
|
|
485
|
-
{@render GeometryAttribute({
|
|
486
|
-
label: 'r',
|
|
487
|
-
ariaLabel: 'sphere dimensions radius value',
|
|
488
|
-
value: radiusMm ? radiusMm.toFixed(2) : '-',
|
|
489
|
-
onInput: (value) =>
|
|
490
|
-
detailConfigUpdater.updateGeometry({ type: 'sphere', r: parseFloat(value) }),
|
|
491
|
-
})}
|
|
492
|
-
</div>
|
|
493
|
-
</div>
|
|
494
|
-
{/if}
|
|
495
|
-
{/if}
|
|
496
|
-
</WeblabActive>
|
|
497
|
-
|
|
498
|
-
<WeblabActive
|
|
499
|
-
experiment={WEBLABS_EXPERIMENTS.MOTION_TOOLS_EDIT_FRAME}
|
|
500
|
-
renderIfActive={false}
|
|
501
|
-
>
|
|
502
|
-
{#if object.geometry}
|
|
503
|
-
{#if object.geometry.geometryType.case === 'box'}
|
|
504
|
-
{@const { dimsMm } = object.geometry.geometryType.value}
|
|
505
|
-
<div>
|
|
506
|
-
<strong class="font-semibold">dimensions (box)</strong>
|
|
507
|
-
<div class="flex gap-3">
|
|
508
|
-
<div>
|
|
509
|
-
<span class="text-subtle-2">x</span>
|
|
510
|
-
{dimsMm?.x ? dimsMm.x.toFixed(2) : '-'}
|
|
511
|
-
</div>
|
|
512
|
-
<div>
|
|
513
|
-
<span class="text-subtle-2">y</span>
|
|
514
|
-
{dimsMm?.y ? dimsMm.y.toFixed(2) : '-'}
|
|
515
|
-
</div>
|
|
516
|
-
<div>
|
|
517
|
-
<span class="text-subtle-2">z</span>
|
|
518
|
-
{dimsMm?.z ? dimsMm.z.toFixed(2) : '-'}
|
|
519
|
-
</div>
|
|
520
|
-
</div>
|
|
521
|
-
</div>
|
|
522
|
-
{:else if object.geometry.geometryType.case === 'capsule'}
|
|
523
|
-
{@const { value } = object.geometry.geometryType}
|
|
524
|
-
<div>
|
|
525
|
-
<strong class="font-semibold">dimensions (capsule)</strong>
|
|
526
|
-
<div class="flex gap-3">
|
|
527
|
-
<div>
|
|
528
|
-
<span class="text-subtle-2">r</span>
|
|
529
|
-
{value.radiusMm ? value.radiusMm.toFixed(2) : '-'}
|
|
530
|
-
</div>
|
|
531
|
-
<div>
|
|
532
|
-
<span class="text-subtle-2">l</span>
|
|
533
|
-
{value.lengthMm ? value.lengthMm.toFixed(2) : '-'}
|
|
534
|
-
</div>
|
|
535
|
-
</div>
|
|
536
|
-
</div>
|
|
537
|
-
{:else if object.geometry.geometryType.case === 'sphere'}
|
|
538
|
-
<div class="flex justify-between">
|
|
539
|
-
<div>
|
|
540
|
-
<strong class="font-semibold">dimensions (sphere)</strong>
|
|
541
|
-
<div class="flex gap-3">
|
|
542
|
-
<div>
|
|
543
|
-
<span class="text-subtle-2">r</span>
|
|
544
|
-
{object.geometry.geometryType.value.radiusMm.toFixed(2)}
|
|
545
|
-
</div>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
</div>
|
|
549
|
-
{/if}
|
|
550
|
-
{/if}
|
|
551
|
-
</WeblabActive>
|
|
500
|
+
</div>
|
|
501
|
+
{:else if capsule.current}
|
|
502
|
+
<div>
|
|
503
|
+
<strong class="font-semibold">dimensions</strong>
|
|
504
|
+
<span class="text-subtle-2">(capsule) (mm)</span>
|
|
505
|
+
<div class="mt-0.5 flex items-center gap-2">
|
|
506
|
+
{@render ScalarAttribute({
|
|
507
|
+
label: 'r',
|
|
508
|
+
ariaLabel: 'capsule dimensions radius value input',
|
|
509
|
+
value: capsule.current.r,
|
|
510
|
+
onInput: (value) => {
|
|
511
|
+
if (isIntermediateInput(value)) return
|
|
512
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
513
|
+
type: 'capsule',
|
|
514
|
+
r: Number.parseFloat(value),
|
|
515
|
+
})
|
|
516
|
+
},
|
|
517
|
+
})}
|
|
518
|
+
{@render ScalarAttribute({
|
|
519
|
+
label: 'l',
|
|
520
|
+
ariaLabel: 'capsule dimensions length value input',
|
|
521
|
+
value: capsule.current.l,
|
|
522
|
+
onInput: (value) => {
|
|
523
|
+
if (isIntermediateInput(value)) return
|
|
524
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
525
|
+
type: 'capsule',
|
|
526
|
+
l: Number.parseFloat(value),
|
|
527
|
+
})
|
|
528
|
+
},
|
|
529
|
+
})}
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
{:else if sphere.current}
|
|
533
|
+
<div>
|
|
534
|
+
<strong class="font-semibold">dimensions (sphere)</strong>
|
|
535
|
+
<div class="flex items-center gap-2">
|
|
536
|
+
{@render ScalarAttribute({
|
|
537
|
+
label: 'r',
|
|
538
|
+
ariaLabel: 'sphere dimensions radius value',
|
|
539
|
+
value: sphere.current.r,
|
|
540
|
+
onInput: (value) => {
|
|
541
|
+
if (isIntermediateInput(value)) return
|
|
542
|
+
detailConfigUpdater.updateGeometry(entity, {
|
|
543
|
+
type: 'sphere',
|
|
544
|
+
r: Number.parseFloat(value),
|
|
545
|
+
})
|
|
546
|
+
},
|
|
547
|
+
})}
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
{/if}
|
|
552
551
|
</div>
|
|
553
552
|
|
|
554
553
|
<h3 class="text-subtle-2 pt-3 pb-2">Actions</h3>
|
|
555
554
|
|
|
556
|
-
{#if
|
|
555
|
+
{#if focusedEntity.current}
|
|
557
556
|
<Button
|
|
558
557
|
class="w-full"
|
|
559
558
|
icon="arrow-left"
|
|
560
559
|
variant="dark"
|
|
561
|
-
onclick={() =>
|
|
560
|
+
onclick={() => focusedEntity.set()}
|
|
562
561
|
>
|
|
563
562
|
Exit object view
|
|
564
563
|
</Button>
|
|
@@ -566,20 +565,20 @@
|
|
|
566
565
|
<Button
|
|
567
566
|
class="w-full"
|
|
568
567
|
icon="image-filter-center-focus"
|
|
569
|
-
onclick={() =>
|
|
568
|
+
onclick={() => focusedEntity.set(entity)}
|
|
570
569
|
>
|
|
571
570
|
Enter object view
|
|
572
571
|
</Button>
|
|
573
572
|
{/if}
|
|
574
573
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
574
|
+
{#if showEditFrameOptions && environment.current.isStandalone}
|
|
575
|
+
<Button
|
|
576
|
+
variant="danger"
|
|
577
|
+
class="mt-2 w-full"
|
|
578
|
+
onclick={() => detailConfigUpdater.deleteFrame(entity)}
|
|
579
|
+
>
|
|
580
|
+
Delete frame
|
|
581
|
+
</Button>
|
|
582
|
+
{/if}
|
|
584
583
|
</div>
|
|
585
584
|
{/if}
|