@viamrobotics/motion-tools 1.26.2 → 1.27.1
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/assert.d.ts +13 -0
- package/dist/assert.js +20 -0
- package/dist/components/App.svelte +11 -5
- package/dist/components/BatchedArrows.svelte +20 -38
- package/dist/components/Entities/Arrows/Arrows.svelte +35 -29
- package/dist/components/Entities/Frame.svelte +18 -35
- package/dist/components/Entities/GLTF.svelte +25 -35
- package/dist/components/Entities/Geometry.svelte +35 -24
- package/dist/components/Entities/Line.svelte +35 -42
- package/dist/components/Entities/Points.svelte +23 -27
- package/dist/components/Scene.svelte +7 -1
- package/dist/components/overlay/Details.svelte +0 -7
- package/dist/draw.js +3 -2
- package/dist/ecs/traits.d.ts +0 -5
- package/dist/ecs/traits.js +2 -1
- package/dist/ecs/worldMatrix.d.ts +2 -2
- package/dist/ecs/worldMatrix.js +4 -14
- package/dist/hooks/useDrawService.svelte.js +4 -7
- package/dist/hooks/useGeometries.svelte.js +16 -6
- package/dist/hooks/usePartConfig.svelte.js +5 -3
- package/dist/plugins/bvh.svelte.js +37 -26
- package/dist/three/OBBHelper.js +4 -1
- package/dist/three/arrow.js +2 -0
- package/package.json +2 -2
package/dist/assert.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class AssertionError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Assert that a value is defined.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const stringify = (value: number | undefined): number => {
|
|
9
|
+
* assertExists(value)
|
|
10
|
+
* return `${value}` // TS now knows that value is of type `number`
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
export declare const assertExists: <T>(value: T, message: string) => asserts value is NonNullable<T>;
|
package/dist/assert.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class AssertionError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'AssertionError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Assert that a value is defined.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const stringify = (value: number | undefined): number => {
|
|
12
|
+
* assertExists(value)
|
|
13
|
+
* return `${value}` // TS now knows that value is of type `number`
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
export const assertExists = (value, message) => {
|
|
17
|
+
if (value === null || value === undefined) {
|
|
18
|
+
throw new AssertionError(message);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { PortalTarget } from '@threlte/extras'
|
|
9
9
|
import { useXR } from '@threlte/xr'
|
|
10
10
|
import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
|
|
11
|
+
import { ThemeUtils } from 'svelte-tweakpane-ui'
|
|
11
12
|
|
|
12
13
|
import type { CameraPose } from '../hooks/useControls.svelte'
|
|
13
14
|
|
|
@@ -90,10 +91,6 @@
|
|
|
90
91
|
const currentRobotCameraWidgets = $derived(settings.current.openCameraWidgets[partID] || [])
|
|
91
92
|
const { isPresenting } = useXR()
|
|
92
93
|
|
|
93
|
-
$effect(() => {
|
|
94
|
-
environment.current.inputBindingsEnabled = inputBindingsEnabled
|
|
95
|
-
})
|
|
96
|
-
|
|
97
94
|
createPartIDContext(() => partID)
|
|
98
95
|
provideDrawConnectionConfig(() => drawConnectionConfig)
|
|
99
96
|
provideWeblabs()
|
|
@@ -106,9 +103,18 @@
|
|
|
106
103
|
() => localConfigProps
|
|
107
104
|
)
|
|
108
105
|
|
|
109
|
-
$effect
|
|
106
|
+
$effect(() => {
|
|
107
|
+
environment.current.inputBindingsEnabled = inputBindingsEnabled
|
|
110
108
|
environment.current.isStandalone = !localConfigProps
|
|
111
109
|
})
|
|
110
|
+
|
|
111
|
+
$effect(() => {
|
|
112
|
+
ThemeUtils.setGlobalDefaultTheme({
|
|
113
|
+
...ThemeUtils.presets.light,
|
|
114
|
+
baseBackgroundColor: '#fbfbfc',
|
|
115
|
+
baseShadowColor: 'transparent',
|
|
116
|
+
})
|
|
117
|
+
})
|
|
112
118
|
</script>
|
|
113
119
|
|
|
114
120
|
{#if settings.current.enableQueryDevtools}
|
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
import type { Entity } from 'koota'
|
|
3
3
|
|
|
4
4
|
import { T } from '@threlte/core'
|
|
5
|
-
import { Portal } from '@threlte/extras'
|
|
6
5
|
import { Color, Quaternion, Vector3 } from 'three'
|
|
7
6
|
|
|
8
|
-
import {
|
|
7
|
+
import { traits, useWorld } from '../ecs'
|
|
9
8
|
import { BatchedArrow } from '../three/BatchedArrow'
|
|
10
9
|
import { OrientationVector } from '../three/OrientationVector'
|
|
11
10
|
|
|
12
|
-
const
|
|
13
|
-
world: new BatchedArrow(),
|
|
14
|
-
})
|
|
15
|
-
const batchEntries = $derived(Object.entries(arrowBatchMap))
|
|
11
|
+
const batched = new BatchedArrow()
|
|
16
12
|
|
|
17
13
|
const world = useWorld()
|
|
18
14
|
|
|
@@ -24,24 +20,19 @@
|
|
|
24
20
|
const tempOv = new OrientationVector()
|
|
25
21
|
|
|
26
22
|
/**
|
|
27
|
-
* Decompose the
|
|
28
|
-
* (OV components from the rotation)
|
|
23
|
+
* Decompose the entity's `WorldMatrix` directly into the arrow's world
|
|
24
|
+
* origin (translation) and direction (OV components from the rotation).
|
|
29
25
|
*/
|
|
30
26
|
const decompose = (entity: Entity): boolean => {
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
33
|
-
|
|
27
|
+
const worldMatrix = entity.get(traits.WorldMatrix)
|
|
28
|
+
if (!worldMatrix) return false
|
|
29
|
+
worldMatrix.decompose(origin, tempQuat, tempScale)
|
|
34
30
|
tempOv.setFromQuaternion(tempQuat)
|
|
35
31
|
direction.set(tempOv.x, tempOv.y, tempOv.z)
|
|
36
32
|
return true
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
const onAdd = (entity: Entity) => {
|
|
40
|
-
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
41
|
-
|
|
42
|
-
arrowBatchMap[parent] ??= new BatchedArrow()
|
|
43
|
-
const batched = arrowBatchMap[parent]
|
|
44
|
-
|
|
45
36
|
const colorRGB = entity.get(traits.Color)
|
|
46
37
|
|
|
47
38
|
if (!decompose(entity)) {
|
|
@@ -58,63 +49,54 @@
|
|
|
58
49
|
entity.add(traits.Instance({ instanceID, meshID: batched.mesh.id }))
|
|
59
50
|
}
|
|
60
51
|
|
|
61
|
-
const
|
|
52
|
+
const onWorldMatrixChange = (entity: Entity) => {
|
|
62
53
|
if (!entity.has(traits.Arrow)) return
|
|
63
54
|
|
|
64
|
-
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
65
|
-
const batch = arrowBatchMap[parent]
|
|
66
55
|
const instanceID = entity.get(traits.Instance)?.instanceID
|
|
67
56
|
|
|
68
57
|
if (instanceID && instanceID !== -1 && decompose(entity)) {
|
|
69
|
-
|
|
58
|
+
batched.updateArrow(instanceID, direction, origin)
|
|
70
59
|
}
|
|
71
60
|
}
|
|
72
61
|
|
|
73
62
|
const onColorChange = (entity: Entity) => {
|
|
74
63
|
if (!entity.has(traits.Arrow)) return
|
|
75
64
|
|
|
76
|
-
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
77
|
-
const batch = arrowBatchMap[parent]
|
|
78
65
|
const instanceID = entity.get(traits.Instance)?.instanceID
|
|
79
66
|
const colorRGB = entity.get(traits.Color)
|
|
80
67
|
|
|
81
68
|
if (instanceID && instanceID !== -1 && colorRGB) {
|
|
82
69
|
color.set(colorRGB.r, colorRGB.g, colorRGB.b)
|
|
83
|
-
|
|
70
|
+
batched.mesh.setColorAt(instanceID, color)
|
|
84
71
|
}
|
|
85
72
|
}
|
|
86
73
|
|
|
87
74
|
const onInstanceRemove = (entity: Entity) => {
|
|
88
75
|
const instance = entity.get(traits.Instance)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (batch.mesh.id === instance?.meshID) {
|
|
92
|
-
batch.removeArrow(instance.instanceID)
|
|
93
|
-
}
|
|
76
|
+
if (instance && instance.meshID === batched.mesh.id) {
|
|
77
|
+
batched.removeArrow(instance.instanceID)
|
|
94
78
|
}
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
$effect(() => {
|
|
98
82
|
const unsubAdd = world.onAdd(traits.Arrow, onAdd)
|
|
99
83
|
const unsubRemove = world.onRemove(traits.Instance, onInstanceRemove)
|
|
100
|
-
const
|
|
84
|
+
const unsubMatrixAdd = world.onAdd(traits.WorldMatrix, onWorldMatrixChange)
|
|
85
|
+
const unsubMatrixChange = world.onChange(traits.WorldMatrix, onWorldMatrixChange)
|
|
101
86
|
const unsubColorChange = world.onChange(traits.Color, onColorChange)
|
|
102
87
|
|
|
103
88
|
return () => {
|
|
104
89
|
unsubAdd()
|
|
105
90
|
unsubRemove()
|
|
91
|
+
unsubMatrixAdd()
|
|
106
92
|
unsubMatrixChange()
|
|
107
93
|
unsubColorChange()
|
|
108
94
|
}
|
|
109
95
|
})
|
|
110
96
|
</script>
|
|
111
97
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
bvh={{ enabled: false }}
|
|
118
|
-
/>
|
|
119
|
-
</Portal>
|
|
120
|
-
{/each}
|
|
98
|
+
<T
|
|
99
|
+
is={batched.mesh}
|
|
100
|
+
dispose={false}
|
|
101
|
+
bvh={{ enabled: false }}
|
|
102
|
+
/>
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Entity } from 'koota'
|
|
3
3
|
|
|
4
|
-
import { T } from '@threlte/core'
|
|
5
|
-
import { Portal } from '@threlte/extras'
|
|
4
|
+
import { T, useThrelte } from '@threlte/core'
|
|
6
5
|
|
|
7
6
|
import type { InstancedArrows } from '../../../three/InstancedArrows/InstancedArrows'
|
|
8
7
|
|
|
9
8
|
import AxesHelper from '../../AxesHelper.svelte'
|
|
10
9
|
import { useEntityEvents } from '../hooks/useEntityEvents.svelte'
|
|
11
|
-
import { traits,
|
|
10
|
+
import { traits, useTrait } from '../../../ecs'
|
|
12
11
|
import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte'
|
|
13
12
|
import { meshBoundsRaycast, raycast } from '../../../three/InstancedArrows/raycast'
|
|
14
13
|
|
|
@@ -19,7 +18,8 @@
|
|
|
19
18
|
|
|
20
19
|
let { entity, arrows }: Props = $props()
|
|
21
20
|
|
|
22
|
-
const
|
|
21
|
+
const { invalidate } = useThrelte()
|
|
22
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
23
23
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
24
24
|
const showAxesHelper = useTrait(() => entity, traits.ShowAxesHelper)
|
|
25
25
|
|
|
@@ -35,32 +35,38 @@
|
|
|
35
35
|
}
|
|
36
36
|
return meshBoundsRaycast
|
|
37
37
|
})
|
|
38
|
+
|
|
39
|
+
$effect.pre(() => {
|
|
40
|
+
arrows.matrixAutoUpdate = false
|
|
41
|
+
if (!worldMatrix.current) return
|
|
42
|
+
arrows.matrix.copy(worldMatrix.current)
|
|
43
|
+
arrows.updateMatrixWorld()
|
|
44
|
+
invalidate()
|
|
45
|
+
})
|
|
38
46
|
</script>
|
|
39
47
|
|
|
40
|
-
<
|
|
48
|
+
<T
|
|
49
|
+
is={arrows}
|
|
50
|
+
name={entity}
|
|
51
|
+
{...events}
|
|
52
|
+
raycast={raycastFunction}
|
|
53
|
+
visible={invisible.current !== true}
|
|
54
|
+
>
|
|
41
55
|
<T
|
|
42
|
-
is={arrows}
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
raycast={() => null}
|
|
56
|
+
is={arrows.headMesh}
|
|
57
|
+
bvh={{ enabled: false }}
|
|
58
|
+
raycast={() => null}
|
|
59
|
+
/>
|
|
60
|
+
<T
|
|
61
|
+
is={arrows.shaftMesh}
|
|
62
|
+
bvh={{ enabled: false }}
|
|
63
|
+
raycast={() => null}
|
|
64
|
+
/>
|
|
65
|
+
{#if showAxesHelper.current}
|
|
66
|
+
<AxesHelper
|
|
67
|
+
name={entity}
|
|
68
|
+
width={3}
|
|
69
|
+
length={0.1}
|
|
57
70
|
/>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
name={entity}
|
|
61
|
-
width={3}
|
|
62
|
-
length={0.1}
|
|
63
|
-
/>
|
|
64
|
-
{/if}
|
|
65
|
-
</T>
|
|
66
|
-
</Portal>
|
|
71
|
+
{/if}
|
|
72
|
+
</T>
|
|
@@ -14,14 +14,12 @@ Renders a Viam Frame object
|
|
|
14
14
|
import type { Snippet } from 'svelte'
|
|
15
15
|
|
|
16
16
|
import { T, useThrelte } from '@threlte/core'
|
|
17
|
-
import { Portal, PortalTarget } from '@threlte/extras'
|
|
18
17
|
import { Group, type Object3D } from 'three'
|
|
19
18
|
|
|
20
19
|
import { asColor } from '../../buffer'
|
|
21
20
|
import { colors, resourceColors } from '../../color'
|
|
22
|
-
import { traits,
|
|
21
|
+
import { traits, useTrait } from '../../ecs'
|
|
23
22
|
import { useResourceByName } from '../../hooks/useResourceByName.svelte'
|
|
24
|
-
import { composeLocalMatrix } from '../../transform'
|
|
25
23
|
|
|
26
24
|
import { useEntityEvents } from './hooks/useEntityEvents.svelte'
|
|
27
25
|
import Mesh from './Mesh.svelte'
|
|
@@ -37,12 +35,9 @@ Renders a Viam Frame object
|
|
|
37
35
|
const resourceByName = useResourceByName()
|
|
38
36
|
|
|
39
37
|
const name = useTrait(() => entity, traits.Name)
|
|
40
|
-
const parent = useParentName(() => entity)
|
|
41
38
|
const entityColors = useTrait(() => entity, traits.Colors)
|
|
42
39
|
const entityColor = useTrait(() => entity, traits.Color)
|
|
43
|
-
const
|
|
44
|
-
const editedMatrix = useTrait(() => entity, traits.EditedMatrix)
|
|
45
|
-
const liveMatrix = useTrait(() => entity, traits.LiveMatrix)
|
|
40
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
46
41
|
const center = useTrait(() => entity, traits.Center)
|
|
47
42
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
48
43
|
|
|
@@ -71,15 +66,9 @@ Renders a Viam Frame object
|
|
|
71
66
|
group.matrixAutoUpdate = false
|
|
72
67
|
|
|
73
68
|
$effect.pre(() => {
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
group.matrix.copy(editedMatrix.current)
|
|
78
|
-
} else if (matrix.current) {
|
|
79
|
-
group.matrix.copy(matrix.current)
|
|
80
|
-
} else {
|
|
81
|
-
return
|
|
82
|
-
}
|
|
69
|
+
if (!worldMatrix.current) return
|
|
70
|
+
|
|
71
|
+
group.matrix.copy(worldMatrix.current)
|
|
83
72
|
|
|
84
73
|
/**
|
|
85
74
|
* Keep position/quaternion/scale in sync with matrix so TransformControls
|
|
@@ -94,22 +83,16 @@ Renders a Viam Frame object
|
|
|
94
83
|
})
|
|
95
84
|
</script>
|
|
96
85
|
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<PortalTarget id={name.current} />
|
|
111
|
-
{/if}
|
|
112
|
-
|
|
113
|
-
{@render children?.({ ref: group })}
|
|
114
|
-
</T>
|
|
115
|
-
</Portal>
|
|
86
|
+
<T
|
|
87
|
+
is={group}
|
|
88
|
+
visible={invisible.current !== true}
|
|
89
|
+
>
|
|
90
|
+
<Mesh
|
|
91
|
+
{entity}
|
|
92
|
+
{color}
|
|
93
|
+
{...events}
|
|
94
|
+
center={center.current}
|
|
95
|
+
/>
|
|
96
|
+
|
|
97
|
+
{@render children?.({ ref: group })}
|
|
98
|
+
</T>
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
import type { Snippet } from 'svelte'
|
|
17
17
|
|
|
18
18
|
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
19
|
-
import {
|
|
19
|
+
import { type ThrelteGltf, useGltfAnimations } from '@threlte/extras'
|
|
20
20
|
import { Group, type Object3D } from 'three'
|
|
21
21
|
|
|
22
|
-
import { traits,
|
|
22
|
+
import { traits, useTrait } from '../../ecs'
|
|
23
23
|
|
|
24
24
|
import AxesHelper from '../AxesHelper.svelte'
|
|
25
25
|
import { useEntityEvents } from './hooks/useEntityEvents.svelte'
|
|
@@ -33,11 +33,8 @@
|
|
|
33
33
|
|
|
34
34
|
const { gltf, actions } = useGltfAnimations()
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
const parent = useParentName(() => entity)
|
|
38
|
-
const matrix = useTrait(() => entity, traits.Matrix)
|
|
36
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
39
37
|
const gltfTrait = useTrait(() => entity, traits.GLTF)
|
|
40
|
-
const scale = useTrait(() => entity, traits.Scale)
|
|
41
38
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
42
39
|
const showAxesHelper = useTrait(() => entity, traits.ShowAxesHelper)
|
|
43
40
|
const events = useEntityEvents(() => entity)
|
|
@@ -48,8 +45,8 @@
|
|
|
48
45
|
group.matrixAutoUpdate = false
|
|
49
46
|
|
|
50
47
|
$effect.pre(() => {
|
|
51
|
-
if (
|
|
52
|
-
group.matrix.copy(
|
|
48
|
+
if (worldMatrix.current) {
|
|
49
|
+
group.matrix.copy(worldMatrix.current)
|
|
53
50
|
group.updateMatrixWorld()
|
|
54
51
|
}
|
|
55
52
|
})
|
|
@@ -85,30 +82,23 @@
|
|
|
85
82
|
})
|
|
86
83
|
</script>
|
|
87
84
|
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
{#if name.current}
|
|
109
|
-
<PortalTarget id={name.current} />
|
|
110
|
-
{/if}
|
|
111
|
-
</T>
|
|
112
|
-
{/if}
|
|
113
|
-
</T>
|
|
114
|
-
</Portal>
|
|
85
|
+
<T is={group}>
|
|
86
|
+
{#if showAxesHelper.current}
|
|
87
|
+
<AxesHelper
|
|
88
|
+
name={entity}
|
|
89
|
+
width={3}
|
|
90
|
+
length={0.1}
|
|
91
|
+
/>
|
|
92
|
+
{/if}
|
|
93
|
+
{#if $gltf}
|
|
94
|
+
<T
|
|
95
|
+
is={$gltf.scene as Object3D}
|
|
96
|
+
name={entity}
|
|
97
|
+
visible={invisible.current !== true}
|
|
98
|
+
{...events}
|
|
99
|
+
{...rest}
|
|
100
|
+
>
|
|
101
|
+
{@render children?.()}
|
|
102
|
+
</T>
|
|
103
|
+
{/if}
|
|
104
|
+
</T>
|
|
@@ -8,9 +8,9 @@ Renders a Viam Geometry object
|
|
|
8
8
|
import type { Snippet } from 'svelte'
|
|
9
9
|
|
|
10
10
|
import { T, useThrelte } from '@threlte/core'
|
|
11
|
-
import {
|
|
11
|
+
import { Group } from 'three'
|
|
12
12
|
|
|
13
|
-
import { traits,
|
|
13
|
+
import { traits, useTrait } from '../../ecs'
|
|
14
14
|
import { use3DModels } from '../../hooks/use3DModels.svelte'
|
|
15
15
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
16
16
|
import { poseToObject3d } from '../../transform'
|
|
@@ -31,7 +31,7 @@ Renders a Viam Geometry object
|
|
|
31
31
|
const models = use3DModels()
|
|
32
32
|
|
|
33
33
|
const name = useTrait(() => entity, traits.Name)
|
|
34
|
-
const
|
|
34
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
35
35
|
const center = useTrait(() => entity, traits.Center)
|
|
36
36
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
37
37
|
|
|
@@ -52,6 +52,16 @@ Renders a Viam Geometry object
|
|
|
52
52
|
return models.current[componentName]?.[id]?.clone() ?? undefined
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
+
const group = new Group()
|
|
56
|
+
group.matrixAutoUpdate = false
|
|
57
|
+
|
|
58
|
+
$effect.pre(() => {
|
|
59
|
+
if (!worldMatrix.current) return
|
|
60
|
+
group.matrix.copy(worldMatrix.current)
|
|
61
|
+
group.updateMatrixWorld()
|
|
62
|
+
invalidate()
|
|
63
|
+
})
|
|
64
|
+
|
|
55
65
|
$effect.pre(() => {
|
|
56
66
|
if (model && center.current) {
|
|
57
67
|
poseToObject3d(center.current, model)
|
|
@@ -62,24 +72,25 @@ Renders a Viam Geometry object
|
|
|
62
72
|
const events = useEntityEvents(() => entity)
|
|
63
73
|
</script>
|
|
64
74
|
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
<T
|
|
76
|
+
is={group}
|
|
77
|
+
visible={invisible.current !== true}
|
|
78
|
+
>
|
|
79
|
+
{#if model}
|
|
80
|
+
<T
|
|
81
|
+
is={model}
|
|
82
|
+
name={entity}
|
|
83
|
+
{...events}
|
|
84
|
+
/>
|
|
85
|
+
{/if}
|
|
86
|
+
|
|
87
|
+
{#if settings.current.renderArmModels.includes('colliders') || !model}
|
|
88
|
+
<Mesh
|
|
89
|
+
{entity}
|
|
90
|
+
center={center.current}
|
|
91
|
+
{...events}
|
|
92
|
+
>
|
|
93
|
+
{@render children?.()}
|
|
94
|
+
</Mesh>
|
|
95
|
+
{/if}
|
|
96
|
+
</T>
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import type { Snippet } from 'svelte'
|
|
4
4
|
|
|
5
5
|
import { T, useThrelte } from '@threlte/core'
|
|
6
|
-
import { meshBounds
|
|
6
|
+
import { meshBounds } from '@threlte/extras'
|
|
7
7
|
import { Line2, LineMaterial } from 'three/examples/jsm/Addons.js'
|
|
8
8
|
|
|
9
9
|
import { isVertexColors, STRIDE } from '../../buffer'
|
|
10
|
-
import { traits,
|
|
10
|
+
import { traits, useTrait } from '../../ecs'
|
|
11
11
|
|
|
12
12
|
import AxesHelper from '../AxesHelper.svelte'
|
|
13
13
|
import { useEntityEvents } from './hooks/useEntityEvents.svelte'
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
const { invalidate } = useThrelte()
|
|
25
25
|
const name = useTrait(() => entity, traits.Name)
|
|
26
|
-
const
|
|
27
|
-
const matrix = useTrait(() => entity, traits.Matrix)
|
|
26
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
28
27
|
const color = useTrait(() => entity, traits.Color)
|
|
29
28
|
const colors = useTrait(() => entity, traits.Colors)
|
|
30
29
|
const dotColors = useTrait(() => entity, traits.DotColors)
|
|
@@ -65,47 +64,45 @@
|
|
|
65
64
|
mesh.matrixAutoUpdate = false
|
|
66
65
|
|
|
67
66
|
$effect.pre(() => {
|
|
68
|
-
if (
|
|
69
|
-
mesh.matrix.copy(
|
|
67
|
+
if (worldMatrix.current) {
|
|
68
|
+
mesh.matrix.copy(worldMatrix.current)
|
|
70
69
|
mesh.updateMatrixWorld()
|
|
71
70
|
invalidate()
|
|
72
71
|
}
|
|
73
72
|
})
|
|
74
73
|
</script>
|
|
75
74
|
|
|
76
|
-
<
|
|
75
|
+
<T
|
|
76
|
+
is={mesh}
|
|
77
|
+
name={entity}
|
|
78
|
+
userData.name={name}
|
|
79
|
+
raycast={meshBounds}
|
|
80
|
+
renderOrder={renderOrder.current}
|
|
81
|
+
visible={invisible.current !== true}
|
|
82
|
+
{...events}
|
|
83
|
+
>
|
|
84
|
+
<LineGeometry
|
|
85
|
+
positions={linePositions.current}
|
|
86
|
+
colors={lineColors}
|
|
87
|
+
/>
|
|
77
88
|
<T
|
|
78
|
-
is={
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
vertexColors={hasVertexColors}
|
|
94
|
-
transparent={currentOpacity < 1}
|
|
95
|
-
depthWrite={currentOpacity === 1}
|
|
96
|
-
opacity={currentOpacity}
|
|
97
|
-
worldUnits={!screenSpace.current}
|
|
98
|
-
linewidth={(lineWidth.current ?? 5) * (screenSpace.current ? 1 : 0.001)}
|
|
99
|
-
depthTest={materialProps.current?.depthTest ?? true}
|
|
89
|
+
is={LineMaterial}
|
|
90
|
+
color={hasVertexColors ? [1, 1, 1] : lineColor}
|
|
91
|
+
vertexColors={hasVertexColors}
|
|
92
|
+
transparent={currentOpacity < 1}
|
|
93
|
+
depthWrite={currentOpacity === 1}
|
|
94
|
+
opacity={currentOpacity}
|
|
95
|
+
worldUnits={!screenSpace.current}
|
|
96
|
+
linewidth={(lineWidth.current ?? 5) * (screenSpace.current ? 1 : 0.001)}
|
|
97
|
+
depthTest={materialProps.current?.depthTest ?? true}
|
|
98
|
+
/>
|
|
99
|
+
{#if showAxesHelper.current}
|
|
100
|
+
<AxesHelper
|
|
101
|
+
name={entity}
|
|
102
|
+
width={3}
|
|
103
|
+
length={0.1}
|
|
100
104
|
/>
|
|
101
|
-
|
|
102
|
-
<AxesHelper
|
|
103
|
-
name={entity}
|
|
104
|
-
width={3}
|
|
105
|
-
length={0.1}
|
|
106
|
-
/>
|
|
107
|
-
{/if}
|
|
108
|
-
</T>
|
|
105
|
+
{/if}
|
|
109
106
|
|
|
110
107
|
{#if linePositions.current && dotSize.current}
|
|
111
108
|
<LineDots
|
|
@@ -116,9 +113,5 @@
|
|
|
116
113
|
/>
|
|
117
114
|
{/if}
|
|
118
115
|
|
|
119
|
-
{#if name.current}
|
|
120
|
-
<PortalTarget id={name.current} />
|
|
121
|
-
{/if}
|
|
122
|
-
|
|
123
116
|
{@render children?.()}
|
|
124
|
-
</
|
|
117
|
+
</T>
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
import type { Snippet } from 'svelte'
|
|
4
4
|
|
|
5
5
|
import { T, useTask, useThrelte } from '@threlte/core'
|
|
6
|
-
import { Portal } from '@threlte/extras'
|
|
7
6
|
import { OrthographicCamera, Points, PointsMaterial } from 'three'
|
|
8
7
|
|
|
9
8
|
import { asColor, isSingleColor } from '../../buffer'
|
|
10
|
-
import { traits,
|
|
9
|
+
import { traits, useTrait } from '../../ecs'
|
|
11
10
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
12
11
|
|
|
13
12
|
import AxesHelper from '../AxesHelper.svelte'
|
|
@@ -23,8 +22,7 @@
|
|
|
23
22
|
const { camera } = useThrelte()
|
|
24
23
|
const settings = useSettings()
|
|
25
24
|
|
|
26
|
-
const
|
|
27
|
-
const matrix = useTrait(() => entity, traits.Matrix)
|
|
25
|
+
const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
|
|
28
26
|
const geometry = useTrait(() => entity, traits.BufferGeometry)
|
|
29
27
|
const entityColor = useTrait(() => entity, traits.Color)
|
|
30
28
|
const colors = useTrait(() => entity, traits.Colors)
|
|
@@ -98,8 +96,8 @@
|
|
|
98
96
|
})
|
|
99
97
|
|
|
100
98
|
$effect.pre(() => {
|
|
101
|
-
if (
|
|
102
|
-
points.matrix.copy(
|
|
99
|
+
if (worldMatrix.current) {
|
|
100
|
+
points.matrix.copy(worldMatrix.current)
|
|
103
101
|
points.updateMatrixWorld()
|
|
104
102
|
}
|
|
105
103
|
})
|
|
@@ -126,25 +124,23 @@
|
|
|
126
124
|
</script>
|
|
127
125
|
|
|
128
126
|
{#if geometry.current}
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
</T>
|
|
149
|
-
</Portal>
|
|
127
|
+
<T
|
|
128
|
+
is={points}
|
|
129
|
+
name={entity}
|
|
130
|
+
bvh={{ maxDepth: 40, maxLeafSize: 20 }}
|
|
131
|
+
visible={invisible.current !== true}
|
|
132
|
+
renderOrder={renderOrder.current}
|
|
133
|
+
{...events}
|
|
134
|
+
>
|
|
135
|
+
<T is={geometry.current} />
|
|
136
|
+
<T is={material} />
|
|
137
|
+
{#if showAxesHelper.current}
|
|
138
|
+
<AxesHelper
|
|
139
|
+
name={entity}
|
|
140
|
+
width={3}
|
|
141
|
+
length={0.1}
|
|
142
|
+
/>
|
|
143
|
+
{/if}
|
|
144
|
+
{@render children?.()}
|
|
145
|
+
</T>
|
|
150
146
|
{/if}
|
|
@@ -51,7 +51,13 @@
|
|
|
51
51
|
enabled.set(settings.current.interactionMode === 'navigate')
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
const bvhEnabled = $derived(
|
|
55
|
+
settings.current.renderSubEntityHoverDetail ||
|
|
56
|
+
settings.current.interactionMode === 'measure' ||
|
|
57
|
+
settings.current.interactionMode === 'select'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
bvh(raycaster, () => ({ helper: false, enabled: bvhEnabled }))
|
|
55
61
|
|
|
56
62
|
const focusedObject = $derived(focusedObject3d.current)
|
|
57
63
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
module
|
|
3
3
|
lang="ts"
|
|
4
4
|
>
|
|
5
|
-
import { ThemeUtils } from 'svelte-tweakpane-ui'
|
|
6
5
|
import { BufferAttribute, Euler, MathUtils, Quaternion } from 'three'
|
|
7
6
|
|
|
8
7
|
import { OrientationVector } from '../../three/OrientationVector'
|
|
@@ -280,12 +279,6 @@
|
|
|
280
279
|
2
|
|
281
280
|
)
|
|
282
281
|
}
|
|
283
|
-
|
|
284
|
-
ThemeUtils.setGlobalDefaultTheme({
|
|
285
|
-
...ThemeUtils.presets.light,
|
|
286
|
-
baseBackgroundColor: '#fbfbfc',
|
|
287
|
-
baseShadowColor: 'transparent',
|
|
288
|
-
})
|
|
289
282
|
</script>
|
|
290
283
|
|
|
291
284
|
{#snippet ImmutableField({
|
package/dist/draw.js
CHANGED
|
@@ -305,8 +305,9 @@ const drawModel = (world, model, api, { removable = true }) => {
|
|
|
305
305
|
relations.ChildOf(root),
|
|
306
306
|
api,
|
|
307
307
|
];
|
|
308
|
-
if (scale)
|
|
309
|
-
subEntityTraits.push(traits.
|
|
308
|
+
if (scale) {
|
|
309
|
+
subEntityTraits.push(traits.Matrix(new Matrix4().makeScale(scale.x ?? 1, scale.y ?? 1, scale.z ?? 1)));
|
|
310
|
+
}
|
|
310
311
|
if (metadata?.invisible)
|
|
311
312
|
subEntityTraits.push(traits.Invisible);
|
|
312
313
|
if (metadata?.showAxesHelper)
|
package/dist/ecs/traits.d.ts
CHANGED
|
@@ -143,11 +143,6 @@ export declare const GLTF: import("koota").Trait<() => {
|
|
|
143
143
|
};
|
|
144
144
|
animationName: string;
|
|
145
145
|
}>;
|
|
146
|
-
export declare const Scale: import("koota").Trait<{
|
|
147
|
-
x: number;
|
|
148
|
-
y: number;
|
|
149
|
-
z: number;
|
|
150
|
-
}>;
|
|
151
146
|
export declare const FramesAPI: import("koota").Trait<() => boolean>;
|
|
152
147
|
export declare const GeometriesAPI: import("koota").Trait<() => boolean>;
|
|
153
148
|
export declare const DrawAPI: import("koota").Trait<() => boolean>;
|
package/dist/ecs/traits.js
CHANGED
|
@@ -120,7 +120,6 @@ export const GLTF = trait(() => ({
|
|
|
120
120
|
source: { url: '' },
|
|
121
121
|
animationName: '',
|
|
122
122
|
}));
|
|
123
|
-
export const Scale = trait({ x: 1, y: 1, z: 1 });
|
|
124
123
|
export const FramesAPI = trait(() => true);
|
|
125
124
|
export const GeometriesAPI = trait(() => true);
|
|
126
125
|
export const DrawAPI = trait(() => true);
|
|
@@ -231,7 +230,9 @@ export const updateGeometryTrait = (entity, geometry) => {
|
|
|
231
230
|
}
|
|
232
231
|
else if (geometry.geometryType.case === 'mesh') {
|
|
233
232
|
if (entity.has(BufferGeometry)) {
|
|
233
|
+
const old = entity.get(BufferGeometry);
|
|
234
234
|
entity.set(BufferGeometry, parsePlyInput(geometry.geometryType.value.mesh));
|
|
235
|
+
old?.dispose();
|
|
235
236
|
}
|
|
236
237
|
else {
|
|
237
238
|
entity.remove(Box, Sphere, Capsule);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type World } from 'koota';
|
|
2
2
|
/**
|
|
3
3
|
* Wire up listeners that maintain `WorldMatrix` reactively. Subscribes to
|
|
4
|
-
* add/change/remove on `Matrix`, `EditedMatrix`, `LiveMatrix`, `
|
|
5
|
-
*
|
|
4
|
+
* add/change/remove on `Matrix`, `EditedMatrix`, `LiveMatrix`, and `ChildOf`;
|
|
5
|
+
* enqueues affected entities and flushes on the next microtask.
|
|
6
6
|
*
|
|
7
7
|
* Returns an unsubscribe function. Plain function (not a rune hook) so tests
|
|
8
8
|
* can drive the lifecycle without mounting Svelte.
|
package/dist/ecs/worldMatrix.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {} from 'koota';
|
|
2
|
-
import { Matrix4
|
|
2
|
+
import { Matrix4 } from 'three';
|
|
3
3
|
import { composeLocalMatrix } from '../transform';
|
|
4
4
|
import { ChildOf } from './relations';
|
|
5
|
-
import { EditedMatrix, LiveMatrix, Matrix,
|
|
6
|
-
const scaleVec3 = new Vector3();
|
|
5
|
+
import { EditedMatrix, LiveMatrix, Matrix, WorldMatrix } from './traits';
|
|
7
6
|
/**
|
|
8
7
|
* Compute the entity's local-to-parent transform into `out`. Mirrors the
|
|
9
8
|
* blend used by `Frame.svelte` so `WorldMatrix` agrees with the displayed
|
|
@@ -52,10 +51,6 @@ const recomputeWorldMatrix = (world, entity, cache) => {
|
|
|
52
51
|
const hasLocal = toLocalMatrix(entity, out);
|
|
53
52
|
if (!hasLocal)
|
|
54
53
|
out.identity();
|
|
55
|
-
const scale = entity.get(Scale);
|
|
56
|
-
if (scale) {
|
|
57
|
-
out.scale(scaleVec3.copy(scale));
|
|
58
|
-
}
|
|
59
54
|
const parent = entity.targetFor(ChildOf);
|
|
60
55
|
if (parent && parent.isAlive()) {
|
|
61
56
|
const parentWorld = recomputeWorldMatrix(world, parent, cache);
|
|
@@ -97,8 +92,8 @@ const flushDirty = (world, dirty) => {
|
|
|
97
92
|
};
|
|
98
93
|
/**
|
|
99
94
|
* Wire up listeners that maintain `WorldMatrix` reactively. Subscribes to
|
|
100
|
-
* add/change/remove on `Matrix`, `EditedMatrix`, `LiveMatrix`, `
|
|
101
|
-
*
|
|
95
|
+
* add/change/remove on `Matrix`, `EditedMatrix`, `LiveMatrix`, and `ChildOf`;
|
|
96
|
+
* enqueues affected entities and flushes on the next microtask.
|
|
102
97
|
*
|
|
103
98
|
* Returns an unsubscribe function. Plain function (not a rune hook) so tests
|
|
104
99
|
* can drive the lifecycle without mounting Svelte.
|
|
@@ -122,8 +117,6 @@ export const installWorldMatrixListeners = (world) => {
|
|
|
122
117
|
enqueue(entity);
|
|
123
118
|
for (const entity of world.query(LiveMatrix))
|
|
124
119
|
enqueue(entity);
|
|
125
|
-
for (const entity of world.query(Scale))
|
|
126
|
-
enqueue(entity);
|
|
127
120
|
const unsubs = [
|
|
128
121
|
world.onAdd(Matrix, enqueue),
|
|
129
122
|
world.onChange(Matrix, enqueue),
|
|
@@ -134,9 +127,6 @@ export const installWorldMatrixListeners = (world) => {
|
|
|
134
127
|
world.onAdd(LiveMatrix, enqueue),
|
|
135
128
|
world.onChange(LiveMatrix, enqueue),
|
|
136
129
|
world.onRemove(LiveMatrix, enqueue),
|
|
137
|
-
world.onAdd(Scale, enqueue),
|
|
138
|
-
world.onChange(Scale, enqueue),
|
|
139
|
-
world.onRemove(Scale, enqueue),
|
|
140
130
|
world.onAdd(ChildOf, enqueue),
|
|
141
131
|
world.onChange(ChildOf, enqueue),
|
|
142
132
|
world.onRemove(ChildOf, enqueue),
|
|
@@ -10,7 +10,7 @@ import { DrawService } from '../buf/draw/v1/service_connect';
|
|
|
10
10
|
import { CreateRelationshipRequest, DeleteRelationshipRequest, EntityChangeType, StreamEntityChangesResponse, } from '../buf/draw/v1/service_pb';
|
|
11
11
|
import { asFloat32Array, inMeters, STRIDE } from '../buffer';
|
|
12
12
|
import { drawDrawing, drawTransform, updateDrawing, updateModel, updateTransform, uuidStringToBytes, } from '../draw';
|
|
13
|
-
import { traits, useWorld } from '../ecs';
|
|
13
|
+
import { hierarchy, traits, useWorld } from '../ecs';
|
|
14
14
|
import { useCameraControls } from './useControls.svelte';
|
|
15
15
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
16
16
|
import { useRelationships } from './useRelationships.svelte';
|
|
@@ -50,8 +50,7 @@ export function provideDrawService() {
|
|
|
50
50
|
const entity = drawingEntities.get(uuidStr);
|
|
51
51
|
if (!entity)
|
|
52
52
|
return;
|
|
53
|
-
|
|
54
|
-
entity.destroy();
|
|
53
|
+
hierarchy.destroyEntityTree(world, entity);
|
|
55
54
|
drawingEntities.delete(uuidStr);
|
|
56
55
|
};
|
|
57
56
|
const processEvent = (event) => {
|
|
@@ -334,13 +333,11 @@ export function provideDrawService() {
|
|
|
334
333
|
connectionStatus = ConnectionStatus.DISCONNECTED;
|
|
335
334
|
activeClient = undefined;
|
|
336
335
|
for (const entity of transformEntities.values()) {
|
|
337
|
-
|
|
338
|
-
entity.destroy();
|
|
336
|
+
hierarchy.destroyEntityTree(world, entity);
|
|
339
337
|
}
|
|
340
338
|
transformEntities.clear();
|
|
341
339
|
for (const entity of drawingEntities.values()) {
|
|
342
|
-
|
|
343
|
-
entity.destroy();
|
|
340
|
+
hierarchy.destroyEntityTree(world, entity);
|
|
344
341
|
}
|
|
345
342
|
drawingEntities.clear();
|
|
346
343
|
relationships.clear();
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { ArmClient, BaseClient, CameraClient, GantryClient, GripperClient } from '@viamrobotics/sdk';
|
|
1
|
+
import { ArmClient, BaseClient, CameraClient, GantryClient, GenericComponentClient, GripperClient, } from '@viamrobotics/sdk';
|
|
2
2
|
import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import {} from 'koota';
|
|
4
4
|
import { getContext, setContext, untrack } from 'svelte';
|
|
5
|
-
import { Color } from 'three';
|
|
5
|
+
import { Color, Matrix4 } from 'three';
|
|
6
6
|
import { resourceColors } from '../color';
|
|
7
7
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
8
8
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
9
9
|
import { updateGeometryTrait } from '../ecs/traits';
|
|
10
|
-
import { createPose,
|
|
10
|
+
import { createPose, poseToMatrix } from '../transform';
|
|
11
11
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
12
12
|
import { useLogs } from './useLogs.svelte';
|
|
13
13
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
14
14
|
import { RefreshRates, useSettings } from './useSettings.svelte';
|
|
15
15
|
const key = Symbol('geometries-context');
|
|
16
16
|
const colorUtil = new Color();
|
|
17
|
+
const tempMatrix = new Matrix4();
|
|
17
18
|
export const provideGeometries = (partID) => {
|
|
18
19
|
const environment = useEnvironment();
|
|
19
20
|
const resources = useResourceByName();
|
|
@@ -24,6 +25,7 @@ export const provideGeometries = (partID) => {
|
|
|
24
25
|
const cameras = useResourceNames(partID, 'camera');
|
|
25
26
|
const grippers = useResourceNames(partID, 'gripper');
|
|
26
27
|
const gantries = useResourceNames(partID, 'gantry');
|
|
28
|
+
const generics = useResourceNames(partID, 'generic');
|
|
27
29
|
const settings = useSettings();
|
|
28
30
|
const { refreshRates } = $derived(settings.current);
|
|
29
31
|
const armClients = $derived(arms.current.map((arm) => createResourceClient(ArmClient, partID, () => arm.name)));
|
|
@@ -31,6 +33,9 @@ export const provideGeometries = (partID) => {
|
|
|
31
33
|
const gripperClients = $derived(grippers.current.map((gripper) => createResourceClient(GripperClient, partID, () => gripper.name)));
|
|
32
34
|
const cameraClients = $derived(cameras.current.map((camera) => createResourceClient(CameraClient, partID, () => camera.name)));
|
|
33
35
|
const gantryClients = $derived(gantries.current.map((gantry) => createResourceClient(GantryClient, partID, () => gantry.name)));
|
|
36
|
+
const genericClients = $derived(generics.current
|
|
37
|
+
.filter((generic) => generic.type === 'component')
|
|
38
|
+
.map((generic) => createResourceClient(GenericComponentClient, partID, () => generic.name)));
|
|
34
39
|
const interval = $derived(refreshRates[RefreshRates.poses]);
|
|
35
40
|
const options = $derived({
|
|
36
41
|
enabled: interval !== RefetchRates.OFF && environment.current.viewerMode === 'monitor',
|
|
@@ -41,12 +46,14 @@ export const provideGeometries = (partID) => {
|
|
|
41
46
|
const gripperQueries = $derived(gripperClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
|
|
42
47
|
const cameraQueries = $derived(cameraClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
|
|
43
48
|
const gantryQueries = $derived(gantryClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
|
|
49
|
+
const genericQueries = $derived(genericClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
|
|
44
50
|
const queries = $derived([
|
|
45
51
|
...armQueries,
|
|
46
52
|
...baseQueries,
|
|
47
53
|
...gripperQueries,
|
|
48
54
|
...cameraQueries,
|
|
49
55
|
...gantryQueries,
|
|
56
|
+
...genericQueries,
|
|
50
57
|
]);
|
|
51
58
|
$effect(() => {
|
|
52
59
|
if (interval === RefetchRates.FPS_30 || interval === RefetchRates.FPS_60) {
|
|
@@ -91,8 +98,11 @@ export const provideGeometries = (partID) => {
|
|
|
91
98
|
const existing = entities.get(entityKey);
|
|
92
99
|
if (existing) {
|
|
93
100
|
hierarchy.setParent(existing, name);
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
poseToMatrix(center, tempMatrix);
|
|
102
|
+
const matrix = existing.get(traits.Matrix);
|
|
103
|
+
if (matrix && !matrix.equals(tempMatrix)) {
|
|
104
|
+
matrix.copy(tempMatrix);
|
|
105
|
+
existing.changed(traits.Matrix);
|
|
96
106
|
}
|
|
97
107
|
updateGeometryTrait(existing, geometry);
|
|
98
108
|
continue;
|
|
@@ -100,7 +110,7 @@ export const provideGeometries = (partID) => {
|
|
|
100
110
|
const entityTraits = [
|
|
101
111
|
...hierarchy.parentTraits(name),
|
|
102
112
|
traits.Name(label),
|
|
103
|
-
traits.
|
|
113
|
+
traits.Matrix(poseToMatrix(center, new Matrix4())),
|
|
104
114
|
traits.GeometriesAPI,
|
|
105
115
|
traits.Geometry(geometry),
|
|
106
116
|
];
|
|
@@ -8,7 +8,7 @@ export const providePartConfig = (partID, params) => {
|
|
|
8
8
|
const props = $derived(params());
|
|
9
9
|
const config = $derived(props ? useEmbeddedPartConfig(props) : useStandalonePartConfig(partID));
|
|
10
10
|
const getCurrent = () => {
|
|
11
|
-
return (config.current
|
|
11
|
+
return (config.current?.toJson?.() ?? { components: [] });
|
|
12
12
|
};
|
|
13
13
|
const current = $derived(getCurrent());
|
|
14
14
|
const createFragmentFrame = (fragmentId, componentName) => {
|
|
@@ -313,10 +313,12 @@ const useStandalonePartConfig = (partID) => {
|
|
|
313
313
|
const id = partID();
|
|
314
314
|
if (lastPartID !== undefined && lastPartID !== id) {
|
|
315
315
|
// Part changed: drop any in-memory edits/pending-save state from the
|
|
316
|
-
// previous part
|
|
317
|
-
//
|
|
316
|
+
// previous part, and clear `current` so consumers don't keep
|
|
317
|
+
// rendering the old config's frames while the new part loads
|
|
318
|
+
// (offline parts may never load, leaving the old frames forever).
|
|
318
319
|
isDirty = false;
|
|
319
320
|
hasPendingSave = false;
|
|
321
|
+
current = undefined;
|
|
320
322
|
}
|
|
321
323
|
lastPartID = id;
|
|
322
324
|
if (!networkPartConfig || isDirty) {
|
|
@@ -17,11 +17,14 @@ export const bvh = (raycaster, options) => {
|
|
|
17
17
|
injectPlugin('bvh', (args) => {
|
|
18
18
|
const { props } = $derived(args);
|
|
19
19
|
const opts = $derived(props.bvh ? { ...bvhOptions, ...props.bvh } : bvhOptions);
|
|
20
|
+
let computed = false;
|
|
21
|
+
let helper;
|
|
20
22
|
$effect(() => {
|
|
21
23
|
const { ref } = args;
|
|
22
|
-
if (
|
|
24
|
+
if (computed)
|
|
25
|
+
return;
|
|
26
|
+
if (opts.enabled === false)
|
|
23
27
|
return;
|
|
24
|
-
}
|
|
25
28
|
if (isInstanceOf(ref, 'Points') &&
|
|
26
29
|
/**
|
|
27
30
|
* This check is necessary, there are some strange cases where points are coming in from PCDs without any position data
|
|
@@ -31,28 +34,12 @@ export const bvh = (raycaster, options) => {
|
|
|
31
34
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
32
35
|
ref.raycast = acceleratedRaycast;
|
|
33
36
|
computeBoundsTree.call(ref.geometry, { type: PointsBVH, ...opts });
|
|
34
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
35
|
-
if (helper)
|
|
36
|
-
ref.add(helper);
|
|
37
|
-
return () => {
|
|
38
|
-
ref.raycast = Points.prototype.raycast;
|
|
39
|
-
if (helper)
|
|
40
|
-
ref.remove(helper);
|
|
41
|
-
};
|
|
42
37
|
}
|
|
43
38
|
else if (isInstanceOf(ref, 'BatchedMesh')) {
|
|
44
39
|
/* @ts-expect-error Some sort of ambient type is conflicing here, likely from @threlte/extras */
|
|
45
40
|
ref.geometry.computeBoundsTree = computeBatchedBoundsTree;
|
|
46
41
|
ref.geometry.disposeBoundsTree = disposeBatchedBoundsTree;
|
|
47
42
|
ref.raycast = acceleratedRaycast;
|
|
48
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
49
|
-
if (helper)
|
|
50
|
-
ref.add(helper);
|
|
51
|
-
return () => {
|
|
52
|
-
ref.raycast = BatchedMesh.prototype.raycast;
|
|
53
|
-
if (helper)
|
|
54
|
-
ref.remove(helper);
|
|
55
|
-
};
|
|
56
43
|
}
|
|
57
44
|
else if (isInstanceOf(ref, 'Mesh') &&
|
|
58
45
|
/**
|
|
@@ -64,15 +51,39 @@ export const bvh = (raycaster, options) => {
|
|
|
64
51
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
65
52
|
ref.raycast = acceleratedRaycast;
|
|
66
53
|
computeBoundsTree.call(ref.geometry, opts);
|
|
67
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
68
|
-
if (helper)
|
|
69
|
-
ref.add(helper);
|
|
70
|
-
return () => {
|
|
71
|
-
ref.raycast = Mesh.prototype.raycast;
|
|
72
|
-
if (helper)
|
|
73
|
-
ref.remove(helper);
|
|
74
|
-
};
|
|
75
54
|
}
|
|
55
|
+
else {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (opts.helper) {
|
|
59
|
+
helper = new BVHHelper(ref);
|
|
60
|
+
ref.add(helper);
|
|
61
|
+
}
|
|
62
|
+
computed = true;
|
|
63
|
+
});
|
|
64
|
+
$effect(() => {
|
|
65
|
+
const { ref } = args;
|
|
66
|
+
return () => {
|
|
67
|
+
if (!computed)
|
|
68
|
+
return;
|
|
69
|
+
if (isInstanceOf(ref, 'Points')) {
|
|
70
|
+
ref.geometry.disposeBoundsTree?.();
|
|
71
|
+
ref.raycast = Points.prototype.raycast;
|
|
72
|
+
}
|
|
73
|
+
else if (isInstanceOf(ref, 'BatchedMesh')) {
|
|
74
|
+
ref.geometry.disposeBoundsTree?.();
|
|
75
|
+
ref.raycast = BatchedMesh.prototype.raycast;
|
|
76
|
+
}
|
|
77
|
+
else if (isInstanceOf(ref, 'Mesh')) {
|
|
78
|
+
ref.geometry.disposeBoundsTree?.();
|
|
79
|
+
ref.raycast = Mesh.prototype.raycast;
|
|
80
|
+
}
|
|
81
|
+
if (helper) {
|
|
82
|
+
ref.remove(helper);
|
|
83
|
+
helper = undefined;
|
|
84
|
+
}
|
|
85
|
+
computed = false;
|
|
86
|
+
};
|
|
76
87
|
});
|
|
77
88
|
});
|
|
78
89
|
};
|
package/dist/three/OBBHelper.js
CHANGED
|
@@ -39,9 +39,12 @@ const expandBoxByTransformedBox = (box, childBox, matrix) => {
|
|
|
39
39
|
};
|
|
40
40
|
export class OBBHelper extends LineSegments2 {
|
|
41
41
|
constructor(color = 0x000000, linewidth = 2) {
|
|
42
|
-
const
|
|
42
|
+
const boxGeometry = new BoxGeometry();
|
|
43
|
+
const edges = new EdgesGeometry(boxGeometry);
|
|
43
44
|
const geometry = new LineSegmentsGeometry();
|
|
44
45
|
geometry.setPositions(edges.getAttribute('position').array);
|
|
46
|
+
edges.dispose();
|
|
47
|
+
boxGeometry.dispose();
|
|
45
48
|
const material = new LineMaterial({
|
|
46
49
|
color,
|
|
47
50
|
linewidth,
|
package/dist/three/arrow.js
CHANGED
|
@@ -20,6 +20,8 @@ export const createArrowGeometry = () => {
|
|
|
20
20
|
// Place its center at y = shaftLength + headLength/2 so tip lands at y = shaftLength + headLength
|
|
21
21
|
headGeo.translate(0, tailLength + headLength * 0.5, 0);
|
|
22
22
|
const merged = mergeGeometries([tailGeometry, headGeo], true);
|
|
23
|
+
tailGeometry.dispose();
|
|
24
|
+
headGeo.dispose();
|
|
23
25
|
merged.computeVertexNormals();
|
|
24
26
|
merged.computeBoundingBox();
|
|
25
27
|
merged.computeBoundingSphere();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.1",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"prettier-plugin-tailwindcss": "0.6.14",
|
|
65
65
|
"publint": "0.3.12",
|
|
66
66
|
"runed": "0.31.1",
|
|
67
|
-
"svelte": "5.55.
|
|
67
|
+
"svelte": "5.55.7",
|
|
68
68
|
"svelte-check": "4.4.5",
|
|
69
69
|
"svelte-tweakpane-ui": "^1.5.16",
|
|
70
70
|
"svelte-virtuallists": "1.4.2",
|