@viamrobotics/motion-tools 1.19.0 → 1.21.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/buf/draw/v1/metadata_pb.d.ts +39 -0
- package/dist/buf/draw/v1/metadata_pb.js +55 -0
- package/dist/buf/draw/v1/service_connect.d.ts +34 -1
- package/dist/buf/draw/v1/service_connect.js +34 -1
- package/dist/buf/draw/v1/service_pb.d.ts +136 -0
- package/dist/buf/draw/v1/service_pb.js +201 -0
- package/dist/components/Entities/Arrows/ArrowGroups.svelte +1 -0
- package/dist/components/Entities/Arrows/Arrows.svelte +1 -1
- package/dist/components/Entities/Entities.svelte +1 -0
- package/dist/components/Entities/Points.svelte +23 -23
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +18 -1
- package/dist/components/FileDrop/FileDrop.svelte +8 -1
- package/dist/components/PCD.svelte +9 -1
- package/dist/components/PCD.svelte.d.ts +2 -0
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Snapshot.svelte +12 -7
- package/dist/components/overlay/AddRelationship.svelte +25 -3
- package/dist/components/overlay/Details.svelte +293 -227
- package/dist/draw.d.ts +22 -9
- package/dist/draw.js +75 -46
- package/dist/ecs/relations.js +1 -1
- package/dist/ecs/traits.d.ts +2 -0
- package/dist/ecs/traits.js +63 -0
- package/dist/hooks/useDrawService.svelte.d.ts +2 -0
- package/dist/hooks/useDrawService.svelte.js +139 -20
- package/dist/hooks/useRelationships.svelte.d.ts +12 -0
- package/dist/hooks/useRelationships.svelte.js +78 -0
- package/dist/hooks/useWorldState.svelte.js +10 -4
- package/dist/metadata.d.ts +7 -3
- package/dist/metadata.js +26 -2
- package/dist/snapshot.d.ts +6 -1
- package/dist/snapshot.js +10 -5
- package/package.json +5 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Entity } from 'koota';
|
|
2
|
+
import type { Relationship } from '../metadata';
|
|
3
|
+
export declare const provideRelationships: () => {
|
|
4
|
+
apply(entity: Entity, relationships: Relationship[] | undefined): void;
|
|
5
|
+
flush(targetUuid: string): void;
|
|
6
|
+
clear(): void;
|
|
7
|
+
};
|
|
8
|
+
export declare const useRelationships: () => {
|
|
9
|
+
apply(entity: Entity, relationships: Relationship[] | undefined): void;
|
|
10
|
+
flush(targetUuid: string): void;
|
|
11
|
+
clear(): void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { uuidBytesToString } from '../draw';
|
|
3
|
+
import { relations, traits, useQuery } from '../ecs';
|
|
4
|
+
const RELATIONSHIPS_CONTEXT_KEY = Symbol('relationships');
|
|
5
|
+
export const provideRelationships = () => {
|
|
6
|
+
const uuids = useQuery(traits.UUID);
|
|
7
|
+
const pending = new Map();
|
|
8
|
+
const addPending = (targetUuid, relationship) => {
|
|
9
|
+
const next = pending.get(targetUuid) ?? [];
|
|
10
|
+
next.push(relationship);
|
|
11
|
+
pending.set(targetUuid, next);
|
|
12
|
+
};
|
|
13
|
+
return setContext(RELATIONSHIPS_CONTEXT_KEY, {
|
|
14
|
+
apply(entity, relationships) {
|
|
15
|
+
const desired = relationships ?? [];
|
|
16
|
+
const currentTargets = entity.targetsFor(relations.SubEntityLink);
|
|
17
|
+
const desiredByUuid = new Map();
|
|
18
|
+
for (const rel of desired) {
|
|
19
|
+
const targetUUID = uuidBytesToString(rel.targetUuid);
|
|
20
|
+
if (!targetUUID)
|
|
21
|
+
continue;
|
|
22
|
+
desiredByUuid.set(targetUUID, rel);
|
|
23
|
+
}
|
|
24
|
+
for (const target of currentTargets) {
|
|
25
|
+
if (!target.isAlive())
|
|
26
|
+
continue;
|
|
27
|
+
const targetUuid = target.get(traits.UUID);
|
|
28
|
+
if (!targetUuid || !desiredByUuid.has(targetUuid)) {
|
|
29
|
+
entity.remove(relations.SubEntityLink(target));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const [uuid, relationship] of desiredByUuid) {
|
|
33
|
+
const targetEntity = uuids.current.find((e) => e.get(traits.UUID) === uuid);
|
|
34
|
+
if (!targetEntity) {
|
|
35
|
+
addPending(uuid, {
|
|
36
|
+
entity: entity,
|
|
37
|
+
type: relationship.type,
|
|
38
|
+
indexMapping: relationship.indexMapping,
|
|
39
|
+
});
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const existing = entity.get(relations.SubEntityLink(targetEntity));
|
|
43
|
+
if (existing &&
|
|
44
|
+
existing.type === relationship.type &&
|
|
45
|
+
existing.indexMapping === (relationship.indexMapping ?? 'index')) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
entity.add(relations.SubEntityLink(targetEntity, {
|
|
49
|
+
type: relationship.type,
|
|
50
|
+
indexMapping: relationship.indexMapping ?? 'index',
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
flush(targetUuid) {
|
|
55
|
+
const relationship = pending.get(targetUuid);
|
|
56
|
+
if (!relationship)
|
|
57
|
+
return;
|
|
58
|
+
pending.delete(targetUuid);
|
|
59
|
+
const targetEntity = uuids.current.find((e) => e.get(traits.UUID) === targetUuid);
|
|
60
|
+
if (!targetEntity)
|
|
61
|
+
return;
|
|
62
|
+
for (const { entity, type, indexMapping } of relationship) {
|
|
63
|
+
if (!entity.isAlive())
|
|
64
|
+
continue;
|
|
65
|
+
entity.add(relations.SubEntityLink(targetEntity, {
|
|
66
|
+
type,
|
|
67
|
+
indexMapping: indexMapping ?? 'index',
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
clear() {
|
|
72
|
+
pending.clear();
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
export const useRelationships = () => {
|
|
77
|
+
return getContext(RELATIONSHIPS_CONTEXT_KEY);
|
|
78
|
+
};
|
|
@@ -9,6 +9,7 @@ import { isPointCloud } from '../geometry';
|
|
|
9
9
|
import { metadataFromStruct } from '../metadata';
|
|
10
10
|
import { createPose } from '../transform';
|
|
11
11
|
import { usePartID } from './usePartID.svelte';
|
|
12
|
+
import { useRelationships } from './useRelationships.svelte';
|
|
12
13
|
export const provideWorldStates = () => {
|
|
13
14
|
const partID = usePartID();
|
|
14
15
|
const resourceNames = useResourceNames(() => partID.current, 'world_state_store');
|
|
@@ -83,6 +84,7 @@ const decodeWorldStateChunk = (response, fallbackStart) => {
|
|
|
83
84
|
const createWorldState = (client) => {
|
|
84
85
|
const { invalidate } = useThrelte();
|
|
85
86
|
const world = useWorld();
|
|
87
|
+
const relationships = useRelationships();
|
|
86
88
|
const entities = new Map();
|
|
87
89
|
const chunkLoader = createChunkLoader({
|
|
88
90
|
world,
|
|
@@ -105,10 +107,12 @@ const createWorldState = (client) => {
|
|
|
105
107
|
if (entities.has(transform.uuidString)) {
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
|
-
const
|
|
109
|
-
entities.set(transform.uuidString, entity);
|
|
110
|
+
const spawned = drawTransform(world, transform, traits.WorldStateStoreAPI, { removable: false });
|
|
111
|
+
entities.set(transform.uuidString, spawned.entity);
|
|
112
|
+
relationships.apply(spawned.entity, spawned.relationships);
|
|
110
113
|
const parsedMetadata = metadataFromStruct(transform.metadata?.fields);
|
|
111
|
-
chunkLoader.start(transform.uuidString, entity, parsedMetadata);
|
|
114
|
+
chunkLoader.start(transform.uuidString, spawned.entity, parsedMetadata);
|
|
115
|
+
relationships.flush(transform.uuidString);
|
|
112
116
|
if (isPointCloud(transform.physicalObject?.geometryType))
|
|
113
117
|
invalidate();
|
|
114
118
|
};
|
|
@@ -140,9 +144,11 @@ const createWorldState = (client) => {
|
|
|
140
144
|
}
|
|
141
145
|
}
|
|
142
146
|
if (metadataDirty) {
|
|
143
|
-
|
|
147
|
+
const parsedMetadata = metadataFromStruct(transform.metadata?.fields);
|
|
148
|
+
updateMetadata(entity, parsedMetadata, {
|
|
144
149
|
pointCloud: isPointCloud(transform.physicalObject?.geometryType),
|
|
145
150
|
});
|
|
151
|
+
relationships.apply(entity, parsedMetadata.relationships);
|
|
146
152
|
}
|
|
147
153
|
};
|
|
148
154
|
let initialized = false;
|
package/dist/metadata.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { PlainMessage, Struct } from '@viamrobotics/sdk';
|
|
2
|
-
import { Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
|
|
3
|
-
/** Metadata for a `Drawing` or `Transform`. */
|
|
4
|
-
export type Metadata = PlainMessage<MetadataProto
|
|
2
|
+
import { Metadata as MetadataProto, type Relationship as RelationshipProto } from './buf/draw/v1/metadata_pb';
|
|
3
|
+
/** Metadata for a `Drawing` or `Transform`. Relationships default to empty. */
|
|
4
|
+
export type Metadata = Omit<PlainMessage<MetadataProto>, 'relationships'> & {
|
|
5
|
+
relationships?: PlainMessage<MetadataProto>['relationships'];
|
|
6
|
+
};
|
|
7
|
+
/** Plain-object representation of a Relationship, usable outside proto classes. */
|
|
8
|
+
export type Relationship = PlainMessage<RelationshipProto>;
|
|
5
9
|
/** Type guard that checks whether a string is a recognised metadata wire key. */
|
|
6
10
|
export declare const isMetadataField: (key: string) => boolean;
|
|
7
11
|
/**
|
package/dist/metadata.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColorFormat, Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
|
|
1
|
+
import { ColorFormat, Metadata as MetadataProto, } from './buf/draw/v1/metadata_pb';
|
|
2
2
|
/** Type guard that checks whether a string is a recognised metadata wire key. */
|
|
3
3
|
export const isMetadataField = (key) => {
|
|
4
4
|
return (key === 'colors' ||
|
|
@@ -6,7 +6,8 @@ export const isMetadataField = (key) => {
|
|
|
6
6
|
key === 'opacities' ||
|
|
7
7
|
key === 'show_axes_helper' ||
|
|
8
8
|
key === 'invisible' ||
|
|
9
|
-
key === 'chunks'
|
|
9
|
+
key === 'chunks' ||
|
|
10
|
+
key === 'relationships');
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* Extracts typed {@link Metadata} from a proto `Struct` fields map.
|
|
@@ -77,6 +78,29 @@ export const metadataFromStruct = (fields = {}) => {
|
|
|
77
78
|
}
|
|
78
79
|
break;
|
|
79
80
|
}
|
|
81
|
+
case 'relationships': {
|
|
82
|
+
if (Array.isArray(unwrappedValue)) {
|
|
83
|
+
json.relationships = unwrappedValue
|
|
84
|
+
.filter((item) => typeof item === 'object' && item !== null)
|
|
85
|
+
.map((item) => {
|
|
86
|
+
const targetUuidStr = item['target_uuid'];
|
|
87
|
+
let targetUuid = new Uint8Array();
|
|
88
|
+
if (typeof targetUuidStr === 'string' && targetUuidStr.length > 0) {
|
|
89
|
+
const binary = atob(targetUuidStr);
|
|
90
|
+
targetUuid = new Uint8Array(binary.length);
|
|
91
|
+
for (let i = 0; i < binary.length; i++) {
|
|
92
|
+
targetUuid[i] = binary.charCodeAt(i);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
targetUuid,
|
|
97
|
+
type: typeof item['type'] === 'string' ? item['type'] : '',
|
|
98
|
+
indexMapping: typeof item['index_mapping'] === 'string' ? item['index_mapping'] : undefined,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
80
104
|
}
|
|
81
105
|
}
|
|
82
106
|
return json;
|
package/dist/snapshot.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import type { Entity, World } from 'koota';
|
|
|
2
2
|
import type { Snapshot } from './buf/draw/v1/snapshot_pb';
|
|
3
3
|
import type { Settings } from './hooks/useSettings.svelte';
|
|
4
4
|
import { type SceneMetadata } from './buf/draw/v1/scene_pb';
|
|
5
|
+
import type { Relationship } from './metadata';
|
|
6
|
+
export type SnapshotEntity = {
|
|
7
|
+
entity: Entity;
|
|
8
|
+
relationships: Relationship[] | undefined;
|
|
9
|
+
};
|
|
5
10
|
/**
|
|
6
11
|
* Merges scene-level metadata (grid, camera, point/line settings) into the
|
|
7
12
|
* current viewer settings. Millimeter values from the proto are converted
|
|
@@ -18,4 +23,4 @@ export declare const applySceneMetadata: (settings: Settings, metadata: SceneMet
|
|
|
18
23
|
*
|
|
19
24
|
* @returns The spawned entities
|
|
20
25
|
*/
|
|
21
|
-
export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) =>
|
|
26
|
+
export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) => SnapshotEntity[];
|
package/dist/snapshot.js
CHANGED
|
@@ -58,13 +58,18 @@ export const spawnSnapshotEntities = (world, snapshot) => {
|
|
|
58
58
|
const entities = [];
|
|
59
59
|
const options = { removable: true, showAxesHelper: false };
|
|
60
60
|
for (const transform of snapshot.transforms) {
|
|
61
|
-
|
|
61
|
+
const spawned = drawTransform(world, transform, traits.SnapshotAPI, options);
|
|
62
|
+
entities.push({
|
|
63
|
+
entity: spawned.entity,
|
|
64
|
+
relationships: spawned.relationships,
|
|
65
|
+
});
|
|
62
66
|
}
|
|
63
67
|
for (const drawing of snapshot.drawings) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
const spawned = drawDrawing(world, drawing, traits.SnapshotAPI, options);
|
|
69
|
+
entities.push({
|
|
70
|
+
entity: spawned.entity,
|
|
71
|
+
relationships: spawned.relationships,
|
|
72
|
+
});
|
|
68
73
|
}
|
|
69
74
|
return entities;
|
|
70
75
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@types/bun": "1.2.21",
|
|
33
33
|
"@types/earcut": "^3.0.0",
|
|
34
34
|
"@types/lodash-es": "4.17.12",
|
|
35
|
+
"@types/node": "^25.6.0",
|
|
35
36
|
"@types/three": "0.183.1",
|
|
36
37
|
"@typescript-eslint/eslint-plugin": "8.56.1",
|
|
37
38
|
"@typescript-eslint/parser": "8.56.1",
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
"runed": "0.31.1",
|
|
66
67
|
"svelte": "5.55.0",
|
|
67
68
|
"svelte-check": "4.4.5",
|
|
69
|
+
"svelte-tweakpane-ui": "^1.5.16",
|
|
68
70
|
"svelte-virtuallists": "1.4.2",
|
|
69
71
|
"tailwindcss": "4.1.13",
|
|
70
72
|
"three": "0.183.2",
|
|
@@ -104,6 +106,7 @@
|
|
|
104
106
|
"lucide-svelte": ">=0.511",
|
|
105
107
|
"runed": ">=0.28",
|
|
106
108
|
"svelte": ">=5",
|
|
109
|
+
"svelte-tweakpane-ui": ">=1.5",
|
|
107
110
|
"svelte-virtuallists": ">=1"
|
|
108
111
|
},
|
|
109
112
|
"engines": {
|
|
@@ -123,7 +126,7 @@
|
|
|
123
126
|
},
|
|
124
127
|
"repository": {
|
|
125
128
|
"type": "git",
|
|
126
|
-
"url": "git+https://github.com/
|
|
129
|
+
"url": "git+https://github.com/viamrobotics/visualization.git"
|
|
127
130
|
},
|
|
128
131
|
"files": [
|
|
129
132
|
"dist",
|