@viamrobotics/motion-tools 0.12.0 → 0.13.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/Detail.svelte.d.ts +41 -0
- package/dist/Detail.svelte.js +147 -0
- package/dist/WorldObject.svelte.d.ts +6 -3
- package/dist/WorldObject.svelte.js +47 -2
- package/dist/components/App.svelte +44 -1
- package/dist/components/App.svelte.d.ts +8 -0
- package/dist/components/Details.svelte +304 -105
- package/dist/components/LiveUpdatesBanner.svelte +39 -0
- package/dist/components/LiveUpdatesBanner.svelte.d.ts +3 -0
- package/dist/components/Selected.svelte +10 -10
- package/dist/components/Tree/buildTree.js +1 -1
- package/dist/components/WorldObjects.svelte +3 -1
- package/dist/components/weblab/WeblabActive.svelte +3 -2
- package/dist/components/weblab/WeblabActive.svelte.d.ts +1 -0
- package/dist/hooks/useFrames.svelte.d.ts +1 -0
- package/dist/hooks/useFrames.svelte.js +167 -3
- package/dist/hooks/usePartConfig.svelte.d.ts +98 -0
- package/dist/hooks/usePartConfig.svelte.js +230 -0
- package/dist/hooks/usePose.svelte.js +6 -1
- package/dist/hooks/useSettings.svelte.d.ts +1 -0
- package/dist/hooks/useSettings.svelte.js +1 -0
- package/dist/three/BatchedArrow.d.ts +3 -2
- package/dist/three/BatchedArrow.js +3 -1
- package/dist/three/OBBHelper.d.ts +14 -0
- package/dist/three/OBBHelper.js +71 -0
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { WorldObject } from './lib';
|
|
2
|
+
import type { Geometries } from './WorldObject.svelte';
|
|
3
|
+
import type { Pose } from '@viamrobotics/sdk';
|
|
4
|
+
type UpdateFrameCallback = {
|
|
5
|
+
(componentName: string, referenceFrame: string, pose: Pose, geometry?: {
|
|
6
|
+
type: 'none' | 'box' | 'sphere' | 'capsule';
|
|
7
|
+
r?: number;
|
|
8
|
+
l?: number;
|
|
9
|
+
x?: number;
|
|
10
|
+
y?: number;
|
|
11
|
+
z?: number;
|
|
12
|
+
}): void;
|
|
13
|
+
};
|
|
14
|
+
export declare class DetailConfigUpdater {
|
|
15
|
+
private object;
|
|
16
|
+
private referenceFrame;
|
|
17
|
+
private updateFrame;
|
|
18
|
+
constructor(object: () => WorldObject<Geometries> | undefined, updateFrame: UpdateFrameCallback, referenceFrame: () => string);
|
|
19
|
+
updateLocalPosition: ({ x, y, z }: {
|
|
20
|
+
x?: number;
|
|
21
|
+
y?: number;
|
|
22
|
+
z?: number;
|
|
23
|
+
}) => void;
|
|
24
|
+
updateLocalOrientation: ({ oX, oY, oZ, theta, }: {
|
|
25
|
+
oX?: number;
|
|
26
|
+
oY?: number;
|
|
27
|
+
oZ?: number;
|
|
28
|
+
theta?: number;
|
|
29
|
+
}) => void;
|
|
30
|
+
updateGeometry: (geometry: {
|
|
31
|
+
type: "none" | "box" | "sphere" | "capsule";
|
|
32
|
+
r?: number;
|
|
33
|
+
l?: number;
|
|
34
|
+
x?: number;
|
|
35
|
+
y?: number;
|
|
36
|
+
z?: number;
|
|
37
|
+
}) => void;
|
|
38
|
+
setFrameParent: (parentName: string) => void;
|
|
39
|
+
setGeometryType: (type: "none" | "box" | "sphere" | "capsule") => void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
export class DetailConfigUpdater {
|
|
2
|
+
object;
|
|
3
|
+
referenceFrame;
|
|
4
|
+
updateFrame;
|
|
5
|
+
constructor(object, updateFrame, referenceFrame) {
|
|
6
|
+
this.referenceFrame = referenceFrame;
|
|
7
|
+
this.object = object;
|
|
8
|
+
this.updateFrame = updateFrame;
|
|
9
|
+
}
|
|
10
|
+
updateLocalPosition = ({ x, y, z }) => {
|
|
11
|
+
const object = this.object();
|
|
12
|
+
if (!object)
|
|
13
|
+
return;
|
|
14
|
+
object.localEditedPose.x = x ?? object.localEditedPose.x;
|
|
15
|
+
object.localEditedPose.y = y ?? object.localEditedPose.y;
|
|
16
|
+
object.localEditedPose.z = z ?? object.localEditedPose.z;
|
|
17
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
18
|
+
x: x ?? object.localEditedPose.x,
|
|
19
|
+
y: y ?? object.localEditedPose.y,
|
|
20
|
+
z: z ?? object.localEditedPose.z,
|
|
21
|
+
oX: object.localEditedPose.oX,
|
|
22
|
+
oY: object.localEditedPose.oY,
|
|
23
|
+
oZ: object.localEditedPose.oZ,
|
|
24
|
+
theta: object.localEditedPose.theta,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
updateLocalOrientation = ({ oX, oY, oZ, theta, }) => {
|
|
28
|
+
const object = this.object();
|
|
29
|
+
if (!object)
|
|
30
|
+
return;
|
|
31
|
+
object.localEditedPose.oX = oX ?? object.localEditedPose.oX;
|
|
32
|
+
object.localEditedPose.oY = oY ?? object.localEditedPose.oY;
|
|
33
|
+
object.localEditedPose.oZ = oZ ?? object.localEditedPose.oZ;
|
|
34
|
+
object.localEditedPose.theta = theta ?? object.localEditedPose.theta;
|
|
35
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
36
|
+
oX: oX ?? object.localEditedPose.oX,
|
|
37
|
+
oY: oY ?? object.localEditedPose.oY,
|
|
38
|
+
oZ: oZ ?? object.localEditedPose.oZ,
|
|
39
|
+
theta: theta ?? object.localEditedPose.theta,
|
|
40
|
+
x: object.localEditedPose.x,
|
|
41
|
+
y: object.localEditedPose.y,
|
|
42
|
+
z: object.localEditedPose.z,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
updateGeometry = (geometry) => {
|
|
46
|
+
const object = this.object();
|
|
47
|
+
if (!object)
|
|
48
|
+
return;
|
|
49
|
+
let geometryObject;
|
|
50
|
+
if (geometry.type === 'box') {
|
|
51
|
+
const currentGeometry = object.geometry?.geometryType.value;
|
|
52
|
+
geometryObject = {
|
|
53
|
+
type: 'box',
|
|
54
|
+
x: geometry.x ?? currentGeometry?.dimsMm?.x,
|
|
55
|
+
y: geometry.y ?? currentGeometry?.dimsMm?.y,
|
|
56
|
+
z: geometry.z ?? currentGeometry?.dimsMm?.z,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else if (geometry.type === 'sphere') {
|
|
60
|
+
const currentGeometry = object.geometry?.geometryType.value;
|
|
61
|
+
geometryObject = {
|
|
62
|
+
type: 'sphere',
|
|
63
|
+
r: geometry.r ?? currentGeometry?.radiusMm,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
else if (geometry.type === 'capsule') {
|
|
67
|
+
const currentGeometry = object.geometry?.geometryType.value;
|
|
68
|
+
geometryObject = {
|
|
69
|
+
type: 'capsule',
|
|
70
|
+
r: geometry.r ?? currentGeometry?.radiusMm,
|
|
71
|
+
l: geometry.l ?? currentGeometry?.lengthMm,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
75
|
+
x: object.localEditedPose.x,
|
|
76
|
+
y: object.localEditedPose.y,
|
|
77
|
+
z: object.localEditedPose.z,
|
|
78
|
+
oX: object.localEditedPose.oX,
|
|
79
|
+
oY: object.localEditedPose.oY,
|
|
80
|
+
oZ: object.localEditedPose.oZ,
|
|
81
|
+
theta: object.localEditedPose.theta,
|
|
82
|
+
}, { ...geometryObject });
|
|
83
|
+
};
|
|
84
|
+
setFrameParent = (parentName) => {
|
|
85
|
+
const object = this.object();
|
|
86
|
+
if (!object)
|
|
87
|
+
return;
|
|
88
|
+
this.updateFrame(object.name ?? '', parentName, {
|
|
89
|
+
x: object.localEditedPose.x,
|
|
90
|
+
y: object.localEditedPose.y,
|
|
91
|
+
z: object.localEditedPose.z,
|
|
92
|
+
oX: object.localEditedPose.oX,
|
|
93
|
+
oY: object.localEditedPose.oY,
|
|
94
|
+
oZ: object.localEditedPose.oZ,
|
|
95
|
+
theta: object.localEditedPose.theta,
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
setGeometryType = (type) => {
|
|
99
|
+
const object = this.object();
|
|
100
|
+
if (!object)
|
|
101
|
+
return;
|
|
102
|
+
if (type === 'none') {
|
|
103
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
104
|
+
x: object.localEditedPose.x,
|
|
105
|
+
y: object.localEditedPose.y,
|
|
106
|
+
z: object.localEditedPose.z,
|
|
107
|
+
oX: object.localEditedPose.oX,
|
|
108
|
+
oY: object.localEditedPose.oY,
|
|
109
|
+
oZ: object.localEditedPose.oZ,
|
|
110
|
+
theta: object.localEditedPose.theta,
|
|
111
|
+
}, { type: 'none' });
|
|
112
|
+
}
|
|
113
|
+
else if (type === 'box') {
|
|
114
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
115
|
+
x: object.localEditedPose.x,
|
|
116
|
+
y: object.localEditedPose.y,
|
|
117
|
+
z: object.localEditedPose.z,
|
|
118
|
+
oX: object.localEditedPose.oX,
|
|
119
|
+
oY: object.localEditedPose.oY,
|
|
120
|
+
oZ: object.localEditedPose.oZ,
|
|
121
|
+
theta: object.localEditedPose.theta,
|
|
122
|
+
}, { type: 'box', x: 100, y: 100, z: 100 });
|
|
123
|
+
}
|
|
124
|
+
else if (type === 'sphere') {
|
|
125
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
126
|
+
x: object.localEditedPose.x,
|
|
127
|
+
y: object.localEditedPose.y,
|
|
128
|
+
z: object.localEditedPose.z,
|
|
129
|
+
oX: object.localEditedPose.oX,
|
|
130
|
+
oY: object.localEditedPose.oY,
|
|
131
|
+
oZ: object.localEditedPose.oZ,
|
|
132
|
+
theta: object.localEditedPose.theta,
|
|
133
|
+
}, { type: 'sphere', r: 100 });
|
|
134
|
+
}
|
|
135
|
+
else if (type === 'capsule') {
|
|
136
|
+
this.updateFrame(object.name ?? '', this.referenceFrame(), {
|
|
137
|
+
x: object.localEditedPose.x,
|
|
138
|
+
y: object.localEditedPose.y,
|
|
139
|
+
z: object.localEditedPose.z,
|
|
140
|
+
oX: object.localEditedPose.oX,
|
|
141
|
+
oY: object.localEditedPose.oY,
|
|
142
|
+
oZ: object.localEditedPose.oZ,
|
|
143
|
+
theta: object.localEditedPose.theta,
|
|
144
|
+
}, { type: 'capsule', r: 20, l: 100 });
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Geometry, Pose, TransformWithUUID } from '@viamrobotics/sdk';
|
|
2
|
-
import { BatchedMesh,
|
|
2
|
+
import { BatchedMesh, Object3D, Vector3, type ColorRepresentation } from 'three';
|
|
3
|
+
import type { OBB } from 'three/addons/math/OBB.js';
|
|
3
4
|
export type PointsGeometry = {
|
|
4
5
|
center: undefined;
|
|
5
6
|
geometryType: {
|
|
@@ -30,15 +31,17 @@ export type Metadata = {
|
|
|
30
31
|
id: number;
|
|
31
32
|
object: BatchedMesh;
|
|
32
33
|
};
|
|
33
|
-
getBoundingBoxAt?: (box:
|
|
34
|
+
getBoundingBoxAt?: (box: OBB) => void;
|
|
34
35
|
};
|
|
36
|
+
export declare const determinePose: (object: WorldObject, pose: WorldObject["pose"] | undefined) => WorldObject["pose"];
|
|
35
37
|
export declare class WorldObject<T extends Geometries = Geometries> {
|
|
36
38
|
uuid: string;
|
|
37
39
|
name: string;
|
|
38
|
-
referenceFrame: string;
|
|
40
|
+
referenceFrame: string | undefined;
|
|
39
41
|
pose: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
|
|
40
42
|
geometry?: T;
|
|
41
43
|
metadata: Metadata;
|
|
44
|
+
localEditedPose: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
|
|
42
45
|
constructor(name: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
|
|
43
46
|
}
|
|
44
47
|
export declare const fromTransform: (transform: TransformWithUUID) => WorldObject<import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Geometry>>;
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
-
import { BatchedMesh,
|
|
1
|
+
import { BatchedMesh, Color, MathUtils, Matrix4, Object3D, Quaternion, Vector3, } from 'three';
|
|
2
2
|
import { createPose } from './transform';
|
|
3
|
+
export const determinePose = (object, pose) => {
|
|
4
|
+
if (pose === undefined) {
|
|
5
|
+
return object.localEditedPose;
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
const poseNetwork = poseToMatrix(object.pose);
|
|
9
|
+
const poseUsePose = poseToMatrix(pose);
|
|
10
|
+
const poseLocalEditedPose = poseToMatrix(object.localEditedPose);
|
|
11
|
+
const poseNetworkInverse = poseNetwork.invert();
|
|
12
|
+
const resultMatrix = poseUsePose.multiply(poseNetworkInverse).multiply(poseLocalEditedPose);
|
|
13
|
+
return matrixToPose(resultMatrix);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
3
16
|
export class WorldObject {
|
|
4
17
|
uuid;
|
|
5
18
|
name;
|
|
6
|
-
referenceFrame;
|
|
19
|
+
referenceFrame = $state.raw();
|
|
7
20
|
pose = $state.raw(createPose());
|
|
8
21
|
geometry;
|
|
9
22
|
metadata;
|
|
23
|
+
localEditedPose = $state.raw(createPose());
|
|
10
24
|
constructor(name, pose, parent = 'world', geometry, metadata) {
|
|
11
25
|
this.uuid = MathUtils.generateUUID();
|
|
12
26
|
this.name = name;
|
|
@@ -15,6 +29,7 @@ export class WorldObject {
|
|
|
15
29
|
this.metadata = metadata ?? {};
|
|
16
30
|
if (pose) {
|
|
17
31
|
this.pose = pose;
|
|
32
|
+
this.localEditedPose = { ...pose };
|
|
18
33
|
}
|
|
19
34
|
}
|
|
20
35
|
}
|
|
@@ -65,3 +80,33 @@ export const fromTransform = (transform) => {
|
|
|
65
80
|
worldObject.uuid = transform.uuidString;
|
|
66
81
|
return worldObject;
|
|
67
82
|
};
|
|
83
|
+
const poseToMatrix = (pose) => {
|
|
84
|
+
const matrix = new Matrix4();
|
|
85
|
+
const poseQuaternion = new Quaternion().setFromAxisAngle(new Vector3(pose.oX, pose.oY, pose.oZ), pose.theta * (Math.PI / 180));
|
|
86
|
+
matrix.makeRotationFromQuaternion(poseQuaternion);
|
|
87
|
+
matrix.setPosition(new Vector3(pose.x, pose.y, pose.z));
|
|
88
|
+
return matrix;
|
|
89
|
+
};
|
|
90
|
+
const matrixToPose = (matrix) => {
|
|
91
|
+
const pose = createPose();
|
|
92
|
+
const translation = new Vector3();
|
|
93
|
+
const quaternion = new Quaternion();
|
|
94
|
+
matrix.decompose(translation, quaternion, new Vector3());
|
|
95
|
+
pose.x = translation.x;
|
|
96
|
+
pose.y = translation.y;
|
|
97
|
+
pose.z = translation.z;
|
|
98
|
+
const s = Math.sqrt(1 - quaternion.w * quaternion.w);
|
|
99
|
+
if (s < 0.000001) {
|
|
100
|
+
pose.oX = 0;
|
|
101
|
+
pose.oY = 0;
|
|
102
|
+
pose.oZ = 1;
|
|
103
|
+
pose.theta = 0;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
pose.oX = quaternion.x / s;
|
|
107
|
+
pose.oY = quaternion.y / s;
|
|
108
|
+
pose.oZ = quaternion.z / s;
|
|
109
|
+
pose.theta = Math.acos(quaternion.w) * 2 * (180 / Math.PI);
|
|
110
|
+
}
|
|
111
|
+
return pose;
|
|
112
|
+
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Canvas } from '@threlte/core'
|
|
4
4
|
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
|
5
5
|
import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
|
|
6
|
+
import type { Struct } from '@viamrobotics/sdk'
|
|
6
7
|
|
|
7
8
|
import Scene from './Scene.svelte'
|
|
8
9
|
import TreeContainer from './Tree/TreeContainer.svelte'
|
|
@@ -16,15 +17,33 @@
|
|
|
16
17
|
import { provideSettings } from '../hooks/useSettings.svelte'
|
|
17
18
|
import FileDrop from './FileDrop.svelte'
|
|
18
19
|
import WeblabProvider from './weblab/WeblabProvider.svelte'
|
|
20
|
+
import { providePartConfig } from '../hooks/usePartConfig.svelte'
|
|
21
|
+
import { useViamClient } from '@viamrobotics/svelte-sdk'
|
|
22
|
+
import LiveUpdatesBanner from './LiveUpdatesBanner.svelte'
|
|
19
23
|
import ArmPositions from './widgets/ArmPositions.svelte'
|
|
24
|
+
|
|
25
|
+
interface LocalConfigProps {
|
|
26
|
+
getLocalPartConfig: () => Struct
|
|
27
|
+
setLocalPartConfig: (config: Struct) => void
|
|
28
|
+
isDirty: () => boolean
|
|
29
|
+
getComponentToFragId: () => Record<string, string>
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
interface Props {
|
|
21
33
|
partID?: string
|
|
22
34
|
enableKeybindings?: boolean
|
|
23
35
|
children?: Snippet
|
|
36
|
+
localConfigProps?: LocalConfigProps
|
|
24
37
|
}
|
|
25
38
|
|
|
26
|
-
let {
|
|
39
|
+
let {
|
|
40
|
+
partID = '',
|
|
41
|
+
enableKeybindings = true,
|
|
42
|
+
children: appChildren,
|
|
43
|
+
localConfigProps,
|
|
44
|
+
}: Props = $props()
|
|
27
45
|
|
|
46
|
+
const appClient = useViamClient()
|
|
28
47
|
const settings = provideSettings()
|
|
29
48
|
|
|
30
49
|
$effect(() => {
|
|
@@ -36,6 +55,27 @@
|
|
|
36
55
|
provideToast()
|
|
37
56
|
|
|
38
57
|
let root = $state.raw<HTMLElement>()
|
|
58
|
+
let isStandalone = $state(false)
|
|
59
|
+
|
|
60
|
+
if (localConfigProps) {
|
|
61
|
+
isStandalone = false
|
|
62
|
+
providePartConfig({
|
|
63
|
+
appEmbeddedPartConfigProps: {
|
|
64
|
+
isDirty: () => localConfigProps.isDirty(),
|
|
65
|
+
getLocalPartConfig: () => localConfigProps.getLocalPartConfig(),
|
|
66
|
+
setLocalPartConfig: (config: Struct) => localConfigProps.setLocalPartConfig(config),
|
|
67
|
+
getComponentToFragId: () => localConfigProps.getComponentToFragId(),
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
} else {
|
|
71
|
+
isStandalone = true
|
|
72
|
+
providePartConfig({
|
|
73
|
+
standalonePartConfigProps: {
|
|
74
|
+
viamClient: () => appClient?.current,
|
|
75
|
+
partID: () => partID,
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
}
|
|
39
79
|
</script>
|
|
40
80
|
|
|
41
81
|
{#if settings.current.enableQueryDevtools}
|
|
@@ -59,6 +99,9 @@
|
|
|
59
99
|
|
|
60
100
|
<Dashboard {@attach domPortal(root)} />
|
|
61
101
|
<Details {@attach domPortal(root)} />
|
|
102
|
+
{#if isStandalone}
|
|
103
|
+
<LiveUpdatesBanner {@attach domPortal(root)} />
|
|
104
|
+
{/if}
|
|
62
105
|
|
|
63
106
|
{#if !focus}
|
|
64
107
|
<TreeContainer {@attach domPortal(root)} />
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { Struct } from '@viamrobotics/sdk';
|
|
3
|
+
interface LocalConfigProps {
|
|
4
|
+
getLocalPartConfig: () => Struct;
|
|
5
|
+
setLocalPartConfig: (config: Struct) => void;
|
|
6
|
+
isDirty: () => boolean;
|
|
7
|
+
getComponentToFragId: () => Record<string, string>;
|
|
8
|
+
}
|
|
2
9
|
interface Props {
|
|
3
10
|
partID?: string;
|
|
4
11
|
enableKeybindings?: boolean;
|
|
5
12
|
children?: Snippet;
|
|
13
|
+
localConfigProps?: LocalConfigProps;
|
|
6
14
|
}
|
|
7
15
|
declare const App: import("svelte").Component<Props, {}, "">;
|
|
8
16
|
type App = ReturnType<typeof App>;
|