@viamrobotics/motion-tools 1.28.1 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/App.svelte +3 -12
- package/dist/components/App.svelte.d.ts +0 -2
- package/dist/components/SceneProviders.svelte +1 -4
- package/dist/components/SelectedTransformControls.svelte +25 -16
- package/dist/components/overlay/AddRelationship.svelte +6 -20
- package/dist/components/overlay/Details.svelte +2 -12
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/plugins/DrawService/DrawService.svelte +18 -0
- package/dist/plugins/DrawService/DrawService.svelte.d.ts +7 -0
- package/dist/plugins/DrawService/serverRelationships.d.ts +14 -0
- package/dist/plugins/DrawService/serverRelationships.js +105 -0
- package/dist/{hooks → plugins/DrawService}/useDrawAPI.svelte.js +9 -9
- package/dist/{hooks → plugins/DrawService}/useDrawService.svelte.d.ts +0 -2
- package/dist/{hooks → plugins/DrawService}/useDrawService.svelte.js +19 -45
- package/dist/{components/Selection/Tool.svelte → plugins/Selection/SelectionTool.svelte} +3 -3
- package/dist/{components/Selection/Tool.svelte.d.ts → plugins/Selection/SelectionTool.svelte.d.ts} +3 -3
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.js +6 -0
- package/package.json +2 -1
- /package/dist/{hooks → plugins/DrawService}/useDrawAPI.svelte.d.ts +0 -0
- /package/dist/{hooks → plugins/DrawService}/useDrawConnectionConfig.svelte.d.ts +0 -0
- /package/dist/{hooks → plugins/DrawService}/useDrawConnectionConfig.svelte.js +0 -0
- /package/dist/{components → plugins}/Selection/Debug.svelte +0 -0
- /package/dist/{components → plugins}/Selection/Debug.svelte.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/Ellipse.svelte +0 -0
- /package/dist/{components → plugins}/Selection/Ellipse.svelte.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/Lasso.svelte +0 -0
- /package/dist/{components → plugins}/Selection/Lasso.svelte.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/traits.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/traits.js +0 -0
- /package/dist/{components → plugins}/Selection/useSelectionPlugin.svelte.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/useSelectionPlugin.svelte.js +0 -0
- /package/dist/{components → plugins}/Selection/utils.d.ts +0 -0
- /package/dist/{components → plugins}/Selection/utils.js +0 -0
|
@@ -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 { primeTheme } from '@viamrobotics/tweakpane-config'
|
|
11
12
|
import { ThemeUtils } from 'svelte-tweakpane-ui'
|
|
12
13
|
|
|
13
14
|
import Controls from './overlay/controls/Controls.svelte'
|
|
@@ -18,10 +19,6 @@
|
|
|
18
19
|
import XR from './xr/XR.svelte'
|
|
19
20
|
import { provideWorld } from '../ecs'
|
|
20
21
|
import { type CameraPose, provideCameraControls } from '../hooks/useControls.svelte'
|
|
21
|
-
import {
|
|
22
|
-
type DrawConnectionConfig,
|
|
23
|
-
provideDrawConnectionConfig,
|
|
24
|
-
} from '../hooks/useDrawConnectionConfig.svelte'
|
|
25
22
|
import { provideEnvironment } from '../hooks/useEnvironment.svelte'
|
|
26
23
|
import { providePartConfig } from '../hooks/usePartConfig.svelte'
|
|
27
24
|
import { createPartIDContext } from '../hooks/usePartID.svelte'
|
|
@@ -51,7 +48,6 @@
|
|
|
51
48
|
partID?: string
|
|
52
49
|
inputBindingsEnabled?: boolean
|
|
53
50
|
localConfigProps?: LocalConfigProps
|
|
54
|
-
drawConnectionConfig?: DrawConnectionConfig
|
|
55
51
|
|
|
56
52
|
/**
|
|
57
53
|
* Snippet for THREE objects
|
|
@@ -79,7 +75,6 @@
|
|
|
79
75
|
inputBindingsEnabled = true,
|
|
80
76
|
localConfigProps,
|
|
81
77
|
cameraPose,
|
|
82
|
-
drawConnectionConfig,
|
|
83
78
|
children: appChildren,
|
|
84
79
|
dashboard,
|
|
85
80
|
details,
|
|
@@ -95,7 +90,7 @@
|
|
|
95
90
|
|
|
96
91
|
provideCameraControls(() => cameraPose)
|
|
97
92
|
createPartIDContext(() => partID)
|
|
98
|
-
|
|
93
|
+
|
|
99
94
|
provideWeblabs()
|
|
100
95
|
provideToast()
|
|
101
96
|
|
|
@@ -112,11 +107,7 @@
|
|
|
112
107
|
})
|
|
113
108
|
|
|
114
109
|
$effect(() => {
|
|
115
|
-
ThemeUtils.setGlobalDefaultTheme(
|
|
116
|
-
...ThemeUtils.presets.light,
|
|
117
|
-
baseBackgroundColor: '#fbfbfc',
|
|
118
|
-
baseShadowColor: 'transparent',
|
|
119
|
-
})
|
|
110
|
+
ThemeUtils.setGlobalDefaultTheme(primeTheme)
|
|
120
111
|
})
|
|
121
112
|
</script>
|
|
122
113
|
|
|
@@ -2,7 +2,6 @@ import type { Struct } from '@viamrobotics/sdk';
|
|
|
2
2
|
import type { Entity } from 'koota';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
4
|
import { type CameraPose } from '../hooks/useControls.svelte';
|
|
5
|
-
import { type DrawConnectionConfig } from '../hooks/useDrawConnectionConfig.svelte';
|
|
6
5
|
interface LocalConfigProps {
|
|
7
6
|
current: Struct;
|
|
8
7
|
isDirty: boolean;
|
|
@@ -13,7 +12,6 @@ interface Props {
|
|
|
13
12
|
partID?: string;
|
|
14
13
|
inputBindingsEnabled?: boolean;
|
|
15
14
|
localConfigProps?: LocalConfigProps;
|
|
16
|
-
drawConnectionConfig?: DrawConnectionConfig;
|
|
17
15
|
/**
|
|
18
16
|
* Snippet for THREE objects
|
|
19
17
|
*/
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
import { provideArmKinematics } from '../hooks/useArmKinematics.svelte'
|
|
8
8
|
import { provideConfigFrames } from '../hooks/useConfigFrames.svelte'
|
|
9
9
|
import { provideTransformControls } from '../hooks/useControls.svelte'
|
|
10
|
-
import { provideDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
11
|
-
import { provideDrawService } from '../hooks/useDrawService.svelte'
|
|
12
10
|
import { provideFrameEditSession } from '../hooks/useFrameEditSession.svelte'
|
|
13
11
|
import { provideFramelessComponents } from '../hooks/useFramelessComponents.svelte'
|
|
14
12
|
import { provideFrames } from '../hooks/useFrames.svelte'
|
|
@@ -39,9 +37,8 @@
|
|
|
39
37
|
provideHierarchy()
|
|
40
38
|
provideWorldMatrix()
|
|
41
39
|
provideOrigin()
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
provideRelationships()
|
|
44
|
-
provideDrawService()
|
|
45
42
|
|
|
46
43
|
provideResourceByName(() => partID.current)
|
|
47
44
|
provideConfigFrames()
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { FrameEditSession } from '../editing/FrameEditSession'
|
|
6
6
|
|
|
7
|
-
import { traits, useTrait } from '../ecs'
|
|
7
|
+
import { relations, traits, useTrait } from '../ecs'
|
|
8
8
|
import { useTransformControls } from '../hooks/useControls.svelte'
|
|
9
9
|
import { useEnvironment } from '../hooks/useEnvironment.svelte'
|
|
10
10
|
import { useFrameEditSession } from '../hooks/useFrameEditSession.svelte'
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
const refPose = createPose()
|
|
61
61
|
const tempRefMatrix = new Matrix4()
|
|
62
62
|
const tempEditedMatrix = new Matrix4()
|
|
63
|
+
const tempParentInverse = new Matrix4()
|
|
63
64
|
const tempPose = createPose()
|
|
64
65
|
|
|
65
66
|
let session: FrameEditSession | undefined
|
|
@@ -183,30 +184,40 @@
|
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
/**
|
|
186
|
-
* Frame.svelte renders frame entities by
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
187
|
+
* Frame.svelte renders frame entities by writing the entity's WorldMatrix
|
|
188
|
+
* into group.matrix and decomposing it into position/quaternion. The gizmo's
|
|
189
|
+
* Three.js parent has identity world, so `ref.position` / `ref.quaternion`
|
|
190
|
+
* are world-space values. Matrix and EditedMatrix store local-to-parent
|
|
191
|
+
* transforms, so we left-multiply by the parent's inverted WorldMatrix
|
|
192
|
+
* before staging — otherwise WorldMatrix recomposition (parent × edited)
|
|
193
|
+
* re-applies the parent's rotation/translation and the frame ends up at
|
|
194
|
+
* parent × where-the-user-pulled-it.
|
|
190
195
|
*
|
|
191
|
-
*
|
|
192
|
-
* M(
|
|
193
|
-
*
|
|
194
|
-
* composition is what keeps the rendering anchored to the user's pointer
|
|
195
|
-
* instead of shearing through the live × baseline⁻¹ offset.
|
|
196
|
+
* With a kinematic offset (LiveMatrix + Matrix both present), the local
|
|
197
|
+
* target M(local) feeds solveEditedMatrix to back out the EditedMatrix
|
|
198
|
+
* that satisfies live × baseline⁻¹ × edited = local.
|
|
196
199
|
*/
|
|
197
|
-
|
|
198
200
|
const stageFrameTransform = () => {
|
|
199
201
|
if (!ref || !entity) return
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
tempRefMatrix.makeRotationFromQuaternion(ref.quaternion)
|
|
204
|
+
tempRefMatrix.setPosition(ref.position)
|
|
205
|
+
|
|
206
|
+
const parentEntity = entity.targetFor(relations.ChildOf)
|
|
207
|
+
const parentWorld = parentEntity?.get(traits.WorldMatrix)
|
|
208
|
+
if (parentWorld) {
|
|
209
|
+
tempParentInverse.copy(parentWorld).invert()
|
|
210
|
+
tempRefMatrix.premultiply(tempParentInverse)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
matrixToPose(tempRefMatrix, refPose)
|
|
203
214
|
|
|
204
215
|
const live = liveMatrix.current
|
|
205
216
|
const config = configMatrix.current
|
|
206
217
|
|
|
207
218
|
if (!live || !config) {
|
|
208
219
|
// No live matrix available — Frame.svelte's blend short-circuits to
|
|
209
|
-
// editedMatrix, so
|
|
220
|
+
// editedMatrix, so the parent-relative target is what we stage.
|
|
210
221
|
if (activeMode === 'translate') {
|
|
211
222
|
session?.stagePose(entity, {
|
|
212
223
|
x: refPose.x,
|
|
@@ -224,8 +235,6 @@
|
|
|
224
235
|
return
|
|
225
236
|
}
|
|
226
237
|
|
|
227
|
-
poseToMatrix(refPose, tempRefMatrix)
|
|
228
|
-
|
|
229
238
|
solveEditedMatrix(config, live, tempRefMatrix, tempEditedMatrix)
|
|
230
239
|
matrixToPose(tempEditedMatrix, tempPose)
|
|
231
240
|
session?.stagePose(entity, { ...tempPose })
|
|
@@ -4,14 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { relations, traits, useQuery, useTrait } from '../../ecs'
|
|
6
6
|
import { SubEntityLinkType } from '../../ecs/relations'
|
|
7
|
-
import { useDrawService } from '../../hooks/useDrawService.svelte'
|
|
8
7
|
|
|
9
8
|
interface Props {
|
|
10
9
|
entity: Entity | undefined
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
const { entity }: Props = $props()
|
|
14
|
-
const drawService = useDrawService()
|
|
15
13
|
|
|
16
14
|
const allEntities = useQuery(traits.Name)
|
|
17
15
|
const name = useTrait(() => entity, traits.Name)
|
|
@@ -55,24 +53,12 @@
|
|
|
55
53
|
)
|
|
56
54
|
if (!selectedEntity) return
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
targetUuid,
|
|
65
|
-
linkType ?? '',
|
|
66
|
-
relationshipFormula
|
|
67
|
-
)
|
|
68
|
-
} else {
|
|
69
|
-
entity.add(
|
|
70
|
-
relations.SubEntityLink(selectedEntity, {
|
|
71
|
-
indexMapping: relationshipFormula,
|
|
72
|
-
type: linkType,
|
|
73
|
-
})
|
|
74
|
-
)
|
|
75
|
-
}
|
|
56
|
+
entity.add(
|
|
57
|
+
relations.SubEntityLink(selectedEntity, {
|
|
58
|
+
indexMapping: relationshipFormula,
|
|
59
|
+
type: linkType,
|
|
60
|
+
})
|
|
61
|
+
)
|
|
76
62
|
showRelationshipOptions = false
|
|
77
63
|
resetForm()
|
|
78
64
|
}
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
import { FrameConfigUpdater } from '../../FrameConfigUpdater.svelte'
|
|
42
42
|
import { useConfigFrames } from '../../hooks/useConfigFrames.svelte'
|
|
43
43
|
import { useCameraControls } from '../../hooks/useControls.svelte'
|
|
44
|
-
import { useDrawService } from '../../hooks/useDrawService.svelte'
|
|
45
44
|
import { useEnvironment } from '../../hooks/useEnvironment.svelte'
|
|
46
45
|
import { useLinkedEntities } from '../../hooks/useLinked.svelte'
|
|
47
46
|
import { usePartConfig } from '../../hooks/usePartConfig.svelte'
|
|
@@ -64,7 +63,6 @@
|
|
|
64
63
|
|
|
65
64
|
const world = useWorld()
|
|
66
65
|
const { invalidate } = useThrelte()
|
|
67
|
-
const drawService = useDrawService()
|
|
68
66
|
const controls = useCameraControls()
|
|
69
67
|
const resourceByName = useResourceByName()
|
|
70
68
|
const configFrames = useConfigFrames()
|
|
@@ -309,7 +307,7 @@
|
|
|
309
307
|
{#if entity}
|
|
310
308
|
<div
|
|
311
309
|
id="details-panel"
|
|
312
|
-
class="border-medium bg-extralight absolute top-0 right-0 z-4 m-2 w-70 border p-2 text-xs
|
|
310
|
+
class="border-medium bg-extralight absolute top-0 right-0 z-4 m-2 w-70 border p-2 text-xs"
|
|
313
311
|
use:draggable={{
|
|
314
312
|
bounds: 'body',
|
|
315
313
|
handle: dragElement,
|
|
@@ -743,15 +741,7 @@
|
|
|
743
741
|
<Icon
|
|
744
742
|
name="trash-can-outline"
|
|
745
743
|
class="h-6 cursor-pointer px-2 py-1 text-xs text-red-500"
|
|
746
|
-
onclick={() =>
|
|
747
|
-
const sourceUuid = entity.get(traits.UUID)
|
|
748
|
-
const targetUuid = linkedEntity.get(traits.UUID)
|
|
749
|
-
if (sourceUuid && targetUuid) {
|
|
750
|
-
void drawService.deleteRelationship(sourceUuid, targetUuid)
|
|
751
|
-
} else {
|
|
752
|
-
entity.remove(relations.SubEntityLink(linkedEntity))
|
|
753
|
-
}
|
|
754
|
-
}}
|
|
744
|
+
onclick={() => entity.remove(relations.SubEntityLink(linkedEntity))}
|
|
755
745
|
/>
|
|
756
746
|
</div>
|
|
757
747
|
{/each}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/** @deprecated MotionTools has been renamed to Visualizer. This export will be removed in v2. */
|
|
2
2
|
export { default as MotionTools } from './components/App.svelte';
|
|
3
3
|
export { default as Visualizer } from './components/App.svelte';
|
|
4
|
-
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
5
4
|
export { default as PCD } from './components/PCD.svelte';
|
|
6
5
|
export * as relations from './ecs/relations';
|
|
7
6
|
export * as traits from './ecs/traits';
|
|
8
|
-
export * as selectionTraits from './components/Selection/traits';
|
|
9
|
-
export { useSelectionPlugin as useSelection } from './components/Selection/useSelectionPlugin.svelte';
|
|
10
7
|
export { default as FloatingPanel } from './components/overlay/FloatingPanel.svelte';
|
|
11
8
|
export { provideWorld, useWorld } from './ecs/useWorld';
|
|
12
9
|
export { useQuery } from './ecs/useQuery.svelte';
|
package/dist/index.js
CHANGED
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
export { default as MotionTools } from './components/App.svelte';
|
|
3
3
|
export { default as Visualizer } from './components/App.svelte';
|
|
4
4
|
// Plugins
|
|
5
|
-
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
6
5
|
export { default as PCD } from './components/PCD.svelte';
|
|
7
6
|
// ECS
|
|
8
7
|
export * as relations from './ecs/relations';
|
|
9
8
|
export * as traits from './ecs/traits';
|
|
10
|
-
export * as selectionTraits from './components/Selection/traits';
|
|
11
|
-
export { useSelectionPlugin as useSelection } from './components/Selection/useSelectionPlugin.svelte';
|
|
12
9
|
export { default as FloatingPanel } from './components/overlay/FloatingPanel.svelte';
|
|
13
10
|
export { provideWorld, useWorld } from './ecs/useWorld';
|
|
14
11
|
export { useQuery } from './ecs/useQuery.svelte';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { provideDrawAPI } from './useDrawAPI.svelte'
|
|
3
|
+
import {
|
|
4
|
+
type DrawConnectionConfig,
|
|
5
|
+
provideDrawConnectionConfig,
|
|
6
|
+
} from './useDrawConnectionConfig.svelte'
|
|
7
|
+
import { provideDrawService } from './useDrawService.svelte'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
config: DrawConnectionConfig
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { config }: Props = $props()
|
|
14
|
+
|
|
15
|
+
provideDrawConnectionConfig(() => config)
|
|
16
|
+
provideDrawAPI()
|
|
17
|
+
provideDrawService()
|
|
18
|
+
</script>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type DrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
config: DrawConnectionConfig;
|
|
4
|
+
}
|
|
5
|
+
declare const DrawService: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type DrawService = ReturnType<typeof DrawService>;
|
|
7
|
+
export default DrawService;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Entity } from 'koota';
|
|
2
|
+
import type { Relationship } from '../../metadata';
|
|
3
|
+
/**
|
|
4
|
+
* Diffs incoming server relationships against the last-known set per entity,
|
|
5
|
+
* so only links the draw service itself authored are added or removed.
|
|
6
|
+
* Client-added links (e.g. interactive HoverLinks from the Details overlay)
|
|
7
|
+
* are left alone.
|
|
8
|
+
*/
|
|
9
|
+
export declare const createServerRelationships: () => {
|
|
10
|
+
apply(sourceEntity: Entity, sourceUuid: string, relationships: Relationship[] | undefined): void;
|
|
11
|
+
forget(sourceUuid: string): void;
|
|
12
|
+
reset(): void;
|
|
13
|
+
dispose(): void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { trait } from 'koota';
|
|
2
|
+
import { uuidBytesToString } from '../../draw';
|
|
3
|
+
import { relations, traits, useWorld } from '../../ecs';
|
|
4
|
+
/**
|
|
5
|
+
* Forward-references waiting on their target entity to arrive. Lives on the
|
|
6
|
+
* source entity so it dies with it — no plugin-side bookkeeping to leak when
|
|
7
|
+
* a source is destroyed before its targets show up.
|
|
8
|
+
*/
|
|
9
|
+
const PendingLinks = trait(() => []);
|
|
10
|
+
/**
|
|
11
|
+
* Diffs incoming server relationships against the last-known set per entity,
|
|
12
|
+
* so only links the draw service itself authored are added or removed.
|
|
13
|
+
* Client-added links (e.g. interactive HoverLinks from the Details overlay)
|
|
14
|
+
* are left alone.
|
|
15
|
+
*/
|
|
16
|
+
export const createServerRelationships = () => {
|
|
17
|
+
const world = useWorld();
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
const lookupByUuid = (uuid) => world.query(traits.UUID).find((entity) => entity.get(traits.UUID) === uuid);
|
|
20
|
+
const enqueue = (sourceEntity, entry) => {
|
|
21
|
+
const existing = sourceEntity.get(PendingLinks) ?? [];
|
|
22
|
+
sourceEntity.set(PendingLinks, [...existing, entry]);
|
|
23
|
+
};
|
|
24
|
+
const unsubAdd = world.onAdd(traits.UUID, (target) => {
|
|
25
|
+
if (!target.isAlive())
|
|
26
|
+
return;
|
|
27
|
+
const targetUuid = target.get(traits.UUID);
|
|
28
|
+
if (!targetUuid)
|
|
29
|
+
return;
|
|
30
|
+
for (const source of world.query(PendingLinks)) {
|
|
31
|
+
if (!source.isAlive())
|
|
32
|
+
continue;
|
|
33
|
+
const queue = source.get(PendingLinks) ?? [];
|
|
34
|
+
const remaining = [];
|
|
35
|
+
let drained = false;
|
|
36
|
+
for (const entry of queue) {
|
|
37
|
+
if (entry.targetUuid === targetUuid) {
|
|
38
|
+
source.add(relations.SubEntityLink(target, { type: entry.type, indexMapping: entry.indexMapping }));
|
|
39
|
+
drained = true;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
remaining.push(entry);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!drained)
|
|
46
|
+
continue;
|
|
47
|
+
if (remaining.length === 0)
|
|
48
|
+
source.remove(PendingLinks);
|
|
49
|
+
else
|
|
50
|
+
source.set(PendingLinks, remaining);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
apply(sourceEntity, sourceUuid, relationships) {
|
|
55
|
+
const desired = new Map();
|
|
56
|
+
for (const relationship of relationships ?? []) {
|
|
57
|
+
const targetUuid = uuidBytesToString(relationship.targetUuid);
|
|
58
|
+
if (!targetUuid)
|
|
59
|
+
continue;
|
|
60
|
+
desired.set(targetUuid, {
|
|
61
|
+
targetUuid,
|
|
62
|
+
type: relationship.type,
|
|
63
|
+
indexMapping: relationship.indexMapping ?? 'index',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const previous = cache.get(sourceUuid) ?? new Map();
|
|
67
|
+
for (const targetUuid of previous.keys()) {
|
|
68
|
+
if (desired.has(targetUuid))
|
|
69
|
+
continue;
|
|
70
|
+
const target = lookupByUuid(targetUuid);
|
|
71
|
+
if (target?.isAlive()) {
|
|
72
|
+
sourceEntity.remove(relations.SubEntityLink(target));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const [targetUuid, link] of desired) {
|
|
76
|
+
const before = previous.get(targetUuid);
|
|
77
|
+
if (before?.type === link.type && before?.indexMapping === link.indexMapping) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const target = lookupByUuid(targetUuid);
|
|
81
|
+
if (!target) {
|
|
82
|
+
enqueue(sourceEntity, link);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
sourceEntity.add(relations.SubEntityLink(target, { type: link.type, indexMapping: link.indexMapping }));
|
|
86
|
+
}
|
|
87
|
+
if (desired.size === 0) {
|
|
88
|
+
cache.delete(sourceUuid);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
cache.set(sourceUuid, desired);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
forget(sourceUuid) {
|
|
95
|
+
cache.delete(sourceUuid);
|
|
96
|
+
},
|
|
97
|
+
reset() {
|
|
98
|
+
cache.clear();
|
|
99
|
+
},
|
|
100
|
+
dispose() {
|
|
101
|
+
unsubAdd();
|
|
102
|
+
cache.clear();
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
|
@@ -5,16 +5,16 @@ import { Color, Matrix4, Vector3, Vector4 } from 'three';
|
|
|
5
5
|
import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
|
|
6
6
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
7
7
|
import { UuidTool } from 'uuid-tool';
|
|
8
|
-
import { createBufferGeometry, updateBufferGeometry } from '
|
|
9
|
-
import { ColorFormat } from '
|
|
10
|
-
import { asRGB, STRIDE } from '
|
|
11
|
-
import { hierarchy, traits, useWorld } from '
|
|
12
|
-
import { createBox, createCapsule, createSphere } from '
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
8
|
+
import { createBufferGeometry, updateBufferGeometry } from '../../attribute';
|
|
9
|
+
import { ColorFormat } from '../../buf/draw/v1/metadata_pb';
|
|
10
|
+
import { asRGB, STRIDE } from '../../buffer';
|
|
11
|
+
import { hierarchy, traits, useWorld } from '../../ecs';
|
|
12
|
+
import { createBox, createCapsule, createSphere } from '../../geometry';
|
|
13
|
+
import { useCameraControls } from '../../hooks/useControls.svelte';
|
|
14
|
+
import { useLogs } from '../../hooks/useLogs.svelte';
|
|
15
|
+
import { parsePlyInput } from '../../ply';
|
|
16
|
+
import { createPose, createPoseFromFrame, poseToMatrix } from '../../transform';
|
|
16
17
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
17
|
-
import { useLogs } from './useLogs.svelte';
|
|
18
18
|
const colorUtil = new Color();
|
|
19
19
|
const rgb = { r: 0, g: 0, b: 0 };
|
|
20
20
|
const bufferTypes = {
|
|
@@ -6,8 +6,6 @@ declare const ConnectionStatus: {
|
|
|
6
6
|
type ConnectionStatusType = (typeof ConnectionStatus)[keyof typeof ConnectionStatus];
|
|
7
7
|
interface Context {
|
|
8
8
|
connectionStatus: ConnectionStatusType;
|
|
9
|
-
createRelationship: (sourceUuid: string, targetUuid: string, type: string, indexMapping?: string) => Promise<void>;
|
|
10
|
-
deleteRelationship: (sourceUuid: string, targetUuid: string) => Promise<void>;
|
|
11
9
|
}
|
|
12
10
|
export declare function provideDrawService(): void;
|
|
13
11
|
export declare function useDrawService(): Context;
|
|
@@ -5,15 +5,15 @@ import { useThrelte } from '@threlte/core';
|
|
|
5
5
|
import {} from 'koota';
|
|
6
6
|
import { getContext, setContext } from 'svelte';
|
|
7
7
|
import { UuidTool } from 'uuid-tool';
|
|
8
|
-
import { writeBufferGeometryRange } from '
|
|
9
|
-
import { DrawService } from '
|
|
10
|
-
import {
|
|
11
|
-
import { asFloat32Array, inMeters, STRIDE } from '
|
|
12
|
-
import { drawDrawing, drawTransform, updateDrawing, updateModel, updateTransform,
|
|
13
|
-
import { hierarchy, traits, useWorld } from '
|
|
14
|
-
import { useCameraControls } from '
|
|
8
|
+
import { writeBufferGeometryRange } from '../../attribute';
|
|
9
|
+
import { DrawService } from '../../buf/draw/v1/service_connect';
|
|
10
|
+
import { EntityChangeType, StreamEntityChangesResponse } from '../../buf/draw/v1/service_pb';
|
|
11
|
+
import { asFloat32Array, inMeters, STRIDE } from '../../buffer';
|
|
12
|
+
import { drawDrawing, drawTransform, updateDrawing, updateModel, updateTransform, } from '../../draw';
|
|
13
|
+
import { hierarchy, traits, useWorld } from '../../ecs';
|
|
14
|
+
import { useCameraControls } from '../../hooks/useControls.svelte';
|
|
15
|
+
import { createServerRelationships } from './serverRelationships';
|
|
15
16
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
16
|
-
import { useRelationships } from './useRelationships.svelte';
|
|
17
17
|
const DRAW_SERVICE_KEY = Symbol('draw-service-context');
|
|
18
18
|
const FLOAT32_SIZE = 4;
|
|
19
19
|
const ConnectionStatus = {
|
|
@@ -26,7 +26,7 @@ export function provideDrawService() {
|
|
|
26
26
|
const world = useWorld();
|
|
27
27
|
const cameraControls = useCameraControls();
|
|
28
28
|
const drawConnectionConfig = useDrawConnectionConfig();
|
|
29
|
-
const
|
|
29
|
+
const serverRelationships = createServerRelationships();
|
|
30
30
|
let connectionStatus = $state(ConnectionStatus.DISCONNECTED);
|
|
31
31
|
const url = $derived(drawConnectionConfig.current?.backendIP
|
|
32
32
|
? `http://${drawConnectionConfig.current.backendIP}:3030`
|
|
@@ -67,25 +67,24 @@ export function provideDrawService() {
|
|
|
67
67
|
if (changeType === EntityChangeType.ADDED) {
|
|
68
68
|
if (!transformEntities.has(uuid)) {
|
|
69
69
|
const spawned = drawTransform(world, transform, traits.DrawServiceAPI);
|
|
70
|
-
|
|
70
|
+
serverRelationships.apply(spawned.entity, uuid, spawned.relationships);
|
|
71
71
|
transformEntities.set(uuid, spawned.entity);
|
|
72
|
-
relationships.flush(uuid);
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
else if (changeType === EntityChangeType.REMOVED) {
|
|
75
|
+
serverRelationships.forget(uuid);
|
|
76
76
|
destroyTransform(uuid);
|
|
77
77
|
}
|
|
78
78
|
else if (changeType === EntityChangeType.UPDATED) {
|
|
79
79
|
const existing = transformEntities.get(uuid);
|
|
80
80
|
if (existing) {
|
|
81
81
|
const updated = updateTransform(existing, transform);
|
|
82
|
-
|
|
82
|
+
serverRelationships.apply(updated.entity, uuid, updated.relationships);
|
|
83
83
|
}
|
|
84
84
|
else {
|
|
85
85
|
const spawned = drawTransform(world, transform, traits.DrawServiceAPI);
|
|
86
|
-
|
|
86
|
+
serverRelationships.apply(spawned.entity, uuid, spawned.relationships);
|
|
87
87
|
transformEntities.set(uuid, spawned.entity);
|
|
88
|
-
relationships.flush(uuid);
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
};
|
|
@@ -155,9 +154,8 @@ export function provideDrawService() {
|
|
|
155
154
|
if (changeType === EntityChangeType.ADDED) {
|
|
156
155
|
if (!drawingEntities.has(uuid)) {
|
|
157
156
|
const spawned = drawDrawing(world, drawing, traits.DrawServiceAPI);
|
|
158
|
-
|
|
157
|
+
serverRelationships.apply(spawned.entity, uuid, spawned.relationships);
|
|
159
158
|
drawingEntities.set(uuid, spawned.entity);
|
|
160
|
-
relationships.flush(uuid);
|
|
161
159
|
if (isChunkedDrawing(drawing) && activeClient && activeSignal) {
|
|
162
160
|
const chunk = getChunkInfo(drawing);
|
|
163
161
|
if (chunk) {
|
|
@@ -169,6 +167,7 @@ export function provideDrawService() {
|
|
|
169
167
|
}
|
|
170
168
|
}
|
|
171
169
|
else if (changeType === EntityChangeType.REMOVED) {
|
|
170
|
+
serverRelationships.forget(uuid);
|
|
172
171
|
destroyDrawing(uuid);
|
|
173
172
|
}
|
|
174
173
|
else if (changeType === EntityChangeType.UPDATED) {
|
|
@@ -178,14 +177,13 @@ export function provideDrawService() {
|
|
|
178
177
|
const result = isModel
|
|
179
178
|
? updateModel(world, existing, drawing, traits.DrawServiceAPI)
|
|
180
179
|
: updateDrawing(world, existing, drawing);
|
|
181
|
-
|
|
180
|
+
serverRelationships.apply(result.entity, uuid, result.relationships);
|
|
182
181
|
drawingEntities.set(uuid, result.entity);
|
|
183
182
|
}
|
|
184
183
|
else {
|
|
185
184
|
const spawned = drawDrawing(world, drawing, traits.DrawServiceAPI);
|
|
186
|
-
|
|
185
|
+
serverRelationships.apply(spawned.entity, uuid, spawned.relationships);
|
|
187
186
|
drawingEntities.set(uuid, spawned.entity);
|
|
188
|
-
relationships.flush(uuid);
|
|
189
187
|
}
|
|
190
188
|
}
|
|
191
189
|
};
|
|
@@ -289,29 +287,6 @@ export function provideDrawService() {
|
|
|
289
287
|
}
|
|
290
288
|
}
|
|
291
289
|
};
|
|
292
|
-
const createRelationship = async (sourceUuid, targetUuid, type, indexMapping) => {
|
|
293
|
-
if (!activeClient)
|
|
294
|
-
return;
|
|
295
|
-
const rel = {
|
|
296
|
-
targetUuid: uuidStringToBytes(targetUuid),
|
|
297
|
-
type,
|
|
298
|
-
};
|
|
299
|
-
if (indexMapping !== undefined) {
|
|
300
|
-
rel.indexMapping = indexMapping;
|
|
301
|
-
}
|
|
302
|
-
await activeClient.createRelationship(new CreateRelationshipRequest({
|
|
303
|
-
sourceUuid: uuidStringToBytes(sourceUuid),
|
|
304
|
-
relationship: rel,
|
|
305
|
-
}));
|
|
306
|
-
};
|
|
307
|
-
const deleteRelationship = async (sourceUuid, targetUuid) => {
|
|
308
|
-
if (!activeClient)
|
|
309
|
-
return;
|
|
310
|
-
await activeClient.deleteRelationship(new DeleteRelationshipRequest({
|
|
311
|
-
sourceUuid: uuidStringToBytes(sourceUuid),
|
|
312
|
-
targetUuid: uuidStringToBytes(targetUuid),
|
|
313
|
-
}));
|
|
314
|
-
};
|
|
315
290
|
$effect(() => {
|
|
316
291
|
if (!url) {
|
|
317
292
|
connectionStatus = ConnectionStatus.DISCONNECTED;
|
|
@@ -340,15 +315,14 @@ export function provideDrawService() {
|
|
|
340
315
|
hierarchy.destroyEntityTree(world, entity);
|
|
341
316
|
}
|
|
342
317
|
drawingEntities.clear();
|
|
343
|
-
|
|
318
|
+
serverRelationships.reset();
|
|
344
319
|
};
|
|
345
320
|
});
|
|
321
|
+
$effect(() => () => serverRelationships.dispose());
|
|
346
322
|
setContext(DRAW_SERVICE_KEY, {
|
|
347
323
|
get connectionStatus() {
|
|
348
324
|
return connectionStatus;
|
|
349
325
|
},
|
|
350
|
-
createRelationship,
|
|
351
|
-
deleteRelationship,
|
|
352
326
|
});
|
|
353
327
|
}
|
|
354
328
|
export function useDrawService() {
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
import { Portal } from '@threlte/extras'
|
|
7
7
|
import { ElementRect } from 'runed'
|
|
8
8
|
|
|
9
|
-
import DashboardButton from '
|
|
9
|
+
import DashboardButton from '../../components/overlay/dashboard/Button.svelte'
|
|
10
|
+
import Popover from '../../components/overlay/Popover.svelte'
|
|
11
|
+
import ToggleGroup from '../../components/overlay/ToggleGroup.svelte'
|
|
10
12
|
import { useSelectedEntity } from '../../hooks/useSelection.svelte'
|
|
11
13
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
12
14
|
|
|
13
|
-
import Popover from '../overlay/Popover.svelte'
|
|
14
|
-
import ToggleGroup from '../overlay/ToggleGroup.svelte'
|
|
15
15
|
import Ellipse from './Ellipse.svelte'
|
|
16
16
|
import Lasso from './Lasso.svelte'
|
|
17
17
|
import { provideSelectionPlugin } from './useSelectionPlugin.svelte'
|
package/dist/{components/Selection/Tool.svelte.d.ts → plugins/Selection/SelectionTool.svelte.d.ts}
RENAMED
|
@@ -5,6 +5,6 @@ interface Props {
|
|
|
5
5
|
autoSelectNewEntities?: boolean;
|
|
6
6
|
children?: Snippet;
|
|
7
7
|
}
|
|
8
|
-
declare const
|
|
9
|
-
type
|
|
10
|
-
export default
|
|
8
|
+
declare const SelectionTool: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type SelectionTool = ReturnType<typeof SelectionTool>;
|
|
10
|
+
export default SelectionTool;
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
+
export { default as SelectionTool } from './Selection/SelectionTool.svelte';
|
|
2
|
+
export * as selectionTraits from './Selection/traits';
|
|
3
|
+
export { useSelectionPlugin } from './Selection/useSelectionPlugin.svelte';
|
|
4
|
+
export { default as DrawService } from './DrawService/DrawService.svelte';
|
|
1
5
|
export { default as Skybox } from './Skybox/Skybox.svelte';
|
package/dist/plugins/index.js
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
// Selection
|
|
2
|
+
export { default as SelectionTool } from './Selection/SelectionTool.svelte';
|
|
3
|
+
export * as selectionTraits from './Selection/traits';
|
|
4
|
+
export { useSelectionPlugin } from './Selection/useSelectionPlugin.svelte';
|
|
5
|
+
// DrawService
|
|
6
|
+
export { default as DrawService } from './DrawService/DrawService.svelte';
|
|
1
7
|
// Skybox
|
|
2
8
|
export { default as Skybox } from './Skybox/Skybox.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@viamrobotics/prime-core": "0.1.5",
|
|
40
40
|
"@viamrobotics/sdk": "0.69.0",
|
|
41
41
|
"@viamrobotics/svelte-sdk": "1.2.2",
|
|
42
|
+
"@viamrobotics/tweakpane-config": "0.1.1",
|
|
42
43
|
"@vitest/browser": "3.2.4",
|
|
43
44
|
"@vitest/coverage-v8": "^3.2.4",
|
|
44
45
|
"@zag-js/collapsible": "1.22.1",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|