@viamrobotics/motion-tools 1.16.0 → 1.18.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/attribute.d.ts +3 -2
- package/dist/attribute.js +24 -16
- package/dist/buf/draw/v1/drawing_pb.d.ts +33 -16
- package/dist/buf/draw/v1/drawing_pb.js +35 -17
- package/dist/buf/draw/v1/metadata_pb.d.ts +44 -3
- package/dist/buf/draw/v1/metadata_pb.js +54 -3
- package/dist/buf/draw/v1/scene_pb.d.ts +6 -6
- package/dist/buf/draw/v1/scene_pb.js +7 -7
- package/dist/buffer.d.ts +54 -45
- package/dist/buffer.js +91 -57
- package/dist/color.d.ts +1 -2
- package/dist/color.js +5 -12
- package/dist/components/App.svelte +18 -3
- package/dist/components/App.svelte.d.ts +15 -2
- package/dist/components/Entities/Arrows/ArrowGroups.svelte +5 -6
- package/dist/components/Entities/Arrows/Arrows.svelte +9 -0
- package/dist/components/Entities/Entities.svelte +18 -1
- package/dist/components/Entities/Frame.svelte +7 -1
- package/dist/components/Entities/GLTF.svelte +13 -2
- package/dist/components/Entities/Line.svelte +46 -18
- package/dist/components/Entities/LineDots.svelte +38 -8
- package/dist/components/Entities/LineDots.svelte.d.ts +2 -2
- package/dist/components/Entities/LineGeometry.svelte +2 -1
- package/dist/components/Entities/LineGeometry.svelte.d.ts +2 -0
- package/dist/components/Entities/Mesh.svelte +8 -1
- package/dist/components/Entities/Points.svelte +22 -11
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +6 -2
- package/dist/components/FileDrop/FileDrop.svelte +5 -1
- package/dist/components/KeyboardControls.svelte +2 -10
- package/dist/components/PCD.svelte +11 -4
- package/dist/components/PCD.svelte.d.ts +3 -1
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Selected.svelte +2 -12
- package/dist/components/Selection/Ellipse.svelte +2 -0
- package/dist/components/Selection/Lasso.svelte +2 -0
- package/dist/components/Selection/Tool.svelte +7 -56
- package/dist/components/Selection/Tool.svelte.d.ts +2 -2
- package/dist/components/Selection/useSelectionPlugin.svelte.d.ts +8 -0
- package/dist/components/Selection/useSelectionPlugin.svelte.js +24 -0
- package/dist/components/Snapshot.svelte +4 -2
- package/dist/components/overlay/AddRelationship.svelte +1 -2
- package/dist/components/overlay/AddRelationship.svelte.d.ts +1 -1
- package/dist/components/overlay/Details.svelte +12 -12
- package/dist/components/overlay/Details.svelte.d.ts +8 -1
- package/dist/components/overlay/settings/Settings.svelte +8 -1
- package/dist/components/xr/XR.svelte +1 -1
- package/dist/draw.d.ts +13 -0
- package/dist/draw.js +428 -0
- package/dist/ecs/traits.d.ts +31 -13
- package/dist/ecs/traits.js +25 -8
- package/dist/geometry.js +3 -0
- package/dist/hooks/useDrawAPI.svelte.js +61 -24
- package/dist/hooks/useDrawService.svelte.d.ts +12 -0
- package/dist/hooks/useDrawService.svelte.js +240 -0
- package/dist/hooks/usePointcloudObjects.svelte.js +7 -2
- package/dist/hooks/usePointclouds.svelte.js +7 -2
- package/dist/hooks/useSettings.svelte.d.ts +2 -1
- package/dist/hooks/useSettings.svelte.js +1 -1
- package/dist/hooks/useWorldState.svelte.js +5 -52
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +2 -0
- package/dist/loaders/pcd/index.d.ts +1 -1
- package/dist/loaders/pcd/messages.d.ts +2 -2
- package/dist/loaders/pcd/worker.inline.d.ts +1 -1
- package/dist/loaders/pcd/worker.inline.js +229 -187
- package/dist/loaders/pcd/worker.js +2 -2
- package/dist/metadata.d.ts +9 -15
- package/dist/metadata.js +45 -9
- package/dist/plugins/bvh.svelte.js +6 -2
- package/dist/snapshot.d.ts +3 -9
- package/dist/snapshot.js +11 -204
- package/dist/three/InstancedArrows/InstancedArrows.js +3 -2
- package/package.json +14 -11
- package/dist/components/xr/Hands.svelte +0 -23
- package/dist/components/xr/Hands.svelte.d.ts +0 -18
package/dist/ecs/traits.js
CHANGED
|
@@ -54,7 +54,12 @@ export const Material = trait({
|
|
|
54
54
|
export const DepthTest = trait(() => true);
|
|
55
55
|
export const Arrow = trait(() => true);
|
|
56
56
|
export const Positions = trait(() => new Float32Array());
|
|
57
|
+
/** Per-vertex RGB colors packed as [r, g, b, ...], stride of 3, values 0-255. */
|
|
57
58
|
export const Colors = trait(() => new Uint8Array());
|
|
59
|
+
/**
|
|
60
|
+
* Per-vertex opacity values packed as uint8 (0-255).
|
|
61
|
+
*/
|
|
62
|
+
export const Opacities = trait(() => new Uint8Array());
|
|
58
63
|
export const Instances = trait({
|
|
59
64
|
count: 0,
|
|
60
65
|
});
|
|
@@ -77,12 +82,7 @@ export const Capsule = trait({ l: 200, r: 50 });
|
|
|
77
82
|
* A sphere, in mm
|
|
78
83
|
*/
|
|
79
84
|
export const Sphere = trait({ r: 200 });
|
|
80
|
-
export const PointColor = trait({ r: 0, g: 0, b: 0 });
|
|
81
|
-
/** format [x, y, z, ...] */
|
|
82
|
-
export const LinePositions = trait(() => new Float32Array());
|
|
83
85
|
export const BufferGeometry = trait(() => new ThreeBufferGeometry());
|
|
84
|
-
/** format [r, g, b, ...] */
|
|
85
|
-
export const VertexColors = trait(() => new Float32Array());
|
|
86
86
|
export const GLTF = trait(() => ({
|
|
87
87
|
source: { url: '' },
|
|
88
88
|
animationName: '',
|
|
@@ -91,6 +91,7 @@ export const Scale = trait({ x: 1, y: 1, z: 1 });
|
|
|
91
91
|
export const FramesAPI = trait(() => true);
|
|
92
92
|
export const GeometriesAPI = trait(() => true);
|
|
93
93
|
export const DrawAPI = trait(() => true);
|
|
94
|
+
export const DrawServiceAPI = trait(() => true);
|
|
94
95
|
export const WorldStateStoreAPI = trait(() => true);
|
|
95
96
|
export const SnapshotAPI = trait(() => true);
|
|
96
97
|
/**
|
|
@@ -98,16 +99,32 @@ export const SnapshotAPI = trait(() => true);
|
|
|
98
99
|
*/
|
|
99
100
|
export const DroppedFile = trait(() => true);
|
|
100
101
|
export const ShowAxesHelper = trait(() => true);
|
|
101
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Marker trait for entities that should be rendered in screen space (CSS pixels)
|
|
104
|
+
*/
|
|
105
|
+
export const ScreenSpace = trait(() => true);
|
|
102
106
|
/**
|
|
103
107
|
* Point size, in mm
|
|
104
108
|
*/
|
|
105
|
-
export const PointSize = trait(() =>
|
|
109
|
+
export const PointSize = trait(() => 5);
|
|
110
|
+
/**
|
|
111
|
+
* Line positions, format [x, y, z, ...]
|
|
112
|
+
*/
|
|
113
|
+
export const LinePositions = trait(() => new Float32Array());
|
|
106
114
|
/**
|
|
107
|
-
* Line width, in mm
|
|
115
|
+
* Line width, in mm when in world units, or CSS pixels when in screen space
|
|
108
116
|
*/
|
|
109
117
|
export const LineWidth = trait(() => 5);
|
|
118
|
+
/**
|
|
119
|
+
* Dot colors for line vertices, format [r, g, b, a, ...]
|
|
120
|
+
*/
|
|
121
|
+
export const DotColors = trait(() => new Uint8Array());
|
|
122
|
+
/**
|
|
123
|
+
* Dot size for line vertices, in mm when in world units, or CSS pixels when in screen space
|
|
124
|
+
*/
|
|
125
|
+
export const DotSize = trait(() => 10);
|
|
110
126
|
export const ReferenceFrame = trait(() => true);
|
|
127
|
+
export const SelectToolInteractionLayer = trait(() => true);
|
|
111
128
|
/**
|
|
112
129
|
* This entity can be safetly removed from the scene by the user
|
|
113
130
|
*/
|
package/dist/geometry.js
CHANGED
|
@@ -6,7 +6,8 @@ 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
8
|
import { createBufferGeometry, updateBufferGeometry } from '../attribute';
|
|
9
|
-
import {
|
|
9
|
+
import { ColorFormat } from '../buf/draw/v1/metadata_pb';
|
|
10
|
+
import { asRGB, STRIDE } from '../buffer';
|
|
10
11
|
import { traits, useWorld } from '../ecs';
|
|
11
12
|
import { createBox, createCapsule, createSphere } from '../geometry';
|
|
12
13
|
import { parsePlyInput } from '../ply';
|
|
@@ -15,6 +16,7 @@ import { useCameraControls } from './useControls.svelte';
|
|
|
15
16
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
16
17
|
import { useLogs } from './useLogs.svelte';
|
|
17
18
|
const colorUtil = new Color();
|
|
19
|
+
const rgb = { r: 0, g: 0, b: 0 };
|
|
18
20
|
const bufferTypes = {
|
|
19
21
|
DRAW_POINTS: 0,
|
|
20
22
|
DRAW_POSES: 1,
|
|
@@ -215,9 +217,9 @@ export const provideDrawAPI = () => {
|
|
|
215
217
|
const nPoints = reader.read();
|
|
216
218
|
const nColors = reader.read();
|
|
217
219
|
const arrowHeadAtPose = reader.read();
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
|
|
220
|
+
const positions = reader.readF32Array(nPoints * STRIDE.ARROWS);
|
|
221
|
+
const rawColors = reader.readU8Array(nColors * STRIDE.COLORS_RGB);
|
|
222
|
+
world.spawn(traits.Name(`Arrow group ${++poseIndex}`), traits.Positions(positions), nColors === 1 ? traits.Color(asRGB(rawColors, rgb)) : traits.Colors(rawColors), traits.Arrows({ headAtPose: arrowHeadAtPose === 1 }), traits.DrawAPI, traits.Removable);
|
|
221
223
|
};
|
|
222
224
|
const drawPoints = async (reader) => {
|
|
223
225
|
// Read label length
|
|
@@ -230,41 +232,66 @@ export const provideDrawAPI = () => {
|
|
|
230
232
|
const nPoints = reader.readU32();
|
|
231
233
|
const nColors = reader.readU32();
|
|
232
234
|
// Read default color
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
235
|
+
const r = reader.read();
|
|
236
|
+
const g = reader.read();
|
|
237
|
+
const b = reader.read();
|
|
238
|
+
// Normalize to uint8 immediately so the rest of the function works in a single color space.
|
|
239
|
+
const defaultColor = r > -1
|
|
240
|
+
? new Uint8Array([Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)])
|
|
241
|
+
: undefined;
|
|
236
242
|
const nPointsElements = nPoints * 3;
|
|
237
243
|
const positions = reader.readF32Array(nPointsElements);
|
|
238
244
|
const nColorsElements = nColors * 3;
|
|
239
245
|
const rawColors = reader.readU8Array(nColorsElements);
|
|
240
|
-
let
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
let vertexColors = undefined;
|
|
247
|
+
let uniformColor = undefined;
|
|
248
|
+
if (nColors > 1 && nColors >= nPoints) {
|
|
249
|
+
vertexColors = rawColors;
|
|
250
|
+
}
|
|
251
|
+
else if (nColors > 1) {
|
|
252
|
+
vertexColors = new Uint8Array(nPointsElements);
|
|
253
|
+
vertexColors.set(rawColors);
|
|
254
|
+
if (defaultColor) {
|
|
255
|
+
for (let i = nColors; i < nPoints; i++) {
|
|
256
|
+
const offset = i * STRIDE.COLORS_RGB;
|
|
257
|
+
vertexColors[offset] = defaultColor[0];
|
|
258
|
+
vertexColors[offset + 1] = defaultColor[1];
|
|
259
|
+
vertexColors[offset + 2] = defaultColor[2];
|
|
260
|
+
}
|
|
250
261
|
}
|
|
251
262
|
}
|
|
252
263
|
else if (nColors === 1) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
uniformColor = new Uint8Array([rawColors[0], rawColors[1], rawColors[2]]);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
uniformColor = defaultColor;
|
|
256
268
|
}
|
|
257
269
|
const entities = world.query(traits.DrawAPI);
|
|
258
270
|
const entity = entities.find((entity) => entity.get(traits.Name) === label);
|
|
259
271
|
if (entity) {
|
|
260
272
|
const geometry = entity.get(traits.BufferGeometry);
|
|
261
273
|
if (geometry) {
|
|
262
|
-
updateBufferGeometry(geometry, positions,
|
|
274
|
+
updateBufferGeometry(geometry, positions, {
|
|
275
|
+
colors: vertexColors,
|
|
276
|
+
colorFormat: ColorFormat.RGB,
|
|
277
|
+
});
|
|
263
278
|
return;
|
|
264
279
|
}
|
|
265
280
|
}
|
|
266
|
-
const geometry = createBufferGeometry(positions,
|
|
267
|
-
|
|
281
|
+
const geometry = createBufferGeometry(positions, {
|
|
282
|
+
colors: vertexColors,
|
|
283
|
+
colorFormat: ColorFormat.RGB,
|
|
284
|
+
});
|
|
285
|
+
const spawnTraits = [
|
|
286
|
+
traits.Name(label),
|
|
287
|
+
traits.BufferGeometry(geometry),
|
|
288
|
+
traits.Points,
|
|
289
|
+
traits.DrawAPI,
|
|
290
|
+
traits.Removable,
|
|
291
|
+
];
|
|
292
|
+
if (uniformColor)
|
|
293
|
+
spawnTraits.push(traits.Color(asRGB(uniformColor, rgb)));
|
|
294
|
+
world.spawn(...spawnTraits);
|
|
268
295
|
};
|
|
269
296
|
const drawLine = async (reader) => {
|
|
270
297
|
// Read label length
|
|
@@ -292,7 +319,17 @@ export const provideDrawAPI = () => {
|
|
|
292
319
|
points[i + 1] = reader.read();
|
|
293
320
|
points[i + 2] = reader.read();
|
|
294
321
|
}
|
|
295
|
-
|
|
322
|
+
const lineColors = new Uint8Array([
|
|
323
|
+
Math.round(r * 255),
|
|
324
|
+
Math.round(g * 255),
|
|
325
|
+
Math.round(b * 255),
|
|
326
|
+
]);
|
|
327
|
+
const dotColors = new Uint8Array([
|
|
328
|
+
Math.round(dotR * 255),
|
|
329
|
+
Math.round(dotG * 255),
|
|
330
|
+
Math.round(dotB * 255),
|
|
331
|
+
]);
|
|
332
|
+
world.spawn(traits.Name(label), traits.Color(asRGB(lineColors, rgb)), traits.Opacity(1), traits.LinePositions(points), traits.DotColors(dotColors), traits.DrawAPI, traits.Removable);
|
|
296
333
|
};
|
|
297
334
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
298
335
|
const drawGeometries = (geometries, colors, parent) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const ConnectionStatus: {
|
|
2
|
+
readonly CONNECTED: "connected";
|
|
3
|
+
readonly DISCONNECTED: "disconnected";
|
|
4
|
+
readonly CONNECTING: "connecting";
|
|
5
|
+
};
|
|
6
|
+
type ConnectionStatusType = (typeof ConnectionStatus)[keyof typeof ConnectionStatus];
|
|
7
|
+
interface Context {
|
|
8
|
+
connectionStatus: ConnectionStatusType;
|
|
9
|
+
}
|
|
10
|
+
export declare function provideDrawService(): void;
|
|
11
|
+
export declare function useDrawService(): Context;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { FieldMask } from '@bufbuild/protobuf';
|
|
2
|
+
import { createClient } from '@connectrpc/connect';
|
|
3
|
+
import { createConnectTransport } from '@connectrpc/connect-web';
|
|
4
|
+
import { useThrelte } from '@threlte/core';
|
|
5
|
+
import {} from 'koota';
|
|
6
|
+
import { getContext, setContext } from 'svelte';
|
|
7
|
+
import { UuidTool } from 'uuid-tool';
|
|
8
|
+
import { DrawService } from '../buf/draw/v1/service_connect';
|
|
9
|
+
import { EntityChangeType, StreamEntityChangesResponse } from '../buf/draw/v1/service_pb';
|
|
10
|
+
import { drawDrawing, drawTransform, updateDrawing, updateTransform, } from '../draw';
|
|
11
|
+
import { traits, useWorld } from '../ecs';
|
|
12
|
+
import { useCameraControls } from './useControls.svelte';
|
|
13
|
+
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
14
|
+
const DRAW_SERVICE_KEY = Symbol('draw-service-context');
|
|
15
|
+
const ConnectionStatus = {
|
|
16
|
+
CONNECTED: 'connected',
|
|
17
|
+
DISCONNECTED: 'disconnected',
|
|
18
|
+
CONNECTING: 'connecting',
|
|
19
|
+
};
|
|
20
|
+
export function provideDrawService() {
|
|
21
|
+
const { invalidate } = useThrelte();
|
|
22
|
+
const world = useWorld();
|
|
23
|
+
const cameraControls = useCameraControls();
|
|
24
|
+
const drawConnectionConfig = useDrawConnectionConfig();
|
|
25
|
+
let connectionStatus = $state(ConnectionStatus.DISCONNECTED);
|
|
26
|
+
const url = $derived(drawConnectionConfig.current?.backendIP
|
|
27
|
+
? `http://${drawConnectionConfig.current.backendIP}:3030`
|
|
28
|
+
: undefined);
|
|
29
|
+
const transformEntities = new Map();
|
|
30
|
+
const drawingEntities = new Map();
|
|
31
|
+
let pendingEvents = [];
|
|
32
|
+
let flushScheduled = false;
|
|
33
|
+
const destroyTransform = (uuidStr) => {
|
|
34
|
+
const entity = transformEntities.get(uuidStr);
|
|
35
|
+
if (!entity)
|
|
36
|
+
return;
|
|
37
|
+
if (world.has(entity))
|
|
38
|
+
entity.destroy();
|
|
39
|
+
transformEntities.delete(uuidStr);
|
|
40
|
+
};
|
|
41
|
+
const destroyDrawing = (uuidStr) => {
|
|
42
|
+
const entities = drawingEntities.get(uuidStr);
|
|
43
|
+
if (!entities)
|
|
44
|
+
return;
|
|
45
|
+
for (const entity of entities) {
|
|
46
|
+
if (world.has(entity))
|
|
47
|
+
entity.destroy();
|
|
48
|
+
}
|
|
49
|
+
drawingEntities.delete(uuidStr);
|
|
50
|
+
};
|
|
51
|
+
const processEvent = (event) => {
|
|
52
|
+
const { changeType, entity, uuid } = event;
|
|
53
|
+
if (entity.case === 'transform') {
|
|
54
|
+
processTransformEvent(entity.value, changeType, uuid);
|
|
55
|
+
}
|
|
56
|
+
else if (entity.case === 'drawing') {
|
|
57
|
+
processDrawingEvent(entity.value, changeType, uuid);
|
|
58
|
+
}
|
|
59
|
+
invalidate();
|
|
60
|
+
};
|
|
61
|
+
const processTransformEvent = (transform, changeType, uuid) => {
|
|
62
|
+
if (changeType === EntityChangeType.ADDED) {
|
|
63
|
+
if (!transformEntities.has(uuid)) {
|
|
64
|
+
const spawned = drawTransform(world, transform, traits.DrawServiceAPI);
|
|
65
|
+
transformEntities.set(uuid, spawned);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (changeType === EntityChangeType.REMOVED) {
|
|
69
|
+
destroyTransform(uuid);
|
|
70
|
+
}
|
|
71
|
+
else if (changeType === EntityChangeType.UPDATED) {
|
|
72
|
+
const existing = transformEntities.get(uuid);
|
|
73
|
+
if (existing) {
|
|
74
|
+
updateTransform(existing, transform);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const spawned = drawTransform(world, transform, traits.DrawServiceAPI);
|
|
78
|
+
transformEntities.set(uuid, spawned);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const processDrawingEvent = (drawing, changeType, uuid) => {
|
|
83
|
+
if (changeType === EntityChangeType.ADDED) {
|
|
84
|
+
if (!drawingEntities.has(uuid)) {
|
|
85
|
+
const spawned = drawDrawing(world, drawing, traits.DrawServiceAPI);
|
|
86
|
+
drawingEntities.set(uuid, spawned);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (changeType === EntityChangeType.REMOVED) {
|
|
90
|
+
destroyDrawing(uuid);
|
|
91
|
+
}
|
|
92
|
+
else if (changeType === EntityChangeType.UPDATED) {
|
|
93
|
+
const existing = drawingEntities.get(uuid);
|
|
94
|
+
if (existing) {
|
|
95
|
+
const next = updateDrawing(world, existing, drawing, traits.DrawServiceAPI);
|
|
96
|
+
drawingEntities.set(uuid, next);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const spawned = drawDrawing(world, drawing, traits.DrawServiceAPI);
|
|
100
|
+
drawingEntities.set(uuid, spawned);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const applyEvents = (events) => {
|
|
105
|
+
const eventsByUUID = new Map();
|
|
106
|
+
for (const event of events) {
|
|
107
|
+
const existing = eventsByUUID.get(event.uuid);
|
|
108
|
+
if (!existing) {
|
|
109
|
+
eventsByUUID.set(event.uuid, event);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
switch (event.changeType) {
|
|
113
|
+
case EntityChangeType.REMOVED: {
|
|
114
|
+
eventsByUUID.set(event.uuid, event);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case EntityChangeType.ADDED: {
|
|
118
|
+
if (existing.changeType !== EntityChangeType.REMOVED) {
|
|
119
|
+
eventsByUUID.set(event.uuid, event);
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case EntityChangeType.UPDATED: {
|
|
124
|
+
if (existing.changeType === EntityChangeType.ADDED) {
|
|
125
|
+
existing.entity = event.entity;
|
|
126
|
+
}
|
|
127
|
+
else if (existing.changeType === EntityChangeType.UPDATED) {
|
|
128
|
+
existing.updatedFields ??= new FieldMask();
|
|
129
|
+
const paths = event.updatedFields?.paths ?? [];
|
|
130
|
+
for (const path of paths) {
|
|
131
|
+
if (!existing.updatedFields.paths.includes(path)) {
|
|
132
|
+
existing.updatedFields.paths.push(path);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
existing.entity = event.entity;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
eventsByUUID.set(event.uuid, event);
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const event of eventsByUUID.values()) {
|
|
145
|
+
processEvent(event);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const scheduleFlush = () => {
|
|
149
|
+
if (flushScheduled)
|
|
150
|
+
return;
|
|
151
|
+
flushScheduled = true;
|
|
152
|
+
requestAnimationFrame(() => {
|
|
153
|
+
flushScheduled = false;
|
|
154
|
+
const toApply = pendingEvents;
|
|
155
|
+
pendingEvents = [];
|
|
156
|
+
applyEvents(toApply);
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
const streamEntityChanges = async (client, signal) => {
|
|
160
|
+
try {
|
|
161
|
+
for await (const response of client.streamEntityChanges({}, { signal })) {
|
|
162
|
+
connectionStatus = ConnectionStatus.CONNECTED;
|
|
163
|
+
const { entity } = response;
|
|
164
|
+
if (!entity.case)
|
|
165
|
+
continue;
|
|
166
|
+
const uuid = UuidTool.toString([...(entity.value.uuid ?? [])]);
|
|
167
|
+
pendingEvents.push({
|
|
168
|
+
uuid,
|
|
169
|
+
changeType: response.changeType,
|
|
170
|
+
entity,
|
|
171
|
+
updatedFields: response.updatedFields,
|
|
172
|
+
});
|
|
173
|
+
scheduleFlush();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (!signal.aborted) {
|
|
178
|
+
console.error('Draw service entity stream error:', error);
|
|
179
|
+
connectionStatus = ConnectionStatus.DISCONNECTED;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const streamSceneChanges = async (client, signal) => {
|
|
184
|
+
try {
|
|
185
|
+
for await (const response of client.streamSceneChanges({}, { signal })) {
|
|
186
|
+
const { sceneMetadata } = response;
|
|
187
|
+
if (!sceneMetadata)
|
|
188
|
+
continue;
|
|
189
|
+
if (sceneMetadata.sceneCamera?.position && sceneMetadata.sceneCamera?.lookAt) {
|
|
190
|
+
const { position, lookAt, animated } = sceneMetadata.sceneCamera;
|
|
191
|
+
cameraControls.setPose({
|
|
192
|
+
position: [position.x * 0.001, position.y * 0.001, position.z * 0.001],
|
|
193
|
+
lookAt: [lookAt.x * 0.001, lookAt.y * 0.001, lookAt.z * 0.001],
|
|
194
|
+
}, animated ?? false);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (!signal.aborted) {
|
|
200
|
+
console.error('Draw service scene stream error:', error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
$effect(() => {
|
|
205
|
+
if (!url) {
|
|
206
|
+
connectionStatus = ConnectionStatus.DISCONNECTED;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
connectionStatus = ConnectionStatus.CONNECTING;
|
|
211
|
+
const transport = createConnectTransport({ baseUrl: url });
|
|
212
|
+
const client = createClient(DrawService, transport);
|
|
213
|
+
void streamEntityChanges(client, controller.signal);
|
|
214
|
+
void streamSceneChanges(client, controller.signal);
|
|
215
|
+
return () => {
|
|
216
|
+
controller.abort();
|
|
217
|
+
connectionStatus = ConnectionStatus.DISCONNECTED;
|
|
218
|
+
for (const entity of transformEntities.values()) {
|
|
219
|
+
if (world.has(entity))
|
|
220
|
+
entity.destroy();
|
|
221
|
+
}
|
|
222
|
+
transformEntities.clear();
|
|
223
|
+
for (const entities of drawingEntities.values()) {
|
|
224
|
+
for (const entity of entities) {
|
|
225
|
+
if (world.has(entity))
|
|
226
|
+
entity.destroy();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
drawingEntities.clear();
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
setContext(DRAW_SERVICE_KEY, {
|
|
233
|
+
get connectionStatus() {
|
|
234
|
+
return connectionStatus;
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
export function useDrawService() {
|
|
239
|
+
return getContext(DRAW_SERVICE_KEY);
|
|
240
|
+
}
|
|
@@ -2,6 +2,7 @@ import { VisionClient } from '@viamrobotics/sdk';
|
|
|
2
2
|
import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import { getContext, setContext, untrack } from 'svelte';
|
|
4
4
|
import { createBufferGeometry, updateBufferGeometry } from '../attribute';
|
|
5
|
+
import { ColorFormat } from '../buf/draw/v1/metadata_pb';
|
|
5
6
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
6
7
|
import { traits, useWorld } from '../ecs';
|
|
7
8
|
import { updateGeometryTrait } from '../ecs/traits';
|
|
@@ -129,14 +130,18 @@ export const providePointcloudObjects = (partID) => {
|
|
|
129
130
|
return;
|
|
130
131
|
}
|
|
131
132
|
const existing = entities.get(pointcloudLabel);
|
|
133
|
+
const metadata = {
|
|
134
|
+
colors,
|
|
135
|
+
colorFormat: ColorFormat.RGB,
|
|
136
|
+
};
|
|
132
137
|
if (existing) {
|
|
133
138
|
const geometry = existing.get(traits.BufferGeometry);
|
|
134
139
|
if (geometry) {
|
|
135
|
-
updateBufferGeometry(geometry, positions,
|
|
140
|
+
updateBufferGeometry(geometry, positions, metadata);
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
else {
|
|
139
|
-
const geometry = createBufferGeometry(positions,
|
|
144
|
+
const geometry = createBufferGeometry(positions, metadata);
|
|
140
145
|
const entity = world.spawn(traits.Name(pointcloudLabel), traits.BufferGeometry(geometry), traits.Points);
|
|
141
146
|
entities.set(pointcloudLabel, entity);
|
|
142
147
|
}
|
|
@@ -2,6 +2,7 @@ import { CameraClient } from '@viamrobotics/sdk';
|
|
|
2
2
|
import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import { getContext, setContext, untrack } from 'svelte';
|
|
4
4
|
import { createBufferGeometry, updateBufferGeometry } from '../attribute';
|
|
5
|
+
import { ColorFormat } from '../buf/draw/v1/metadata_pb';
|
|
5
6
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
6
7
|
import { traits, useWorld } from '../ecs';
|
|
7
8
|
import { parsePcdInWorker } from '../loaders/pcd';
|
|
@@ -102,14 +103,18 @@ export const providePointclouds = (partID) => {
|
|
|
102
103
|
return;
|
|
103
104
|
}
|
|
104
105
|
const existing = entities.get(queryKey);
|
|
106
|
+
const metadata = {
|
|
107
|
+
colors,
|
|
108
|
+
colorFormat: ColorFormat.RGB,
|
|
109
|
+
};
|
|
105
110
|
if (existing) {
|
|
106
111
|
const geometry = existing.get(traits.BufferGeometry);
|
|
107
112
|
if (geometry) {
|
|
108
|
-
updateBufferGeometry(geometry, positions,
|
|
113
|
+
updateBufferGeometry(geometry, positions, metadata);
|
|
109
114
|
return;
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
|
-
const geometry = createBufferGeometry(positions,
|
|
117
|
+
const geometry = createBufferGeometry(positions, metadata);
|
|
113
118
|
const entity = world.spawn(traits.Parent(name), traits.Name(`${name} pointcloud`), traits.BufferGeometry(geometry), traits.Points);
|
|
114
119
|
entities.set(queryKey, entity);
|
|
115
120
|
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorRepresentation } from 'three';
|
|
1
2
|
export interface Settings {
|
|
2
3
|
cameraMode: 'orthographic' | 'perspective';
|
|
3
4
|
interactionMode: 'navigate' | 'measure' | 'select';
|
|
@@ -16,7 +17,7 @@ export interface Settings {
|
|
|
16
17
|
gridSectionSize: number;
|
|
17
18
|
gridFadeDistance: number;
|
|
18
19
|
pointSize: number;
|
|
19
|
-
pointColor:
|
|
20
|
+
pointColor: ColorRepresentation;
|
|
20
21
|
lineWidth: number;
|
|
21
22
|
lineDotSize: number;
|
|
22
23
|
enableMeasureAxisX: boolean;
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { useThrelte } from '@threlte/core';
|
|
2
2
|
import { TransformChangeType, WorldStateStoreClient, } from '@viamrobotics/sdk';
|
|
3
3
|
import { createResourceClient, createResourceQuery, createResourceStream, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
4
|
-
import {
|
|
5
|
-
import { createBufferGeometry } from '../attribute';
|
|
6
|
-
import { asColor, asOpacity, isPerVertexColors, STRIDE } from '../buffer';
|
|
4
|
+
import { drawTransform } from '../draw';
|
|
7
5
|
import { traits, useWorld } from '../ecs';
|
|
8
6
|
import { createBox, createCapsule, createSphere } from '../geometry';
|
|
9
|
-
import {
|
|
10
|
-
import { parseMetadata } from '../metadata';
|
|
7
|
+
import { isPointCloud } from '../geometry';
|
|
11
8
|
import { parsePlyInput } from '../ply';
|
|
12
9
|
import { createPose } from '../transform';
|
|
13
10
|
import { usePartID } from './usePartID.svelte';
|
|
14
|
-
const colorUtil = new Color();
|
|
15
11
|
export const provideWorldStates = () => {
|
|
16
12
|
const partID = usePartID();
|
|
17
13
|
const resourceNames = useResourceNames(() => partID.current, 'world_state_store');
|
|
@@ -36,53 +32,10 @@ const createWorldState = (client) => {
|
|
|
36
32
|
if (entities.has(transform.uuidString)) {
|
|
37
33
|
return;
|
|
38
34
|
}
|
|
39
|
-
const
|
|
40
|
-
const pose = createPose(transform.poseInObserverFrame?.pose);
|
|
41
|
-
const entityTraits = [];
|
|
42
|
-
const parent = transform.poseInObserverFrame?.referenceFrame;
|
|
43
|
-
if (parent && parent !== 'world') {
|
|
44
|
-
entityTraits.push(traits.Parent(parent));
|
|
45
|
-
}
|
|
46
|
-
if (transform.physicalObject) {
|
|
47
|
-
if (transform.physicalObject.geometryType.case === 'pointcloud') {
|
|
48
|
-
const metadataColors = metadata.colors;
|
|
49
|
-
parsePcdInWorker(new Uint8Array(transform.physicalObject.geometryType.value.pointCloud)).then((pointcloud) => {
|
|
50
|
-
const entity = entities.get(transform.uuidString);
|
|
51
|
-
if (!entity) {
|
|
52
|
-
console.error('Entity not found to add pointcloud trait to', transform.uuidString);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const numPoints = pointcloud.positions.length / STRIDE.POSITIONS;
|
|
56
|
-
const vertexColors = metadataColors && isPerVertexColors(metadataColors, numPoints)
|
|
57
|
-
? metadataColors
|
|
58
|
-
: pointcloud.colors;
|
|
59
|
-
const geometry = createBufferGeometry(pointcloud.positions, vertexColors);
|
|
60
|
-
entity.add(traits.BufferGeometry(geometry));
|
|
61
|
-
entity.add(traits.Points);
|
|
62
|
-
if (metadataColors && !isPerVertexColors(metadataColors, numPoints)) {
|
|
63
|
-
asColor(metadataColors, colorUtil);
|
|
64
|
-
entity.add(traits.Color({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
|
|
65
|
-
if (metadataColors.length % STRIDE.COLORS_RGBA === 0) {
|
|
66
|
-
entity.add(traits.Opacity(asOpacity(metadataColors)));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
invalidate();
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
if (metadata.colors) {
|
|
74
|
-
asColor(metadata.colors, colorUtil);
|
|
75
|
-
entityTraits.push(traits.Color({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
|
|
76
|
-
if (metadata.colors.length % STRIDE.COLORS_RGBA === 0) {
|
|
77
|
-
entityTraits.push(traits.Opacity(asOpacity(metadata.colors)));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
entityTraits.push(traits.Geometry(transform.physicalObject));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
entityTraits.push(traits.Name(transform.referenceFrame), traits.Pose(pose), traits.ShowAxesHelper, traits.WorldStateStoreAPI);
|
|
84
|
-
const entity = world.spawn(...entityTraits);
|
|
35
|
+
const entity = drawTransform(world, transform, traits.WorldStateStoreAPI, { removable: false });
|
|
85
36
|
entities.set(transform.uuidString, entity);
|
|
37
|
+
if (isPointCloud(transform.physicalObject?.geometryType))
|
|
38
|
+
invalidate();
|
|
86
39
|
};
|
|
87
40
|
const destroyEntity = (uuid) => {
|
|
88
41
|
const entity = entities.get(uuid);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
export { default as MotionTools } from './components/App.svelte';
|
|
2
2
|
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
3
3
|
export { default as PCD } from './components/PCD.svelte';
|
|
4
|
+
export * as relations from './ecs/relations';
|
|
5
|
+
export * as traits from './ecs/traits';
|
|
6
|
+
export * as selectionTraits from './components/Selection/traits';
|
|
7
|
+
export { useSelectionPlugin as useSelection } from './components/Selection/useSelectionPlugin.svelte';
|
|
8
|
+
export { default as FloatingPanel } from './components/overlay/FloatingPanel.svelte';
|
|
9
|
+
export { provideWorld, useWorld } from './ecs/useWorld';
|
|
10
|
+
export { useQuery } from './ecs/useQuery.svelte';
|
|
11
|
+
export { useTrait } from './ecs/useTrait.svelte';
|
package/dist/index.js
CHANGED
|
@@ -2,3 +2,12 @@ export { default as MotionTools } from './components/App.svelte';
|
|
|
2
2
|
// Plugins
|
|
3
3
|
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
4
4
|
export { default as PCD } from './components/PCD.svelte';
|
|
5
|
+
// ECS
|
|
6
|
+
export * as relations from './ecs/relations';
|
|
7
|
+
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
|
+
export { default as FloatingPanel } from './components/overlay/FloatingPanel.svelte';
|
|
11
|
+
export { provideWorld, useWorld } from './ecs/useWorld';
|
|
12
|
+
export { useQuery } from './ecs/useQuery.svelte';
|
|
13
|
+
export { useTrait } from './ecs/useTrait.svelte';
|
package/dist/lib.d.ts
CHANGED
|
@@ -5,3 +5,5 @@ export { BatchedArrow } from './three/BatchedArrow';
|
|
|
5
5
|
export { CapsuleGeometry } from './three/CapsuleGeometry';
|
|
6
6
|
export { OrientationVector } from './three/OrientationVector';
|
|
7
7
|
export { parsePcdInWorker } from './loaders/pcd';
|
|
8
|
+
export { createBinaryPCD } from './pcd';
|
|
9
|
+
export { metadataFromStruct } from './metadata';
|