@viamrobotics/motion-tools 1.15.8 → 1.18.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/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/{Lasso → Selection}/Debug.svelte +8 -8
- package/dist/components/{Lasso → Selection}/Debug.svelte.d.ts +2 -2
- package/dist/components/Selection/Ellipse.svelte +294 -0
- package/dist/components/Selection/Ellipse.svelte.d.ts +7 -0
- package/dist/components/{Lasso → Selection}/Lasso.svelte +33 -61
- package/dist/components/{Lasso → Selection}/Lasso.svelte.d.ts +1 -0
- package/dist/components/Selection/Tool.svelte +94 -0
- package/dist/components/{Lasso → Selection}/Tool.svelte.d.ts +2 -2
- package/dist/components/{Lasso → Selection}/traits.d.ts +11 -2
- package/dist/components/{Lasso → Selection}/traits.js +7 -2
- package/dist/components/Selection/useSelectionPlugin.svelte.d.ts +8 -0
- package/dist/components/Selection/useSelectionPlugin.svelte.js +24 -0
- package/dist/components/Selection/utils.d.ts +5 -0
- package/dist/components/Selection/utils.js +38 -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/OriginMarker.svelte +94 -17
- 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 +3 -2
- package/dist/hooks/useSettings.svelte.js +2 -2
- package/dist/hooks/useWorldState.svelte.js +5 -52
- package/dist/index.d.ts +9 -1
- package/dist/index.js +10 -1
- 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/Lasso/Tool.svelte +0 -108
- package/dist/components/xr/Hands.svelte +0 -23
- package/dist/components/xr/Hands.svelte.d.ts +0 -18
|
@@ -15,8 +15,8 @@ globalThis.onmessage = async (event) => {
|
|
|
15
15
|
*/
|
|
16
16
|
const positions = pcd.geometry.attributes.position?.array ??
|
|
17
17
|
new Float32Array(0);
|
|
18
|
-
const colorsFloat = pcd.geometry.attributes.color?.array ??
|
|
19
|
-
const colors = colorsFloat ? new Uint8Array(colorsFloat.length) :
|
|
18
|
+
const colorsFloat = pcd.geometry.attributes.color?.array ?? undefined;
|
|
19
|
+
const colors = colorsFloat ? new Uint8Array(colorsFloat.length) : undefined;
|
|
20
20
|
if (colors) {
|
|
21
21
|
for (let i = 0, l = colorsFloat.length; i < l; i++) {
|
|
22
22
|
colors[i] = Math.round(colorsFloat[i] * 255);
|
package/dist/metadata.d.ts
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import type { PlainMessage, Struct } from '@viamrobotics/sdk';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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;
|
|
2
|
+
import { Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
|
|
3
|
+
/** Metadata for a `Drawing` or `Transform`. */
|
|
4
|
+
export type Metadata = PlainMessage<MetadataProto>;
|
|
5
|
+
/** Type guard that checks whether a string is a recognised metadata wire key. */
|
|
6
|
+
export declare const isMetadataField: (key: string) => boolean;
|
|
13
7
|
/**
|
|
14
8
|
* Extracts typed {@link Metadata} from a proto `Struct` fields map.
|
|
15
9
|
*
|
|
16
|
-
* The `colors`
|
|
17
|
-
* represent binary data in a `google.protobuf.Value`), which
|
|
18
|
-
*
|
|
10
|
+
* The `colors` and `opacities` fields are base64-encoded strings (the only way
|
|
11
|
+
* to represent binary data in a `google.protobuf.Value`), which are decoded into
|
|
12
|
+
* `Uint8Array`s.
|
|
19
13
|
*
|
|
20
14
|
* Unknown keys are silently ignored.
|
|
21
15
|
*/
|
|
22
|
-
export declare const
|
|
16
|
+
export declare const metadataFromStruct: (fields?: PlainMessage<Struct>["fields"]) => Metadata;
|
package/dist/metadata.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { ColorFormat, Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
|
|
2
|
+
/** Type guard that checks whether a string is a recognised metadata wire key. */
|
|
3
|
+
export const isMetadataField = (key) => {
|
|
4
|
+
return (key === 'colors' ||
|
|
5
|
+
key === 'color_format' ||
|
|
6
|
+
key === 'opacities' ||
|
|
7
|
+
key === 'show_axes_helper' ||
|
|
8
|
+
key === 'invisible');
|
|
4
9
|
};
|
|
5
10
|
/**
|
|
6
11
|
* Extracts typed {@link Metadata} from a proto `Struct` fields map.
|
|
7
12
|
*
|
|
8
|
-
* The `colors`
|
|
9
|
-
* represent binary data in a `google.protobuf.Value`), which
|
|
10
|
-
*
|
|
13
|
+
* The `colors` and `opacities` fields are base64-encoded strings (the only way
|
|
14
|
+
* to represent binary data in a `google.protobuf.Value`), which are decoded into
|
|
15
|
+
* `Uint8Array`s.
|
|
11
16
|
*
|
|
12
17
|
* Unknown keys are silently ignored.
|
|
13
18
|
*/
|
|
14
|
-
export const
|
|
15
|
-
const json = {
|
|
19
|
+
export const metadataFromStruct = (fields = {}) => {
|
|
20
|
+
const json = {
|
|
21
|
+
colorFormat: ColorFormat.UNSPECIFIED,
|
|
22
|
+
};
|
|
16
23
|
for (const [k, v] of Object.entries(fields)) {
|
|
17
|
-
if (!
|
|
24
|
+
if (!isMetadataField(k))
|
|
18
25
|
continue;
|
|
19
26
|
const unwrappedValue = unwrapValue(v);
|
|
20
27
|
switch (k) {
|
|
@@ -29,6 +36,35 @@ export const parseMetadata = (fields = {}) => {
|
|
|
29
36
|
}
|
|
30
37
|
break;
|
|
31
38
|
}
|
|
39
|
+
case 'color_format': {
|
|
40
|
+
if (typeof unwrappedValue === 'number') {
|
|
41
|
+
json.colorFormat = unwrappedValue;
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case 'opacities': {
|
|
46
|
+
if (typeof unwrappedValue === 'string') {
|
|
47
|
+
const binary = atob(unwrappedValue);
|
|
48
|
+
const opacityBytes = new Uint8Array(binary.length);
|
|
49
|
+
for (let i = 0; i < binary.length; i++) {
|
|
50
|
+
opacityBytes[i] = binary.charCodeAt(i);
|
|
51
|
+
}
|
|
52
|
+
json.opacities = opacityBytes;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case 'show_axes_helper': {
|
|
57
|
+
if (typeof unwrappedValue === 'boolean') {
|
|
58
|
+
json.showAxesHelper = unwrappedValue;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'invisible': {
|
|
63
|
+
if (typeof unwrappedValue === 'boolean') {
|
|
64
|
+
json.invisible = unwrappedValue;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
32
68
|
}
|
|
33
69
|
}
|
|
34
70
|
return json;
|
|
@@ -22,7 +22,11 @@ export const bvh = (raycaster, options) => {
|
|
|
22
22
|
if (opts.enabled === false) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
if (isInstanceOf(ref, 'Points')
|
|
25
|
+
if (isInstanceOf(ref, 'Points') &&
|
|
26
|
+
/**
|
|
27
|
+
* This check is necessary, there are some strange cases where points are coming in from PCDs without any position data
|
|
28
|
+
*/
|
|
29
|
+
ref.geometry?.attributes.position) {
|
|
26
30
|
ref.geometry.computeBoundsTree = computeBoundsTree;
|
|
27
31
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
28
32
|
ref.raycast = acceleratedRaycast;
|
|
@@ -55,7 +59,7 @@ export const bvh = (raycaster, options) => {
|
|
|
55
59
|
* (mp) Line2s sort of suck. Their buffer attribute design internally is much different
|
|
56
60
|
* but they give no indication other than this that they are different.
|
|
57
61
|
*/
|
|
58
|
-
ref.geometry
|
|
62
|
+
ref.geometry?.attributes.position) {
|
|
59
63
|
ref.geometry.computeBoundsTree = computeBoundsTree;
|
|
60
64
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
61
65
|
ref.raycast = acceleratedRaycast;
|
package/dist/snapshot.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import type { Settings } from './hooks/useSettings.svelte';
|
|
|
4
4
|
import { type SceneMetadata } from './buf/draw/v1/scene_pb';
|
|
5
5
|
/**
|
|
6
6
|
* Merges scene-level metadata (grid, camera, point/line settings) into the
|
|
7
|
-
* current viewer settings.
|
|
8
|
-
* to
|
|
7
|
+
* current viewer settings. Millimeter values from the proto are converted
|
|
8
|
+
* to meters.
|
|
9
9
|
*/
|
|
10
10
|
export declare const applySceneMetadata: (settings: Settings, metadata: SceneMetadata) => Settings;
|
|
11
11
|
/**
|
|
@@ -16,12 +16,6 @@ export declare const applySceneMetadata: (settings: Settings, metadata: SceneMet
|
|
|
16
16
|
* depending on the geometry type (arrows, points, line, nurbs, model, or
|
|
17
17
|
* simple shapes like box/sphere/capsule).
|
|
18
18
|
*
|
|
19
|
-
* @returns The spawned entities
|
|
20
|
-
* clean up before loading a new snapshot.
|
|
19
|
+
* @returns The spawned entities
|
|
21
20
|
*/
|
|
22
21
|
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
|
-
*/
|
|
27
|
-
export declare const destroyEntities: (world: World, entities: Entity[]) => void;
|
package/dist/snapshot.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import { Geometry } from '@viamrobotics/sdk';
|
|
2
|
-
import { Color, Vector3, Vector4 } from 'three';
|
|
3
|
-
import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
|
|
4
|
-
import {} from './buf/draw/v1/drawing_pb';
|
|
5
1
|
import { RenderArmModels } from './buf/draw/v1/scene_pb';
|
|
6
2
|
import { traits } from './ecs';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { asColor, asFloat32Array, asOpacity, isPerVertexColors, STRIDE } from './buffer';
|
|
10
|
-
import { rgbaToHex } from './color';
|
|
11
|
-
const vec3 = new Vector3();
|
|
12
|
-
const colorUtil = new Color();
|
|
3
|
+
import { rgbToHex } from './color';
|
|
4
|
+
import { drawDrawing, drawTransform } from './draw';
|
|
13
5
|
/**
|
|
14
6
|
* Merges scene-level metadata (grid, camera, point/line settings) into the
|
|
15
|
-
* current viewer settings.
|
|
16
|
-
* to
|
|
7
|
+
* current viewer settings. Millimeter values from the proto are converted
|
|
8
|
+
* to meters.
|
|
17
9
|
*/
|
|
18
10
|
export const applySceneMetadata = (settings, metadata) => {
|
|
19
11
|
const next = { ...settings };
|
|
@@ -33,13 +25,13 @@ export const applySceneMetadata = (settings, metadata) => {
|
|
|
33
25
|
next.pointSize = metadata.pointSize / 1000;
|
|
34
26
|
}
|
|
35
27
|
if (metadata.pointColor !== undefined) {
|
|
36
|
-
next.pointColor =
|
|
28
|
+
next.pointColor = rgbToHex(metadata.pointColor);
|
|
37
29
|
}
|
|
38
30
|
if (metadata.lineWidth !== undefined) {
|
|
39
31
|
next.lineWidth = metadata.lineWidth / 1000;
|
|
40
32
|
}
|
|
41
|
-
if (metadata.
|
|
42
|
-
next.lineDotSize = metadata.
|
|
33
|
+
if (metadata.lineDotSize !== undefined) {
|
|
34
|
+
next.lineDotSize = metadata.lineDotSize / 1000;
|
|
43
35
|
}
|
|
44
36
|
if (metadata.renderArmModels !== undefined) {
|
|
45
37
|
next.renderArmModels = getRenderArmModels(metadata.renderArmModels);
|
|
@@ -60,33 +52,22 @@ export const applySceneMetadata = (settings, metadata) => {
|
|
|
60
52
|
* depending on the geometry type (arrows, points, line, nurbs, model, or
|
|
61
53
|
* simple shapes like box/sphere/capsule).
|
|
62
54
|
*
|
|
63
|
-
* @returns The spawned entities
|
|
64
|
-
* clean up before loading a new snapshot.
|
|
55
|
+
* @returns The spawned entities
|
|
65
56
|
*/
|
|
66
57
|
export const spawnSnapshotEntities = (world, snapshot) => {
|
|
67
58
|
const entities = [];
|
|
59
|
+
const options = { removable: true, showAxesHelper: false };
|
|
68
60
|
for (const transform of snapshot.transforms) {
|
|
69
|
-
entities.push(
|
|
61
|
+
entities.push(drawTransform(world, transform, traits.SnapshotAPI, options));
|
|
70
62
|
}
|
|
71
63
|
for (const drawing of snapshot.drawings) {
|
|
72
|
-
const drawingEntities =
|
|
64
|
+
const drawingEntities = drawDrawing(world, drawing, traits.SnapshotAPI, options);
|
|
73
65
|
for (const e of drawingEntities) {
|
|
74
66
|
entities.push(e);
|
|
75
67
|
}
|
|
76
68
|
}
|
|
77
69
|
return entities;
|
|
78
70
|
};
|
|
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
|
-
*/
|
|
83
|
-
export const destroyEntities = (world, entities) => {
|
|
84
|
-
for (const entity of entities) {
|
|
85
|
-
if (world.has(entity)) {
|
|
86
|
-
entity.destroy();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
71
|
const getRenderArmModels = (renderArmModels) => {
|
|
91
72
|
switch (renderArmModels) {
|
|
92
73
|
case RenderArmModels.COLLIDERS: {
|
|
@@ -101,177 +82,3 @@ const getRenderArmModels = (renderArmModels) => {
|
|
|
101
82
|
}
|
|
102
83
|
}
|
|
103
84
|
};
|
|
104
|
-
const spawnTransformEntity = (world, transform) => {
|
|
105
|
-
const entityTraits = [
|
|
106
|
-
traits.Name(transform.referenceFrame),
|
|
107
|
-
traits.Geometry(transform.physicalObject ?? Geometry.fromJson({})),
|
|
108
|
-
traits.Center(transform.physicalObject?.center),
|
|
109
|
-
traits.SnapshotAPI,
|
|
110
|
-
traits.Removable,
|
|
111
|
-
];
|
|
112
|
-
const poseInFrame = transform.poseInObserverFrame;
|
|
113
|
-
entityTraits.push(traits.Pose(poseInFrame?.pose), traits.Parent(poseInFrame?.referenceFrame));
|
|
114
|
-
if (transform.metadata) {
|
|
115
|
-
const metadata = parseMetadata(transform.metadata.fields);
|
|
116
|
-
if (metadata.colors)
|
|
117
|
-
addColorTraits(entityTraits, metadata.colors);
|
|
118
|
-
}
|
|
119
|
-
return world.spawn(...entityTraits);
|
|
120
|
-
};
|
|
121
|
-
const spawnEntitiesFromDrawing = (world, drawing) => {
|
|
122
|
-
const entities = [];
|
|
123
|
-
const poseInFrame = drawing.poseInObserverFrame;
|
|
124
|
-
const parent = poseInFrame?.referenceFrame;
|
|
125
|
-
const { geometryType } = drawing.physicalObject ?? {};
|
|
126
|
-
if (geometryType?.case === 'arrows') {
|
|
127
|
-
const poses = asFloat32Array(geometryType.value.poses);
|
|
128
|
-
const colors = drawing.metadata?.colors;
|
|
129
|
-
const entityTraits = [
|
|
130
|
-
traits.Name(drawing.referenceFrame),
|
|
131
|
-
traits.Pose(poseInFrame?.pose),
|
|
132
|
-
traits.Positions(poses),
|
|
133
|
-
];
|
|
134
|
-
if (parent) {
|
|
135
|
-
entityTraits.push(traits.Parent(parent));
|
|
136
|
-
}
|
|
137
|
-
if (colors) {
|
|
138
|
-
entityTraits.push(traits.Colors(colors));
|
|
139
|
-
}
|
|
140
|
-
const entity = world.spawn(...entityTraits, traits.Arrows({ headAtPose: true }), traits.Instances({ count: poses.length / STRIDE.ARROWS }), traits.SnapshotAPI, traits.Removable);
|
|
141
|
-
entities.push(entity);
|
|
142
|
-
}
|
|
143
|
-
else if (geometryType?.case === 'model') {
|
|
144
|
-
const rootEntityTraits = [
|
|
145
|
-
traits.Name(drawing.referenceFrame),
|
|
146
|
-
traits.Pose(poseInFrame?.pose),
|
|
147
|
-
traits.ReferenceFrame,
|
|
148
|
-
];
|
|
149
|
-
if (parent) {
|
|
150
|
-
rootEntityTraits.push(traits.Parent(parent));
|
|
151
|
-
}
|
|
152
|
-
const rootEntity = world.spawn(...rootEntityTraits, traits.SnapshotAPI, traits.Removable);
|
|
153
|
-
entities.push(rootEntity);
|
|
154
|
-
let i = 1;
|
|
155
|
-
for (const asset of geometryType.value.assets) {
|
|
156
|
-
const entityTraits = [
|
|
157
|
-
traits.Name(`${drawing.referenceFrame} model ${i++}`),
|
|
158
|
-
traits.Parent(drawing.referenceFrame),
|
|
159
|
-
];
|
|
160
|
-
if (geometryType.value.scale) {
|
|
161
|
-
entityTraits.push(traits.Scale(geometryType.value.scale));
|
|
162
|
-
}
|
|
163
|
-
if (asset.content.case === 'url') {
|
|
164
|
-
entityTraits.push(traits.GLTF({
|
|
165
|
-
source: { url: asset.content.value },
|
|
166
|
-
animationName: geometryType.value.animationName ?? '',
|
|
167
|
-
}));
|
|
168
|
-
}
|
|
169
|
-
else if (asset.content.value) {
|
|
170
|
-
entityTraits.push(traits.GLTF({
|
|
171
|
-
source: { glb: asset.content.value },
|
|
172
|
-
animationName: geometryType.value.animationName ?? '',
|
|
173
|
-
}));
|
|
174
|
-
}
|
|
175
|
-
const entity = world.spawn(...entityTraits, traits.SnapshotAPI, traits.Removable);
|
|
176
|
-
entities.push(entity);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
const entityTraits = [
|
|
181
|
-
traits.Name(drawing.referenceFrame),
|
|
182
|
-
traits.Pose(poseInFrame?.pose),
|
|
183
|
-
];
|
|
184
|
-
if (parent && parent !== 'world') {
|
|
185
|
-
entityTraits.push(traits.Parent);
|
|
186
|
-
}
|
|
187
|
-
if (drawing.physicalObject?.center) {
|
|
188
|
-
entityTraits.push(traits.Center(drawing.physicalObject.center));
|
|
189
|
-
}
|
|
190
|
-
if (geometryType?.case === 'line') {
|
|
191
|
-
const positions = asFloat32Array(geometryType.value.positions);
|
|
192
|
-
for (let i = 0, l = positions.length; i < l; i += 1) {
|
|
193
|
-
positions[i] *= 0.001;
|
|
194
|
-
}
|
|
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
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else if (geometryType?.case === 'points') {
|
|
212
|
-
const positions = asFloat32Array(geometryType.value.positions);
|
|
213
|
-
for (let i = 0, l = positions.length; i < l; i += 1) {
|
|
214
|
-
positions[i] *= 0.001;
|
|
215
|
-
}
|
|
216
|
-
const colors = drawing.metadata?.colors;
|
|
217
|
-
const numPoints = positions.length / STRIDE.POSITIONS;
|
|
218
|
-
const vertexColors = colors && isPerVertexColors(colors, numPoints) ? colors : undefined;
|
|
219
|
-
const geometry = createBufferGeometry(positions, vertexColors);
|
|
220
|
-
entityTraits.push(traits.BufferGeometry(geometry));
|
|
221
|
-
if (colors && !vertexColors) {
|
|
222
|
-
addColorTraits(entityTraits, colors);
|
|
223
|
-
}
|
|
224
|
-
if (geometryType.value.pointSize) {
|
|
225
|
-
entityTraits.push(traits.PointSize(geometryType.value.pointSize * 0.001));
|
|
226
|
-
}
|
|
227
|
-
entityTraits.push(traits.Points);
|
|
228
|
-
}
|
|
229
|
-
else if (geometryType?.case === 'nurbs') {
|
|
230
|
-
const { degree = 3, knots: knotsBuffer, weights: weightsBuffer, controlPoints: controlPointsBuffer, } = geometryType.value;
|
|
231
|
-
const knots = [...asFloat32Array(knotsBuffer)];
|
|
232
|
-
const weights = weightsBuffer
|
|
233
|
-
? [...asFloat32Array(weightsBuffer)]
|
|
234
|
-
: [];
|
|
235
|
-
const controlPointsArray = [...asFloat32Array(controlPointsBuffer)];
|
|
236
|
-
const controlPoints = [];
|
|
237
|
-
for (let i = 0, j = 0, l = controlPointsArray.length / STRIDE.NURBS_CONTROL_POINTS; i < l; i += STRIDE.NURBS_CONTROL_POINTS, j += 1) {
|
|
238
|
-
vec3
|
|
239
|
-
.set(controlPointsArray[0], controlPointsArray[1], controlPointsArray[2])
|
|
240
|
-
.multiplyScalar(0.001);
|
|
241
|
-
controlPoints.push(new Vector4(vec3.x, vec3.y, vec3.z, weights[j] ?? 0));
|
|
242
|
-
}
|
|
243
|
-
const curve = new NURBSCurve(degree, knots, controlPoints);
|
|
244
|
-
const numPoints = 600;
|
|
245
|
-
const points = new Float32Array(numPoints * 3);
|
|
246
|
-
const l = numPoints * 3;
|
|
247
|
-
for (let i = 0; i < l; i += 3) {
|
|
248
|
-
curve.getPointAt(i / (l - 1), vec3);
|
|
249
|
-
points[i + 0] = vec3.x;
|
|
250
|
-
points[i + 1] = vec3.y;
|
|
251
|
-
points[i + 2] = vec3.z;
|
|
252
|
-
}
|
|
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
|
-
}
|
|
265
|
-
}
|
|
266
|
-
const entity = world.spawn(...entityTraits, traits.SnapshotAPI, traits.Removable);
|
|
267
|
-
entities.push(entity);
|
|
268
|
-
}
|
|
269
|
-
return entities;
|
|
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,5 @@
|
|
|
1
1
|
import { Box3, BufferGeometry, Color, DynamicDrawUsage, FrontSide, Group, InstancedBufferAttribute, InstancedInterleavedBuffer, InterleavedBufferAttribute, Material, Mesh, RawShaderMaterial, Vector3, } from 'three';
|
|
2
|
+
import { STRIDE } from '../../buffer';
|
|
2
3
|
import { computeBoundingBox } from './box';
|
|
3
4
|
import fragmentShader from './fragment.glsl';
|
|
4
5
|
import { createHeadGeometry, createShaftGeometry, toInstanced } from './geometry';
|
|
@@ -64,8 +65,8 @@ export class InstancedArrows extends Group {
|
|
|
64
65
|
instanceDirection,
|
|
65
66
|
};
|
|
66
67
|
if (!options.uniformColor) {
|
|
67
|
-
const colors = new Uint8Array(this.count *
|
|
68
|
-
const instanceColor = new InstancedBufferAttribute(colors,
|
|
68
|
+
const colors = new Uint8Array(this.count * STRIDE.COLORS_RGB);
|
|
69
|
+
const instanceColor = new InstancedBufferAttribute(colors, STRIDE.COLORS_RGB, true);
|
|
69
70
|
instanceColor.setUsage(DynamicDrawUsage);
|
|
70
71
|
this.attributes.instanceColor = instanceColor;
|
|
71
72
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -25,19 +25,20 @@
|
|
|
25
25
|
"@testing-library/jest-dom": "6.8.0",
|
|
26
26
|
"@testing-library/svelte": "5.2.8",
|
|
27
27
|
"@testing-library/user-event": "^14.6.1",
|
|
28
|
-
"@threlte/core": "8.5.
|
|
29
|
-
"@threlte/extras": "9.
|
|
30
|
-
"@threlte/rapier": "3.4.
|
|
31
|
-
"@threlte/xr": "1.
|
|
28
|
+
"@threlte/core": "8.5.5",
|
|
29
|
+
"@threlte/extras": "9.14.1",
|
|
30
|
+
"@threlte/rapier": "3.4.1",
|
|
31
|
+
"@threlte/xr": "1.5.2",
|
|
32
32
|
"@types/bun": "1.2.21",
|
|
33
33
|
"@types/earcut": "^3.0.0",
|
|
34
34
|
"@types/lodash-es": "4.17.12",
|
|
35
|
-
"@types/three": "0.
|
|
35
|
+
"@types/three": "0.183.1",
|
|
36
36
|
"@typescript-eslint/eslint-plugin": "8.56.1",
|
|
37
37
|
"@typescript-eslint/parser": "8.56.1",
|
|
38
38
|
"@viamrobotics/prime-core": "0.1.5",
|
|
39
39
|
"@viamrobotics/sdk": "0.58.0",
|
|
40
40
|
"@viamrobotics/svelte-sdk": "1.0.1",
|
|
41
|
+
"@vitest/browser": "3.2.4",
|
|
41
42
|
"@vitest/coverage-v8": "^3.2.4",
|
|
42
43
|
"@zag-js/collapsible": "1.22.1",
|
|
43
44
|
"@zag-js/floating-panel": "1.22.1",
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"@zag-js/toggle-group": "1.22.1",
|
|
48
49
|
"@zag-js/tree-view": "1.22.1",
|
|
49
50
|
"camera-controls": "3.1.0",
|
|
51
|
+
"concurrently": "^9.2.1",
|
|
50
52
|
"esbuild": "^0.27.3",
|
|
51
53
|
"eslint": "10.0.2",
|
|
52
54
|
"eslint-config-prettier": "10.1.8",
|
|
@@ -55,7 +57,6 @@
|
|
|
55
57
|
"eslint-plugin-unicorn": "^63.0.0",
|
|
56
58
|
"globals": "16.3.0",
|
|
57
59
|
"idb-keyval": "6.2.2",
|
|
58
|
-
"jsdom": "26.1.0",
|
|
59
60
|
"lucide-svelte": "0.542.0",
|
|
60
61
|
"prettier": "3.6.2",
|
|
61
62
|
"prettier-plugin-svelte": "3.4.0",
|
|
@@ -66,13 +67,13 @@
|
|
|
66
67
|
"svelte-check": "4.4.5",
|
|
67
68
|
"svelte-virtuallists": "1.4.2",
|
|
68
69
|
"tailwindcss": "4.1.13",
|
|
69
|
-
"three": "0.
|
|
70
|
+
"three": "0.183.2",
|
|
70
71
|
"threlte-uikit": "1.2.1",
|
|
71
72
|
"tsx": "4.20.5",
|
|
72
73
|
"type-fest": "^5.0.1",
|
|
73
74
|
"typescript": "5.9.2",
|
|
74
75
|
"typescript-eslint": "8.56.1",
|
|
75
|
-
"vite": "7.
|
|
76
|
+
"vite": "7.3.2",
|
|
76
77
|
"vite-plugin-devtools-json": "1.0.0",
|
|
77
78
|
"vite-plugin-glsl": "^1.5.5",
|
|
78
79
|
"vite-plugin-mkcert": "1.17.8",
|
|
@@ -138,12 +139,14 @@
|
|
|
138
139
|
"earcut": "^3.0.2",
|
|
139
140
|
"filtrex": "^3.1.0",
|
|
140
141
|
"koota": "0.6.5",
|
|
141
|
-
"lodash-es": "4.
|
|
142
|
+
"lodash-es": "4.18.1",
|
|
142
143
|
"three-mesh-bvh": "^0.9.8",
|
|
143
144
|
"uuid-tool": "^2.0.3"
|
|
144
145
|
},
|
|
145
146
|
"scripts": {
|
|
146
|
-
"dev": "
|
|
147
|
+
"dev": "pnpm dev:bun",
|
|
148
|
+
"dev:bun": "tsx server/check-bun && bun run server/server.ts",
|
|
149
|
+
"dev:next": "concurrently \"pnpm dev:bun\" \"go run cmd/draw-server/main.go -port 3030\"",
|
|
147
150
|
"dev:https": "vite dev -- --https",
|
|
148
151
|
"build": "vite build && npm run prepack",
|
|
149
152
|
"build:workers": "node scripts/build-workers.js",
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { BufferGeometry } from 'three'
|
|
3
|
-
|
|
4
|
-
import { useThrelte } from '@threlte/core'
|
|
5
|
-
import { Portal } from '@threlte/extras'
|
|
6
|
-
import { Button } from '@viamrobotics/prime-core'
|
|
7
|
-
import { ElementRect } from 'runed'
|
|
8
|
-
import { BufferGeometryUtils } from 'three/examples/jsm/Addons.js'
|
|
9
|
-
|
|
10
|
-
import DashboardButton from '../overlay/dashboard/Button.svelte'
|
|
11
|
-
import { traits, useWorld } from '../../ecs'
|
|
12
|
-
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
13
|
-
import { createBinaryPCD } from '../../pcd'
|
|
14
|
-
|
|
15
|
-
import FloatingPanel from '../overlay/FloatingPanel.svelte'
|
|
16
|
-
import Lasso from './Lasso.svelte'
|
|
17
|
-
import * as lassoTraits from './traits'
|
|
18
|
-
|
|
19
|
-
interface Props {
|
|
20
|
-
/** Whether to auto-enable lasso mode when the component mounts */
|
|
21
|
-
enabled?: boolean
|
|
22
|
-
|
|
23
|
-
/** Fires when the user has committed to a lasso selection */
|
|
24
|
-
onSelection: (pcd: Blob) => void
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let { enabled = false, onSelection }: Props = $props()
|
|
28
|
-
|
|
29
|
-
const { dom } = useThrelte()
|
|
30
|
-
const world = useWorld()
|
|
31
|
-
const settings = useSettings()
|
|
32
|
-
const isLassoMode = $derived(settings.current.interactionMode === 'lasso')
|
|
33
|
-
|
|
34
|
-
const onCommitClick = () => {
|
|
35
|
-
const entities = world.query(lassoTraits.LassoEnclosedPoints)
|
|
36
|
-
|
|
37
|
-
const geometries: BufferGeometry[] = []
|
|
38
|
-
for (const entity of entities) {
|
|
39
|
-
const geometry = entity.get(traits.BufferGeometry)
|
|
40
|
-
|
|
41
|
-
if (geometry) {
|
|
42
|
-
geometries.push(geometry)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries)
|
|
47
|
-
const positions = mergedGeometry.getAttribute('position').array as Float32Array
|
|
48
|
-
|
|
49
|
-
const pcd = createBinaryPCD(positions)
|
|
50
|
-
|
|
51
|
-
onSelection(pcd)
|
|
52
|
-
|
|
53
|
-
for (const entity of entities) {
|
|
54
|
-
if (world.has(entity)) {
|
|
55
|
-
entity.destroy()
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
$effect(() => {
|
|
61
|
-
if (isLassoMode) {
|
|
62
|
-
settings.current.cameraMode = 'orthographic'
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
$effect(() => {
|
|
67
|
-
if (enabled) {
|
|
68
|
-
settings.current.interactionMode = 'lasso'
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const rect = new ElementRect(() => dom)
|
|
73
|
-
</script>
|
|
74
|
-
|
|
75
|
-
<Portal id="dashboard">
|
|
76
|
-
<fieldset>
|
|
77
|
-
<DashboardButton
|
|
78
|
-
active={isLassoMode}
|
|
79
|
-
icon="selection-drag"
|
|
80
|
-
description="{isLassoMode ? 'Disable' : 'Enable'} lasso selection"
|
|
81
|
-
onclick={() => {
|
|
82
|
-
settings.current.interactionMode = isLassoMode ? 'navigate' : 'lasso'
|
|
83
|
-
}}
|
|
84
|
-
/>
|
|
85
|
-
</fieldset>
|
|
86
|
-
</Portal>
|
|
87
|
-
|
|
88
|
-
{#if isLassoMode && rect.height > 0 && rect.width > 0}
|
|
89
|
-
<Lasso />
|
|
90
|
-
|
|
91
|
-
<Portal id="dom">
|
|
92
|
-
<FloatingPanel
|
|
93
|
-
isOpen
|
|
94
|
-
exitable={false}
|
|
95
|
-
title="Lasso"
|
|
96
|
-
defaultSize={{ width: 445, height: 100 }}
|
|
97
|
-
defaultPosition={{ x: rect.width / 2 - 200, y: rect.height - 10 - 100 }}
|
|
98
|
-
>
|
|
99
|
-
<div class="flex items-center gap-4 p-4 text-xs">
|
|
100
|
-
Shift + click and drag to make a lasso selection.
|
|
101
|
-
<Button
|
|
102
|
-
onclick={onCommitClick}
|
|
103
|
-
variant="success">Commit selection</Button
|
|
104
|
-
>
|
|
105
|
-
</div>
|
|
106
|
-
</FloatingPanel>
|
|
107
|
-
</Portal>
|
|
108
|
-
{/if}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Hand } from '@threlte/xr'
|
|
3
|
-
|
|
4
|
-
const onpinchstart = () => {
|
|
5
|
-
// Pinch started
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const onpinchend = () => {
|
|
9
|
-
// Pinch ended
|
|
10
|
-
}
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<Hand
|
|
14
|
-
left
|
|
15
|
-
{onpinchstart}
|
|
16
|
-
{onpinchend}
|
|
17
|
-
></Hand>
|
|
18
|
-
|
|
19
|
-
<Hand
|
|
20
|
-
right
|
|
21
|
-
{onpinchstart}
|
|
22
|
-
{onpinchend}
|
|
23
|
-
></Hand>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const Hands: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type Hands = InstanceType<typeof Hands>;
|
|
18
|
-
export default Hands;
|