@viamrobotics/motion-tools 1.26.1 → 1.27.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.js +42 -29
- package/dist/assert.d.ts +13 -0
- package/dist/assert.js +20 -0
- package/dist/buf/common/v1/common_pb.d.ts +19 -0
- package/dist/buf/common/v1/common_pb.js +32 -0
- package/dist/components/BatchedArrows.svelte +43 -45
- package/dist/components/Entities/Arrows/Arrows.svelte +35 -29
- package/dist/components/Entities/Entities.svelte +3 -8
- package/dist/components/Entities/Frame.svelte +31 -32
- package/dist/components/Entities/Frame.svelte.d.ts +0 -2
- package/dist/components/Entities/GLTF.svelte +27 -36
- package/dist/components/Entities/Geometry.svelte +35 -24
- package/dist/components/Entities/Line.svelte +37 -43
- package/dist/components/Entities/Mesh.svelte +12 -18
- package/dist/components/Entities/Points.svelte +25 -28
- package/dist/components/Entities/Pose.svelte +17 -24
- package/dist/components/Entities/Pose.svelte.d.ts +1 -4
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +40 -41
- package/dist/components/Scene.svelte +7 -1
- package/dist/components/SceneProviders.svelte +2 -1
- package/dist/components/SelectedTransformControls.svelte +57 -34
- package/dist/components/StaticGeometries.svelte +1 -1
- package/dist/components/hover/HoveredEntity.svelte +33 -3
- package/dist/components/hover/LinkedHoveredEntity.svelte +2 -3
- package/dist/components/overlay/Details.svelte +72 -94
- package/dist/components/overlay/__tests__/__fixtures__/entity.js +14 -17
- package/dist/components/overlay/left-pane/Tree.svelte +9 -9
- package/dist/components/overlay/left-pane/Tree.svelte.d.ts +1 -2
- package/dist/components/overlay/left-pane/TreeContainer.svelte +4 -15
- package/dist/components/overlay/left-pane/TreeNode.svelte +1 -1
- package/dist/components/overlay/left-pane/TreeNode.svelte.d.ts +1 -1
- package/dist/components/overlay/left-pane/useTree.svelte.d.ts +14 -0
- package/dist/components/overlay/left-pane/useTree.svelte.js +63 -0
- package/dist/draw.js +24 -9
- package/dist/ecs/index.d.ts +1 -0
- package/dist/ecs/index.js +1 -0
- package/dist/ecs/provideWorldMatrix.svelte.d.ts +8 -0
- package/dist/ecs/provideWorldMatrix.svelte.js +13 -0
- package/dist/ecs/traits.d.ts +41 -50
- package/dist/ecs/traits.js +57 -29
- package/dist/ecs/useTrait.svelte.d.ts +1 -6
- package/dist/ecs/useTrait.svelte.js +21 -13
- package/dist/ecs/worldMatrix.d.ts +10 -0
- package/dist/ecs/worldMatrix.js +138 -0
- package/dist/editing/FrameEditSession.js +31 -18
- package/dist/hooks/use3DModels.svelte.js +1 -1
- package/dist/hooks/useConfigFrames.svelte.js +12 -0
- package/dist/hooks/useDrawAPI.svelte.js +14 -6
- package/dist/hooks/useDrawService.svelte.js +4 -7
- package/dist/hooks/useFrames.svelte.js +23 -11
- package/dist/hooks/useGeometries.svelte.js +11 -3
- package/dist/hooks/usePartConfig.svelte.js +43 -6
- package/dist/hooks/useWorldState.svelte.js +10 -2
- package/dist/plugins/bvh.svelte.js +37 -26
- package/dist/transform.js +55 -21
- package/package.json +3 -3
- package/dist/components/overlay/left-pane/buildTree.d.ts +0 -13
- package/dist/components/overlay/left-pane/buildTree.js +0 -48
|
@@ -17,11 +17,14 @@ export const bvh = (raycaster, options) => {
|
|
|
17
17
|
injectPlugin('bvh', (args) => {
|
|
18
18
|
const { props } = $derived(args);
|
|
19
19
|
const opts = $derived(props.bvh ? { ...bvhOptions, ...props.bvh } : bvhOptions);
|
|
20
|
+
let computed = false;
|
|
21
|
+
let helper;
|
|
20
22
|
$effect(() => {
|
|
21
23
|
const { ref } = args;
|
|
22
|
-
if (
|
|
24
|
+
if (computed)
|
|
25
|
+
return;
|
|
26
|
+
if (opts.enabled === false)
|
|
23
27
|
return;
|
|
24
|
-
}
|
|
25
28
|
if (isInstanceOf(ref, 'Points') &&
|
|
26
29
|
/**
|
|
27
30
|
* This check is necessary, there are some strange cases where points are coming in from PCDs without any position data
|
|
@@ -31,28 +34,12 @@ export const bvh = (raycaster, options) => {
|
|
|
31
34
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
32
35
|
ref.raycast = acceleratedRaycast;
|
|
33
36
|
computeBoundsTree.call(ref.geometry, { type: PointsBVH, ...opts });
|
|
34
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
35
|
-
if (helper)
|
|
36
|
-
ref.add(helper);
|
|
37
|
-
return () => {
|
|
38
|
-
ref.raycast = Points.prototype.raycast;
|
|
39
|
-
if (helper)
|
|
40
|
-
ref.remove(helper);
|
|
41
|
-
};
|
|
42
37
|
}
|
|
43
38
|
else if (isInstanceOf(ref, 'BatchedMesh')) {
|
|
44
39
|
/* @ts-expect-error Some sort of ambient type is conflicing here, likely from @threlte/extras */
|
|
45
40
|
ref.geometry.computeBoundsTree = computeBatchedBoundsTree;
|
|
46
41
|
ref.geometry.disposeBoundsTree = disposeBatchedBoundsTree;
|
|
47
42
|
ref.raycast = acceleratedRaycast;
|
|
48
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
49
|
-
if (helper)
|
|
50
|
-
ref.add(helper);
|
|
51
|
-
return () => {
|
|
52
|
-
ref.raycast = BatchedMesh.prototype.raycast;
|
|
53
|
-
if (helper)
|
|
54
|
-
ref.remove(helper);
|
|
55
|
-
};
|
|
56
43
|
}
|
|
57
44
|
else if (isInstanceOf(ref, 'Mesh') &&
|
|
58
45
|
/**
|
|
@@ -64,15 +51,39 @@ export const bvh = (raycaster, options) => {
|
|
|
64
51
|
ref.geometry.disposeBoundsTree = disposeBoundsTree;
|
|
65
52
|
ref.raycast = acceleratedRaycast;
|
|
66
53
|
computeBoundsTree.call(ref.geometry, opts);
|
|
67
|
-
const helper = opts.helper ? new BVHHelper(ref) : undefined;
|
|
68
|
-
if (helper)
|
|
69
|
-
ref.add(helper);
|
|
70
|
-
return () => {
|
|
71
|
-
ref.raycast = Mesh.prototype.raycast;
|
|
72
|
-
if (helper)
|
|
73
|
-
ref.remove(helper);
|
|
74
|
-
};
|
|
75
54
|
}
|
|
55
|
+
else {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (opts.helper) {
|
|
59
|
+
helper = new BVHHelper(ref);
|
|
60
|
+
ref.add(helper);
|
|
61
|
+
}
|
|
62
|
+
computed = true;
|
|
63
|
+
});
|
|
64
|
+
$effect(() => {
|
|
65
|
+
const { ref } = args;
|
|
66
|
+
return () => {
|
|
67
|
+
if (!computed)
|
|
68
|
+
return;
|
|
69
|
+
if (isInstanceOf(ref, 'Points')) {
|
|
70
|
+
ref.geometry.disposeBoundsTree?.();
|
|
71
|
+
ref.raycast = Points.prototype.raycast;
|
|
72
|
+
}
|
|
73
|
+
else if (isInstanceOf(ref, 'BatchedMesh')) {
|
|
74
|
+
ref.geometry.disposeBoundsTree?.();
|
|
75
|
+
ref.raycast = BatchedMesh.prototype.raycast;
|
|
76
|
+
}
|
|
77
|
+
else if (isInstanceOf(ref, 'Mesh')) {
|
|
78
|
+
ref.geometry.disposeBoundsTree?.();
|
|
79
|
+
ref.raycast = Mesh.prototype.raycast;
|
|
80
|
+
}
|
|
81
|
+
if (helper) {
|
|
82
|
+
ref.remove(helper);
|
|
83
|
+
helper = undefined;
|
|
84
|
+
}
|
|
85
|
+
computed = false;
|
|
86
|
+
};
|
|
76
87
|
});
|
|
77
88
|
});
|
|
78
89
|
};
|
package/dist/transform.js
CHANGED
|
@@ -5,6 +5,20 @@ const euler = new Euler();
|
|
|
5
5
|
const ov = new OrientationVector();
|
|
6
6
|
const translation = new Vector3();
|
|
7
7
|
const scale = new Vector3();
|
|
8
|
+
const matA = new Matrix4();
|
|
9
|
+
export const isPoseEqual = (a, b) => {
|
|
10
|
+
if (a === b)
|
|
11
|
+
return true;
|
|
12
|
+
if (!a || !b)
|
|
13
|
+
return false;
|
|
14
|
+
return (a.x === b.x &&
|
|
15
|
+
a.y === b.y &&
|
|
16
|
+
a.z === b.z &&
|
|
17
|
+
a.oX === b.oX &&
|
|
18
|
+
a.oY === b.oY &&
|
|
19
|
+
a.oZ === b.oZ &&
|
|
20
|
+
a.theta === b.theta);
|
|
21
|
+
};
|
|
8
22
|
export const createPose = (pose) => {
|
|
9
23
|
// We should only default to the 0,0,1,0 orientation vector if the entire vector component is missing
|
|
10
24
|
const oZ = pose?.oX === undefined && pose?.oY === undefined && pose?.oZ === undefined ? 1 : (pose?.oZ ?? 0);
|
|
@@ -84,20 +98,31 @@ export const poseToDirection = (pose) => {
|
|
|
84
98
|
ov.set(pose.oX, pose.oY, pose.oZ, MathUtils.degToRad(pose.theta));
|
|
85
99
|
return new Vector3(ov.x, ov.y, ov.z);
|
|
86
100
|
};
|
|
87
|
-
export const
|
|
101
|
+
export const isFinitePose = (pose) => Number.isFinite(pose.x) &&
|
|
102
|
+
Number.isFinite(pose.y) &&
|
|
103
|
+
Number.isFinite(pose.z) &&
|
|
104
|
+
Number.isFinite(pose.oX) &&
|
|
105
|
+
Number.isFinite(pose.oY) &&
|
|
106
|
+
Number.isFinite(pose.oZ) &&
|
|
107
|
+
Number.isFinite(pose.theta);
|
|
108
|
+
/**
|
|
109
|
+
* Build a TRS `Matrix4` (m) from a `Pose` (mm), writing into `matrix`.
|
|
110
|
+
*/
|
|
111
|
+
export const poseToMatrix = (pose, matrix) => {
|
|
88
112
|
ov.set(pose.oX, pose.oY, pose.oZ, MathUtils.degToRad(pose.theta));
|
|
89
113
|
ov.toQuaternion(quaternion);
|
|
90
|
-
const matrix = new Matrix4();
|
|
91
114
|
matrix.makeRotationFromQuaternion(quaternion);
|
|
92
|
-
matrix.setPosition(pose.x, pose.y, pose.z);
|
|
115
|
+
matrix.setPosition(pose.x * 0.001, pose.y * 0.001, pose.z * 0.001);
|
|
93
116
|
return matrix;
|
|
94
117
|
};
|
|
95
|
-
|
|
96
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Decompose a `Matrix4` (m) into a `Pose` (mm), writing into `pose`.
|
|
120
|
+
*/
|
|
121
|
+
export const matrixToPose = (matrix, pose) => {
|
|
97
122
|
matrix.decompose(translation, quaternion, scale);
|
|
98
|
-
pose.x = translation.x;
|
|
99
|
-
pose.y = translation.y;
|
|
100
|
-
pose.z = translation.z;
|
|
123
|
+
pose.x = translation.x * 1000;
|
|
124
|
+
pose.y = translation.y * 1000;
|
|
125
|
+
pose.z = translation.z * 1000;
|
|
101
126
|
ov.setFromQuaternion(quaternion);
|
|
102
127
|
pose.oX = ov.x;
|
|
103
128
|
pose.oY = ov.y;
|
|
@@ -105,16 +130,25 @@ export const matrixToPose = (matrix) => {
|
|
|
105
130
|
pose.theta = MathUtils.radToDeg(ov.th);
|
|
106
131
|
return pose;
|
|
107
132
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
export const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Compose the entity's local-to-parent transform: writes
|
|
135
|
+
* `live × baseline⁻¹ × edited` into `out`. Mirrors the formula
|
|
136
|
+
* `Frame.svelte` uses to blend live kinematics with user-staged edits;
|
|
137
|
+
* `worldMatrix.ts` premultiplies the result by the parent's `WorldMatrix`.
|
|
138
|
+
*/
|
|
139
|
+
export const composeLocalMatrix = (live, baseline, edited, out) => {
|
|
140
|
+
matA.copy(baseline).invert();
|
|
141
|
+
out.copy(live).multiply(matA).multiply(edited);
|
|
142
|
+
return out;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Inverse of `composeLocalMatrix` for the transform controls path:
|
|
146
|
+
* writes `baseline × live⁻¹ × target` into `out`. Solves for the
|
|
147
|
+
* `EditedMatrix` that, blended through `composeLocalMatrix`, renders
|
|
148
|
+
* to `target`.
|
|
149
|
+
*/
|
|
150
|
+
export const solveEditedMatrix = (baseline, live, target, out) => {
|
|
151
|
+
matA.copy(live).invert();
|
|
152
|
+
out.copy(baseline).multiply(matA).multiply(target);
|
|
153
|
+
return out;
|
|
154
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -25,8 +25,8 @@
|
|
|
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.
|
|
28
|
+
"@threlte/core": "8.5.14",
|
|
29
|
+
"@threlte/extras": "9.17.0",
|
|
30
30
|
"@threlte/rapier": "3.4.1",
|
|
31
31
|
"@threlte/xr": "1.6.0",
|
|
32
32
|
"@types/bun": "1.2.21",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Entity, QueryResult, Trait } from 'koota';
|
|
2
|
-
export interface TreeNode {
|
|
3
|
-
entity: Entity;
|
|
4
|
-
parent?: TreeNode;
|
|
5
|
-
children?: TreeNode[];
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Creates a tree representing parent child / relationships from a set of frames.
|
|
9
|
-
*/
|
|
10
|
-
export declare const buildTreeNodes: (entities: QueryResult<[Trait]>) => {
|
|
11
|
-
rootNodes: TreeNode[];
|
|
12
|
-
nodeMap: Record<string, TreeNode | undefined>;
|
|
13
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { hierarchy, traits } from '../../../ecs';
|
|
2
|
-
function sortNodes(nodes) {
|
|
3
|
-
nodes.sort((a, b) => a.entity.get(traits.Name)?.localeCompare(b.entity.get(traits.Name) ?? '') ?? 0);
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Creates a tree representing parent child / relationships from a set of frames.
|
|
7
|
-
*/
|
|
8
|
-
export const buildTreeNodes = (entities) => {
|
|
9
|
-
const nodeMap = {};
|
|
10
|
-
const rootNodes = [];
|
|
11
|
-
const childNodes = [];
|
|
12
|
-
for (const entity of entities) {
|
|
13
|
-
const parent = hierarchy.getParentName(entity);
|
|
14
|
-
const name = entity.get(traits.Name) ?? '';
|
|
15
|
-
const node = { entity };
|
|
16
|
-
nodeMap[name] = node;
|
|
17
|
-
if (!parent || parent === 'world') {
|
|
18
|
-
rootNodes.push(node);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
childNodes.push(node);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
for (const node of childNodes) {
|
|
25
|
-
const parent = hierarchy.getParentName(node.entity);
|
|
26
|
-
if (parent) {
|
|
27
|
-
const parentNode = nodeMap[parent];
|
|
28
|
-
node.parent = parentNode;
|
|
29
|
-
if (parentNode) {
|
|
30
|
-
parentNode.children ??= [];
|
|
31
|
-
parentNode.children?.push(node);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
for (const node of rootNodes) {
|
|
36
|
-
if (!node.children)
|
|
37
|
-
continue;
|
|
38
|
-
sortNodes(node.children);
|
|
39
|
-
}
|
|
40
|
-
for (const node of childNodes) {
|
|
41
|
-
if (!node.children)
|
|
42
|
-
continue;
|
|
43
|
-
sortNodes(node.children);
|
|
44
|
-
}
|
|
45
|
-
sortNodes(rootNodes);
|
|
46
|
-
sortNodes(childNodes);
|
|
47
|
-
return { rootNodes, nodeMap };
|
|
48
|
-
};
|