@viamrobotics/motion-tools 1.13.1 → 1.15.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/FrameConfigUpdater.svelte.d.ts +2 -2
- package/dist/HoverUpdater.svelte.d.ts +1 -1
- package/dist/attribute.js +11 -3
- package/dist/buffer.d.ts +56 -7
- package/dist/buffer.js +70 -12
- package/dist/color.d.ts +1 -1
- package/dist/color.js +2 -2
- package/dist/components/App.svelte +25 -21
- package/dist/components/App.svelte.d.ts +1 -1
- package/dist/components/BatchedArrows.svelte +5 -3
- package/dist/components/Camera.svelte +1 -0
- package/dist/components/CameraControls.svelte +5 -3
- package/dist/components/Entities/Arrows/ArrowGroups.svelte +6 -3
- package/dist/components/Entities/Arrows/Arrows.svelte +6 -3
- package/dist/components/Entities/Entities.svelte +9 -7
- package/dist/components/Entities/Frame.svelte +48 -48
- package/dist/components/Entities/Frame.svelte.d.ts +3 -2
- package/dist/components/Entities/GLTF.svelte +8 -5
- package/dist/components/Entities/GLTF.svelte.d.ts +2 -2
- package/dist/components/Entities/Geometry.svelte +45 -173
- package/dist/components/Entities/Geometry.svelte.d.ts +5 -14
- package/dist/components/Entities/Line.svelte +69 -19
- package/dist/components/Entities/Line.svelte.d.ts +1 -1
- package/dist/components/Entities/LineDots.svelte +1 -1
- package/dist/components/Entities/LineGeometry.svelte +1 -1
- package/dist/components/Entities/Mesh.svelte +133 -0
- package/dist/components/Entities/Mesh.svelte.d.ts +4 -0
- package/dist/components/Entities/Points.svelte +9 -6
- package/dist/components/Entities/Points.svelte.d.ts +2 -2
- package/dist/components/Entities/Pose.svelte +4 -3
- package/dist/components/Entities/hooks/useEntityEvents.svelte.d.ts +1 -1
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +2 -2
- package/dist/components/FileDrop/FileDrop.svelte +10 -6
- package/dist/components/FileDrop/file-dropper.d.ts +1 -1
- package/dist/components/FileDrop/pcd-dropper.js +1 -1
- package/dist/components/FileDrop/ply-dropper.js +1 -1
- package/dist/components/FileDrop/snapshot-dropper.js +1 -1
- package/dist/components/Focus.svelte +4 -2
- package/dist/components/KeyboardControls.svelte +4 -2
- package/dist/components/Lasso/Debug.svelte +5 -2
- package/dist/components/Lasso/Lasso.svelte +9 -6
- package/dist/components/Lasso/Tool.svelte +10 -7
- package/dist/components/MeasureTool/MeasurePoint.svelte +2 -1
- package/dist/components/MeasureTool/MeasurePoint.svelte.d.ts +1 -1
- package/dist/components/MeasureTool/MeasureTool.svelte +7 -5
- package/dist/components/PCD.svelte +4 -3
- package/dist/components/PointerMissBox.svelte +3 -2
- package/dist/components/Scene.svelte +12 -9
- package/dist/components/SceneProviders.svelte +20 -18
- package/dist/components/Selected.svelte +7 -3
- package/dist/components/Snapshot.svelte +8 -5
- package/dist/components/StaticGeometries.svelte +10 -7
- package/dist/components/hover/HoveredEntities.svelte +2 -1
- package/dist/components/hover/HoveredEntity.svelte +2 -1
- package/dist/components/hover/HoveredEntityTooltip.svelte +1 -0
- package/dist/components/hover/LinkedHoveredEntity.svelte +7 -5
- package/dist/components/overlay/AddRelationship.svelte +4 -2
- package/dist/components/overlay/Details.svelte +21 -19
- package/dist/components/overlay/FloatingPanel.svelte +40 -3
- package/dist/components/overlay/FloatingPanel.svelte.d.ts +1 -0
- package/dist/components/overlay/LiveUpdatesBanner.svelte +1 -0
- package/dist/components/overlay/Logs.svelte +4 -2
- package/dist/components/overlay/Popover.svelte +3 -2
- package/dist/components/overlay/RefreshRate.svelte +4 -2
- package/dist/components/overlay/dashboard/Button.svelte +2 -1
- package/dist/components/overlay/dashboard/Button.svelte.d.ts +1 -1
- package/dist/components/overlay/dashboard/Dashboard.svelte +3 -1
- package/dist/components/overlay/left-pane/AddFrames.svelte +4 -2
- package/dist/components/overlay/left-pane/Drawer.svelte +3 -2
- package/dist/components/overlay/left-pane/Tree.svelte +6 -12
- package/dist/components/overlay/left-pane/TreeContainer.svelte +33 -50
- package/dist/components/overlay/left-pane/TreeContainer.svelte.d.ts +1 -1
- package/dist/components/overlay/left-pane/buildTree.js +15 -0
- package/dist/components/overlay/settings/Settings.svelte +37 -10
- package/dist/components/overlay/settings/Tabs.svelte +2 -1
- package/dist/components/overlay/widgets/ArmPositions.svelte +3 -2
- package/dist/components/overlay/widgets/Camera.svelte +6 -5
- package/dist/components/weblab/WeblabActive.svelte +2 -1
- package/dist/components/xr/ArmTeleop.svelte +7 -6
- package/dist/components/xr/BentPlaneGeometry.svelte +3 -2
- package/dist/components/xr/CameraFeed.svelte +2 -0
- package/dist/components/xr/Controllers.svelte +5 -3
- package/dist/components/xr/Draggable.svelte +4 -3
- package/dist/components/xr/HandCollider.svelte +2 -1
- package/dist/components/xr/JointLimitsWidget.svelte +1 -0
- package/dist/components/xr/OriginMarker.svelte +2 -1
- package/dist/components/xr/PointDistance.svelte +3 -2
- package/dist/components/xr/XR.svelte +8 -6
- package/dist/components/xr/XRConfigPanel.svelte +4 -3
- package/dist/components/xr/XRControllerSettings.svelte +2 -1
- package/dist/components/xr/XRToast.svelte +4 -3
- package/dist/ecs/traits.d.ts +3 -20
- package/dist/ecs/traits.js +34 -7
- package/dist/ecs/useQuery.svelte.js +1 -1
- package/dist/frame.js +1 -1
- package/dist/hooks/use3DModels.svelte.js +4 -6
- package/dist/hooks/useConfigFrames.svelte.js +3 -3
- package/dist/hooks/useDrawAPI.svelte.js +9 -9
- package/dist/hooks/useFramelessComponents.svelte.js +1 -1
- package/dist/hooks/useFrames.svelte.js +18 -19
- package/dist/hooks/useGeometries.svelte.js +66 -43
- package/dist/hooks/useMouseRaycaster.svelte.d.ts +1 -1
- package/dist/hooks/useMouseRaycaster.svelte.js +1 -1
- package/dist/hooks/usePartConfig.svelte.d.ts +1 -1
- package/dist/hooks/usePartConfig.svelte.js +3 -3
- package/dist/hooks/usePointcloudObjects.svelte.js +108 -63
- package/dist/hooks/usePointclouds.svelte.js +53 -33
- package/dist/hooks/usePose.svelte.js +7 -7
- package/dist/hooks/useSelection.svelte.d.ts +1 -1
- package/dist/hooks/useWeblabs.svelte.d.ts +1 -0
- package/dist/hooks/useWeblabs.svelte.js +15 -3
- package/dist/hooks/useWorldState.svelte.js +31 -31
- package/dist/metadata.d.ts +22 -0
- package/dist/metadata.js +66 -0
- package/dist/plugins/bvh.svelte.js +2 -2
- package/dist/snapshot.d.ts +22 -2
- package/dist/snapshot.js +67 -25
- package/dist/three/BatchedArrow.d.ts +1 -1
- package/dist/three/BatchedArrow.js +1 -1
- package/dist/three/InstancedArrows/InstancedArrows.d.ts +1 -1
- package/dist/three/InstancedArrows/InstancedArrows.js +3 -3
- package/dist/three/InstancedArrows/box.js +1 -1
- package/dist/three/InstancedArrows/geometry.js +1 -1
- package/dist/three/InstancedArrows/raycast.d.ts +1 -1
- package/dist/three/InstancedArrows/raycast.js +1 -1
- package/dist/three/OBBHelper.d.ts +3 -2
- package/dist/three/OBBHelper.js +17 -5
- package/dist/three/OrientationVector.js +1 -1
- package/dist/transform.js +1 -1
- package/package.json +3 -2
- package/dist/WorldObject.svelte.d.ts +0 -27
- package/dist/WorldObject.svelte.js +0 -127
- package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte +0 -41
- package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte.d.ts +0 -6
- package/dist/hooks/useResizable.svelte.d.ts +0 -12
- package/dist/hooks/useResizable.svelte.js +0 -46
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { CameraClient } from '@viamrobotics/sdk';
|
|
2
|
-
import { setContext, getContext, untrack } from 'svelte';
|
|
3
2
|
import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { useLogs } from './useLogs.svelte';
|
|
3
|
+
import { getContext, setContext, untrack } from 'svelte';
|
|
4
|
+
import { createBufferGeometry, updateBufferGeometry } from '../attribute';
|
|
7
5
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
8
6
|
import { traits, useWorld } from '../ecs';
|
|
7
|
+
import { parsePcdInWorker } from '../loaders/pcd';
|
|
9
8
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
return Object.fromEntries(entries);
|
|
13
|
-
};
|
|
9
|
+
import { useLogs } from './useLogs.svelte';
|
|
10
|
+
import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
|
|
14
11
|
const key = Symbol('pointcloud-context');
|
|
15
12
|
export const providePointclouds = (partID) => {
|
|
16
13
|
const environment = useEnvironment();
|
|
@@ -60,7 +57,6 @@ export const providePointclouds = (partID) => {
|
|
|
60
57
|
refetchInterval: interval === RefetchRates.MANUAL ? false : interval,
|
|
61
58
|
});
|
|
62
59
|
const queries = $derived(enabledClients.map((client) => [client.current.name, createResourceQuery(client, 'getPointCloud', () => options)]));
|
|
63
|
-
const queryMap = $derived(typeSafeObjectFromEntries(queries));
|
|
64
60
|
$effect(() => {
|
|
65
61
|
for (const [name, query] of queries) {
|
|
66
62
|
untrack(() => {
|
|
@@ -77,39 +73,63 @@ export const providePointclouds = (partID) => {
|
|
|
77
73
|
});
|
|
78
74
|
const entities = new Map();
|
|
79
75
|
$effect(() => {
|
|
76
|
+
const currentPartID = partID();
|
|
77
|
+
const activeQueryKeys = new Set();
|
|
80
78
|
for (const [name, query] of queries) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
const queryKey = `${currentPartID}:${name}`;
|
|
80
|
+
activeQueryKeys.add(queryKey);
|
|
81
|
+
$effect(() => {
|
|
82
|
+
const { data } = query;
|
|
83
|
+
let disposed = false;
|
|
84
|
+
const destroyEntity = () => {
|
|
85
|
+
const entity = entities.get(queryKey);
|
|
86
|
+
if (entity) {
|
|
87
|
+
if (world.has(entity))
|
|
88
|
+
entity.destroy();
|
|
89
|
+
entities.delete(queryKey);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
if (!data || data.length === 0) {
|
|
93
|
+
destroyEntity();
|
|
94
|
+
return () => {
|
|
95
|
+
disposed = true;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
parsePcdInWorker(data)
|
|
99
|
+
.then(({ positions, colors }) => {
|
|
100
|
+
if (disposed) {
|
|
85
101
|
return;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
102
|
+
}
|
|
103
|
+
const existing = entities.get(queryKey);
|
|
104
|
+
if (existing) {
|
|
105
|
+
const geometry = existing.get(traits.BufferGeometry);
|
|
106
|
+
if (geometry) {
|
|
107
|
+
updateBufferGeometry(geometry, positions, colors);
|
|
108
|
+
return;
|
|
95
109
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
}
|
|
111
|
+
const geometry = createBufferGeometry(positions, colors);
|
|
112
|
+
const entity = world.spawn(traits.Parent(name), traits.Name(`${name} pointcloud`), traits.BufferGeometry(geometry), traits.Points);
|
|
113
|
+
entities.set(queryKey, entity);
|
|
114
|
+
})
|
|
115
|
+
.catch((error) => {
|
|
116
|
+
if (disposed) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
logs.add(error?.reason ?? error?.message ?? 'Failed to parse pointcloud', 'error');
|
|
103
120
|
});
|
|
121
|
+
return () => {
|
|
122
|
+
disposed = true;
|
|
123
|
+
};
|
|
104
124
|
});
|
|
105
125
|
}
|
|
106
|
-
//
|
|
107
|
-
for (const [
|
|
108
|
-
if (!
|
|
126
|
+
// clean up queries that disappeared entirely
|
|
127
|
+
for (const [queryKey, entity] of entities) {
|
|
128
|
+
if (!activeQueryKeys.has(queryKey)) {
|
|
109
129
|
if (world.has(entity)) {
|
|
110
130
|
entity.destroy();
|
|
111
131
|
}
|
|
112
|
-
entities.delete(
|
|
132
|
+
entities.delete(queryKey);
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { createRobotQuery, useRobotClient } from '@viamrobotics/svelte-sdk';
|
|
2
|
-
import { usePartID } from './usePartID.svelte';
|
|
3
|
-
import { commonApi, Pose } from '@viamrobotics/sdk';
|
|
4
|
-
import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
|
|
5
|
-
import { useEnvironment } from './useEnvironment.svelte';
|
|
6
1
|
import { observe } from '@threlte/core';
|
|
2
|
+
import { commonApi, Pose } from '@viamrobotics/sdk';
|
|
3
|
+
import { createRobotQuery, useRobotClient } from '@viamrobotics/svelte-sdk';
|
|
7
4
|
import { untrack } from 'svelte';
|
|
8
|
-
import { useFrames } from './useFrames.svelte';
|
|
9
5
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
6
|
+
import { useEnvironment } from './useEnvironment.svelte';
|
|
7
|
+
import { useFrames } from './useFrames.svelte';
|
|
10
8
|
import { useLogs } from './useLogs.svelte';
|
|
11
|
-
import {
|
|
9
|
+
import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
|
|
10
|
+
import { usePartID } from './usePartID.svelte';
|
|
12
11
|
import { useRefetchPoses } from './useRefetchPoses';
|
|
12
|
+
import { useResourceByName } from './useResourceByName.svelte';
|
|
13
13
|
const originFrameComponentTypes = new Set(['arm', 'gantry', 'gripper', 'base']);
|
|
14
14
|
export const usePose = (name, parent) => {
|
|
15
15
|
const environment = useEnvironment();
|
|
@@ -3,6 +3,7 @@ export declare const WEBLABS_CONTEXT_KEY: unique symbol;
|
|
|
3
3
|
interface Context {
|
|
4
4
|
load: (experiments: string[]) => void;
|
|
5
5
|
isActive(experiment: string): boolean;
|
|
6
|
+
toggle(experiment: string): void;
|
|
6
7
|
}
|
|
7
8
|
export declare const createWeblabs: () => Context;
|
|
8
9
|
export declare const provideWeblabs: () => void;
|
|
@@ -37,11 +37,22 @@ export const createWeblabs = () => {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
+
const toggle = (experiment) => {
|
|
41
|
+
const cookieExperiments = new Set(getCookieExperiments());
|
|
42
|
+
if (activeExperiments.has(experiment)) {
|
|
43
|
+
activeExperiments.delete(experiment);
|
|
44
|
+
cookieExperiments.delete(experiment);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
activeExperiments.add(experiment);
|
|
48
|
+
cookieExperiments.add(experiment);
|
|
49
|
+
}
|
|
50
|
+
addCookie('weblab_experiments', [...cookieExperiments].join(','));
|
|
51
|
+
};
|
|
40
52
|
return {
|
|
41
53
|
load,
|
|
42
|
-
isActive: (experiment) =>
|
|
43
|
-
|
|
44
|
-
},
|
|
54
|
+
isActive: (experiment) => activeExperiments.has(experiment),
|
|
55
|
+
toggle,
|
|
45
56
|
};
|
|
46
57
|
};
|
|
47
58
|
export const provideWeblabs = () => {
|
|
@@ -58,6 +69,7 @@ export const useWeblabs = () => {
|
|
|
58
69
|
return {
|
|
59
70
|
load: () => { },
|
|
60
71
|
isActive: () => false,
|
|
72
|
+
toggle: () => { },
|
|
61
73
|
};
|
|
62
74
|
}
|
|
63
75
|
return context;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useThrelte } from '@threlte/core';
|
|
2
|
+
import { TransformChangeType, WorldStateStoreClient, } from '@viamrobotics/sdk';
|
|
2
3
|
import { createResourceClient, createResourceQuery, createResourceStream, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { Color } from 'three';
|
|
5
|
+
import { createBufferGeometry } from '../attribute';
|
|
6
|
+
import { asColor, asOpacity, isPerVertexColors, STRIDE } from '../buffer';
|
|
5
7
|
import { traits, useWorld } from '../ecs';
|
|
6
|
-
import { createPose } from '../transform';
|
|
7
|
-
import { useThrelte } from '@threlte/core';
|
|
8
8
|
import { createBox, createCapsule, createSphere } from '../geometry';
|
|
9
|
-
import { parsePlyInput } from '../ply';
|
|
10
9
|
import { parsePcdInWorker } from '../loaders/pcd';
|
|
11
|
-
import {
|
|
10
|
+
import { parseMetadata } from '../metadata';
|
|
11
|
+
import { parsePlyInput } from '../ply';
|
|
12
|
+
import { createPose } from '../transform';
|
|
13
|
+
import { usePartID } from './usePartID.svelte';
|
|
14
|
+
const colorUtil = new Color();
|
|
12
15
|
export const provideWorldStates = () => {
|
|
13
16
|
const partID = usePartID();
|
|
14
17
|
const resourceNames = useResourceNames(() => partID.current, 'world_state_store');
|
|
@@ -40,46 +43,43 @@ const createWorldState = (client) => {
|
|
|
40
43
|
if (parent && parent !== 'world') {
|
|
41
44
|
entityTraits.push(traits.Parent(parent));
|
|
42
45
|
}
|
|
43
|
-
if (metadata.color) {
|
|
44
|
-
entityTraits.push(traits.Color(metadata.color));
|
|
45
|
-
}
|
|
46
|
-
if (metadata.colors) {
|
|
47
|
-
entityTraits.push(traits.VertexColors(metadata.colors));
|
|
48
|
-
}
|
|
49
46
|
if (transform.physicalObject) {
|
|
50
47
|
if (transform.physicalObject.geometryType.case === 'pointcloud') {
|
|
48
|
+
const metadataColors = metadata.colors;
|
|
51
49
|
parsePcdInWorker(new Uint8Array(transform.physicalObject.geometryType.value.pointCloud)).then((pointcloud) => {
|
|
52
|
-
// pcds are a special case since they have to be loaded in a worker and the trait will be added to the existing entity
|
|
53
50
|
const entity = entities.get(transform.uuidString);
|
|
54
51
|
if (!entity) {
|
|
55
52
|
console.error('Entity not found to add pointcloud trait to', transform.uuidString);
|
|
56
53
|
return;
|
|
57
54
|
}
|
|
58
|
-
const
|
|
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);
|
|
59
60
|
entity.add(traits.BufferGeometry(geometry));
|
|
60
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();
|
|
61
70
|
});
|
|
62
71
|
}
|
|
63
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
|
+
}
|
|
64
80
|
entityTraits.push(traits.Geometry(transform.physicalObject));
|
|
65
81
|
}
|
|
66
82
|
}
|
|
67
|
-
if (metadata.shape === 'line' && metadata.points) {
|
|
68
|
-
const { points } = metadata;
|
|
69
|
-
const positions = new Float32Array(points.length * 3);
|
|
70
|
-
for (let i = 0, j = 0, l = points.length * 3; i < l; i += 3, j += 1) {
|
|
71
|
-
positions[i + 0] = points[j].x;
|
|
72
|
-
positions[i + 1] = points[j].y;
|
|
73
|
-
positions[i + 2] = points[j].z;
|
|
74
|
-
}
|
|
75
|
-
entityTraits.push(traits.LinePositions(positions), traits.PointColor(metadata.lineDotColor));
|
|
76
|
-
}
|
|
77
|
-
if (metadata.gltf) {
|
|
78
|
-
entityTraits.push(traits.GLTF({ source: { gltf: metadata.gltf }, animationName: '' }));
|
|
79
|
-
}
|
|
80
|
-
if (metadata.shape === 'arrow') {
|
|
81
|
-
entityTraits.push(traits.Arrow);
|
|
82
|
-
}
|
|
83
83
|
entityTraits.push(traits.Name(transform.referenceFrame), traits.Pose(pose), traits.ShowAxesHelper, traits.WorldStateStoreAPI);
|
|
84
84
|
const entity = world.spawn(...entityTraits);
|
|
85
85
|
entities.set(transform.uuidString, entity);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PlainMessage, Struct } from '@viamrobotics/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Metadata for a Viam `Transform`.
|
|
4
|
+
*
|
|
5
|
+
* Per the API this can be a struct of any data, so we type this version for
|
|
6
|
+
* fields we use and how we expect them to be defined.
|
|
7
|
+
*/
|
|
8
|
+
export type Metadata = {
|
|
9
|
+
colors?: Uint8Array<ArrayBuffer>;
|
|
10
|
+
};
|
|
11
|
+
/** Type guard that checks whether a string is a recognised {@link Metadata} field name. */
|
|
12
|
+
export declare const isMetadataKey: (key: string) => key is keyof Metadata;
|
|
13
|
+
/**
|
|
14
|
+
* Extracts typed {@link Metadata} from a proto `Struct` fields map.
|
|
15
|
+
*
|
|
16
|
+
* The `colors` field is expected as a base64-encoded string (the only way to
|
|
17
|
+
* represent binary data in a `google.protobuf.Value`), which is decoded into
|
|
18
|
+
* a `Uint8Array`.
|
|
19
|
+
*
|
|
20
|
+
* Unknown keys are silently ignored.
|
|
21
|
+
*/
|
|
22
|
+
export declare const parseMetadata: (fields?: PlainMessage<Struct>["fields"]) => Metadata;
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Type guard that checks whether a string is a recognised {@link Metadata} field name. */
|
|
2
|
+
export const isMetadataKey = (key) => {
|
|
3
|
+
return key === 'colors';
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Extracts typed {@link Metadata} from a proto `Struct` fields map.
|
|
7
|
+
*
|
|
8
|
+
* The `colors` field is expected as a base64-encoded string (the only way to
|
|
9
|
+
* represent binary data in a `google.protobuf.Value`), which is decoded into
|
|
10
|
+
* a `Uint8Array`.
|
|
11
|
+
*
|
|
12
|
+
* Unknown keys are silently ignored.
|
|
13
|
+
*/
|
|
14
|
+
export const parseMetadata = (fields = {}) => {
|
|
15
|
+
const json = {};
|
|
16
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
17
|
+
if (!isMetadataKey(k))
|
|
18
|
+
continue;
|
|
19
|
+
const unwrappedValue = unwrapValue(v);
|
|
20
|
+
switch (k) {
|
|
21
|
+
case 'colors': {
|
|
22
|
+
if (typeof unwrappedValue === 'string') {
|
|
23
|
+
const binary = atob(unwrappedValue);
|
|
24
|
+
const colorBytes = new Uint8Array(binary.length);
|
|
25
|
+
for (let i = 0; i < binary.length; i++) {
|
|
26
|
+
colorBytes[i] = binary.charCodeAt(i);
|
|
27
|
+
}
|
|
28
|
+
json.colors = colorBytes;
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return json;
|
|
35
|
+
};
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
const unwrapValue = (value) => {
|
|
38
|
+
if (!value?.kind)
|
|
39
|
+
return value;
|
|
40
|
+
switch (value.kind.case) {
|
|
41
|
+
case 'numberValue':
|
|
42
|
+
case 'stringValue':
|
|
43
|
+
case 'boolValue': {
|
|
44
|
+
return value.kind.value;
|
|
45
|
+
}
|
|
46
|
+
case 'structValue': {
|
|
47
|
+
const result = {};
|
|
48
|
+
for (const [key, val] of Object.entries(value.kind.value.fields || {})) {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
result[key] = unwrapValue(val);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
case 'listValue': {
|
|
55
|
+
return (value.kind.value.values?.map(
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
(v) => unwrapValue(v)) || []);
|
|
58
|
+
}
|
|
59
|
+
case 'nullValue': {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
default: {
|
|
63
|
+
return value.kind.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectPlugin, isInstanceOf } from '@threlte/core';
|
|
2
|
-
import { BatchedMesh,
|
|
3
|
-
import { acceleratedRaycast,
|
|
2
|
+
import { BatchedMesh, Mesh, Points } from 'three';
|
|
3
|
+
import { acceleratedRaycast, BVHHelper, computeBatchedBoundsTree, computeBoundsTree, disposeBatchedBoundsTree, disposeBoundsTree, PointsBVH, SAH, } from 'three-mesh-bvh';
|
|
4
4
|
export const bvh = (raycaster, options) => {
|
|
5
5
|
const bvhOptions = $derived({
|
|
6
6
|
strategy: SAH,
|
package/dist/snapshot.d.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Entity, World } from 'koota';
|
|
2
2
|
import type { Snapshot } from './buf/draw/v1/snapshot_pb';
|
|
3
|
-
import { type SceneMetadata } from './buf/draw/v1/scene_pb';
|
|
4
3
|
import type { Settings } from './hooks/useSettings.svelte';
|
|
4
|
+
import { type SceneMetadata } from './buf/draw/v1/scene_pb';
|
|
5
|
+
/**
|
|
6
|
+
* Merges scene-level metadata (grid, camera, point/line settings) into the
|
|
7
|
+
* current viewer settings. Millimetre values from the proto are converted
|
|
8
|
+
* to metres.
|
|
9
|
+
*/
|
|
5
10
|
export declare const applySceneMetadata: (settings: Settings, metadata: SceneMetadata) => Settings;
|
|
11
|
+
/**
|
|
12
|
+
* Spawns ECS entities for every transform and drawing in a {@link Snapshot}.
|
|
13
|
+
*
|
|
14
|
+
* Each transform produces one entity with Name, Pose, Parent, Geometry, and
|
|
15
|
+
* optional Color/Opacity traits. Each drawing produces one or more entities
|
|
16
|
+
* depending on the geometry type (arrows, points, line, nurbs, model, or
|
|
17
|
+
* simple shapes like box/sphere/capsule).
|
|
18
|
+
*
|
|
19
|
+
* @returns The spawned entities — pass them to {@link destroyEntities} to
|
|
20
|
+
* clean up before loading a new snapshot.
|
|
21
|
+
*/
|
|
6
22
|
export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) => Entity[];
|
|
23
|
+
/**
|
|
24
|
+
* Destroys a list of entities that are still alive in the given world.
|
|
25
|
+
* Silently skips entities that have already been removed.
|
|
26
|
+
*/
|
|
7
27
|
export declare const destroyEntities: (world: World, entities: Entity[]) => void;
|
package/dist/snapshot.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Geometry } from '@viamrobotics/sdk';
|
|
2
|
+
import { Color, Vector3, Vector4 } from 'three';
|
|
2
3
|
import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
|
|
3
|
-
import { RenderArmModels } from './buf/draw/v1/scene_pb';
|
|
4
4
|
import {} from './buf/draw/v1/drawing_pb';
|
|
5
|
+
import { RenderArmModels } from './buf/draw/v1/scene_pb';
|
|
5
6
|
import { traits } from './ecs';
|
|
6
|
-
import {
|
|
7
|
-
import { parseMetadata } from './WorldObject.svelte';
|
|
8
|
-
import { rgbaBytesToFloat32, rgbaToHex } from './color';
|
|
9
|
-
import { asFloat32Array, STRIDE } from './buffer';
|
|
7
|
+
import { parseMetadata } from './metadata';
|
|
10
8
|
import { createBufferGeometry } from './attribute';
|
|
9
|
+
import { asColor, asFloat32Array, asOpacity, isPerVertexColors, STRIDE } from './buffer';
|
|
10
|
+
import { rgbaToHex } from './color';
|
|
11
11
|
const vec3 = new Vector3();
|
|
12
|
+
const colorUtil = new Color();
|
|
13
|
+
/**
|
|
14
|
+
* Merges scene-level metadata (grid, camera, point/line settings) into the
|
|
15
|
+
* current viewer settings. Millimetre values from the proto are converted
|
|
16
|
+
* to metres.
|
|
17
|
+
*/
|
|
12
18
|
export const applySceneMetadata = (settings, metadata) => {
|
|
13
19
|
const next = { ...settings };
|
|
14
20
|
if (metadata.grid !== undefined) {
|
|
@@ -46,6 +52,17 @@ export const applySceneMetadata = (settings, metadata) => {
|
|
|
46
52
|
}
|
|
47
53
|
return next;
|
|
48
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* Spawns ECS entities for every transform and drawing in a {@link Snapshot}.
|
|
57
|
+
*
|
|
58
|
+
* Each transform produces one entity with Name, Pose, Parent, Geometry, and
|
|
59
|
+
* optional Color/Opacity traits. Each drawing produces one or more entities
|
|
60
|
+
* depending on the geometry type (arrows, points, line, nurbs, model, or
|
|
61
|
+
* simple shapes like box/sphere/capsule).
|
|
62
|
+
*
|
|
63
|
+
* @returns The spawned entities — pass them to {@link destroyEntities} to
|
|
64
|
+
* clean up before loading a new snapshot.
|
|
65
|
+
*/
|
|
49
66
|
export const spawnSnapshotEntities = (world, snapshot) => {
|
|
50
67
|
const entities = [];
|
|
51
68
|
for (const transform of snapshot.transforms) {
|
|
@@ -59,6 +76,10 @@ export const spawnSnapshotEntities = (world, snapshot) => {
|
|
|
59
76
|
}
|
|
60
77
|
return entities;
|
|
61
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Destroys a list of entities that are still alive in the given world.
|
|
81
|
+
* Silently skips entities that have already been removed.
|
|
82
|
+
*/
|
|
62
83
|
export const destroyEntities = (world, entities) => {
|
|
63
84
|
for (const entity of entities) {
|
|
64
85
|
if (world.has(entity)) {
|
|
@@ -92,12 +113,8 @@ const spawnTransformEntity = (world, transform) => {
|
|
|
92
113
|
entityTraits.push(traits.Pose(poseInFrame?.pose), traits.Parent(poseInFrame?.referenceFrame));
|
|
93
114
|
if (transform.metadata) {
|
|
94
115
|
const metadata = parseMetadata(transform.metadata.fields);
|
|
95
|
-
if (metadata.
|
|
96
|
-
entityTraits
|
|
97
|
-
}
|
|
98
|
-
if (metadata.opacity !== undefined) {
|
|
99
|
-
entityTraits.push(traits.Opacity(metadata.opacity));
|
|
100
|
-
}
|
|
116
|
+
if (metadata.colors)
|
|
117
|
+
addColorTraits(entityTraits, metadata.colors);
|
|
101
118
|
}
|
|
102
119
|
return world.spawn(...entityTraits);
|
|
103
120
|
};
|
|
@@ -167,15 +184,6 @@ const spawnEntitiesFromDrawing = (world, drawing) => {
|
|
|
167
184
|
if (parent && parent !== 'world') {
|
|
168
185
|
entityTraits.push(traits.Parent);
|
|
169
186
|
}
|
|
170
|
-
if (drawing.metadata?.colors) {
|
|
171
|
-
const colors = rgbaBytesToFloat32(drawing.metadata.colors);
|
|
172
|
-
if (colors.length === 4) {
|
|
173
|
-
entityTraits.push(traits.Color({ r: colors[0], g: colors[1], b: colors[2] }), traits.Opacity(colors[3]));
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
entityTraits.push(traits.VertexColors(colors));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
187
|
if (drawing.physicalObject?.center) {
|
|
180
188
|
entityTraits.push(traits.Center(drawing.physicalObject.center));
|
|
181
189
|
}
|
|
@@ -184,9 +192,20 @@ const spawnEntitiesFromDrawing = (world, drawing) => {
|
|
|
184
192
|
for (let i = 0, l = positions.length; i < l; i += 1) {
|
|
185
193
|
positions[i] *= 0.001;
|
|
186
194
|
}
|
|
187
|
-
entityTraits.push(traits.LinePositions(positions), traits.LineWidth(geometryType.value.lineWidth), traits.PointSize(geometryType.value.pointSize));
|
|
188
|
-
|
|
189
|
-
|
|
195
|
+
entityTraits.push(traits.LinePositions(positions), traits.LineWidth(geometryType.value.lineWidth), traits.PointSize((geometryType.value.pointSize ?? 0) * 0.001));
|
|
196
|
+
// Lines pack exactly 2 colors: [lineColor, pointColor]
|
|
197
|
+
const colors = drawing.metadata?.colors;
|
|
198
|
+
if (colors && colors.length >= STRIDE.COLORS_RGB) {
|
|
199
|
+
const stride = colors.length % STRIDE.COLORS_RGBA === 0 ? STRIDE.COLORS_RGBA : STRIDE.COLORS_RGB;
|
|
200
|
+
asColor(colors, colorUtil, 0);
|
|
201
|
+
entityTraits.push(traits.Color({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
|
|
202
|
+
if (colors.length >= stride * 2) {
|
|
203
|
+
asColor(colors, colorUtil, stride);
|
|
204
|
+
entityTraits.push(traits.PointColor({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
|
|
205
|
+
if (stride === STRIDE.COLORS_RGBA) {
|
|
206
|
+
entityTraits.push(traits.Opacity(asOpacity(colors, 1, 3)));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
190
209
|
}
|
|
191
210
|
}
|
|
192
211
|
else if (geometryType?.case === 'points') {
|
|
@@ -195,8 +214,13 @@ const spawnEntitiesFromDrawing = (world, drawing) => {
|
|
|
195
214
|
positions[i] *= 0.001;
|
|
196
215
|
}
|
|
197
216
|
const colors = drawing.metadata?.colors;
|
|
198
|
-
const
|
|
217
|
+
const numPoints = positions.length / STRIDE.POSITIONS;
|
|
218
|
+
const vertexColors = colors && isPerVertexColors(colors, numPoints) ? colors : undefined;
|
|
219
|
+
const geometry = createBufferGeometry(positions, vertexColors);
|
|
199
220
|
entityTraits.push(traits.BufferGeometry(geometry));
|
|
221
|
+
if (colors && !vertexColors) {
|
|
222
|
+
addColorTraits(entityTraits, colors);
|
|
223
|
+
}
|
|
200
224
|
if (geometryType.value.pointSize) {
|
|
201
225
|
entityTraits.push(traits.PointSize(geometryType.value.pointSize * 0.001));
|
|
202
226
|
}
|
|
@@ -227,9 +251,27 @@ const spawnEntitiesFromDrawing = (world, drawing) => {
|
|
|
227
251
|
points[i + 2] = vec3.z;
|
|
228
252
|
}
|
|
229
253
|
entityTraits.push(traits.LinePositions(points));
|
|
254
|
+
const colors = drawing.metadata?.colors;
|
|
255
|
+
if (colors) {
|
|
256
|
+
addColorTraits(entityTraits, colors);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Box, sphere, capsule, and other geometry shapes with a single color
|
|
261
|
+
const colors = drawing.metadata?.colors;
|
|
262
|
+
if (colors) {
|
|
263
|
+
addColorTraits(entityTraits, colors);
|
|
264
|
+
}
|
|
230
265
|
}
|
|
231
266
|
const entity = world.spawn(...entityTraits, traits.SnapshotAPI, traits.Removable);
|
|
232
267
|
entities.push(entity);
|
|
233
268
|
}
|
|
234
269
|
return entities;
|
|
235
270
|
};
|
|
271
|
+
const addColorTraits = (entityTraits, bytes) => {
|
|
272
|
+
asColor(bytes, colorUtil);
|
|
273
|
+
entityTraits.push(traits.Color(colorUtil));
|
|
274
|
+
const isRgba = bytes.length % STRIDE.COLORS_RGBA === 0;
|
|
275
|
+
if (isRgba)
|
|
276
|
+
entityTraits.push(traits.Opacity(asOpacity(bytes)));
|
|
277
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BatchedMesh,
|
|
1
|
+
import { BatchedMesh, Box3, Color, MeshBasicMaterial, Object3D, Vector3 } from 'three';
|
|
2
2
|
import { createArrowGeometry } from './arrow';
|
|
3
3
|
const black = new Color('black');
|
|
4
4
|
const axis = new Vector3();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Box3, BufferGeometry, type ColorRepresentation, Group, InstancedInterleavedBuffer, Mesh, Vector3 } from 'three';
|
|
2
2
|
export declare class InstancedArrows extends Group {
|
|
3
3
|
isInstancedArrows: boolean;
|
|
4
4
|
count: number;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { Box3, BufferGeometry, Color, DynamicDrawUsage, FrontSide, Group, InstancedBufferAttribute, InstancedInterleavedBuffer, InterleavedBufferAttribute, Material, Mesh, RawShaderMaterial, Vector3, } from 'three';
|
|
2
|
+
import { computeBoundingBox } from './box';
|
|
3
3
|
import fragmentShader from './fragment.glsl';
|
|
4
4
|
import { createHeadGeometry, createShaftGeometry, toInstanced } from './geometry';
|
|
5
|
-
import
|
|
5
|
+
import vertexShader from './vertex.glsl';
|
|
6
6
|
const defaults = {
|
|
7
7
|
LENGTH: 0.1,
|
|
8
8
|
HEAD_LENGTH: 0.02,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BufferAttribute, BufferGeometry, InstancedBufferGeometry } from 'three';
|
|
2
2
|
export const createShaftGeometry = () => {
|
|
3
3
|
// Triangular prism aligned to +Y, base at y=0, top at y=1.
|
|
4
4
|
// No caps, 6 verts, 6 side triangles.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Intersection, Raycaster } from 'three';
|
|
2
2
|
import type { InstancedArrows } from './InstancedArrows';
|
|
3
3
|
export declare function meshBoundsRaycast(this: InstancedArrows, raycaster: Raycaster, intersects: Intersection[]): void;
|
|
4
4
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Object3D, Vector3 } from 'three';
|
|
2
|
+
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
|
|
3
|
+
export declare class OBBHelper extends LineSegments2 {
|
|
3
4
|
constructor(color?: number, linewidth?: number);
|
|
4
5
|
setFromOBB(obb: {
|
|
5
6
|
center: Vector3;
|