@viamrobotics/motion-tools 0.1.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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/WorldObject.d.ts +33 -0
- package/dist/WorldObject.js +18 -0
- package/dist/assert.d.ts +14 -0
- package/dist/assert.js +21 -0
- package/dist/color.d.ts +8 -0
- package/dist/color.js +14 -0
- package/dist/components/App.svelte +63 -0
- package/dist/components/App.svelte.d.ts +8 -0
- package/dist/components/AxesHelper.svelte +17 -0
- package/dist/components/AxesHelper.svelte.d.ts +4 -0
- package/dist/components/BentPlaneGeometry.svelte +52 -0
- package/dist/components/BentPlaneGeometry.svelte.d.ts +29 -0
- package/dist/components/Camera.svelte +45 -0
- package/dist/components/Camera.svelte.d.ts +5 -0
- package/dist/components/CameraControls.svelte +82 -0
- package/dist/components/CameraControls.svelte.d.ts +9 -0
- package/dist/components/Details.svelte +161 -0
- package/dist/components/Details.svelte.d.ts +3 -0
- package/dist/components/Detections.svelte +41 -0
- package/dist/components/Detections.svelte.d.ts +3 -0
- package/dist/components/DetectionsPlane.svelte +23 -0
- package/dist/components/DetectionsPlane.svelte.d.ts +21 -0
- package/dist/components/DomPortal.svelte +20 -0
- package/dist/components/DomPortal.svelte.d.ts +5 -0
- package/dist/components/Focus.svelte +49 -0
- package/dist/components/Focus.svelte.d.ts +3 -0
- package/dist/components/Frame.svelte +112 -0
- package/dist/components/Frame.svelte.d.ts +16 -0
- package/dist/components/Frames.svelte +54 -0
- package/dist/components/Frames.svelte.d.ts +18 -0
- package/dist/components/Pointcloud.svelte +55 -0
- package/dist/components/Pointcloud.svelte.d.ts +10 -0
- package/dist/components/Pointclouds.svelte +21 -0
- package/dist/components/Pointclouds.svelte.d.ts +18 -0
- package/dist/components/Pose.svelte +19 -0
- package/dist/components/Pose.svelte.d.ts +12 -0
- package/dist/components/RefreshRate.svelte +47 -0
- package/dist/components/RefreshRate.svelte.d.ts +8 -0
- package/dist/components/Scene.svelte +81 -0
- package/dist/components/Scene.svelte.d.ts +7 -0
- package/dist/components/SceneProviders.svelte +41 -0
- package/dist/components/SceneProviders.svelte.d.ts +9 -0
- package/dist/components/Selected.svelte +44 -0
- package/dist/components/Selected.svelte.d.ts +3 -0
- package/dist/components/Shapes.svelte +49 -0
- package/dist/components/Shapes.svelte.d.ts +18 -0
- package/dist/components/StaticGeometries.svelte +79 -0
- package/dist/components/StaticGeometries.svelte.d.ts +18 -0
- package/dist/components/Tree/Settings.svelte +54 -0
- package/dist/components/Tree/Settings.svelte.d.ts +18 -0
- package/dist/components/Tree/Tree.svelte +204 -0
- package/dist/components/Tree/Tree.svelte.d.ts +10 -0
- package/dist/components/Tree/TreeContainer.svelte +70 -0
- package/dist/components/Tree/TreeContainer.svelte.d.ts +3 -0
- package/dist/components/Tree/buildTree.d.ts +11 -0
- package/dist/components/Tree/buildTree.js +29 -0
- package/dist/components/Tree/useExpanded.svelte.d.ts +5 -0
- package/dist/components/Tree/useExpanded.svelte.js +21 -0
- package/dist/components/WorldObject.svelte +27 -0
- package/dist/components/WorldObject.svelte.d.ts +11 -0
- package/dist/components/XR.svelte +20 -0
- package/dist/components/XR.svelte.d.ts +3 -0
- package/dist/components/models/README.md +5 -0
- package/dist/components/null-states/Connection.svelte +0 -0
- package/dist/components/null-states/Connection.svelte.d.ts +26 -0
- package/dist/components/portal/Portal.svelte +25 -0
- package/dist/components/portal/Portal.svelte.d.ts +8 -0
- package/dist/components/portal/PortalTarget.svelte +18 -0
- package/dist/components/portal/PortalTarget.svelte.d.ts +6 -0
- package/dist/components/portal/index.d.ts +2 -0
- package/dist/components/portal/index.js +2 -0
- package/dist/components/portal/usePortalContext.svelte.d.ts +5 -0
- package/dist/components/portal/usePortalContext.svelte.js +8 -0
- package/dist/components/xr/CameraFeed.svelte +81 -0
- package/dist/components/xr/CameraFeed.svelte.d.ts +6 -0
- package/dist/components/xr/Controllers.svelte +71 -0
- package/dist/components/xr/Controllers.svelte.d.ts +3 -0
- package/dist/components/xr/Draggable.svelte +101 -0
- package/dist/components/xr/Draggable.svelte.d.ts +11 -0
- package/dist/components/xr/HandCollider.svelte +19 -0
- package/dist/components/xr/HandCollider.svelte.d.ts +18 -0
- package/dist/components/xr/Hands.svelte +24 -0
- package/dist/components/xr/Hands.svelte.d.ts +18 -0
- package/dist/components/xr/OriginMarker.svelte +100 -0
- package/dist/components/xr/OriginMarker.svelte.d.ts +3 -0
- package/dist/components/xr/PointDistance.svelte +52 -0
- package/dist/components/xr/PointDistance.svelte.d.ts +3 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useConnectionConfigs.svelte.d.ts +17 -0
- package/dist/hooks/useConnectionConfigs.svelte.js +40 -0
- package/dist/hooks/useControls.svelte.d.ts +7 -0
- package/dist/hooks/useControls.svelte.js +16 -0
- package/dist/hooks/useDraggable.svelte.d.ts +2 -0
- package/dist/hooks/useDraggable.svelte.js +25 -0
- package/dist/hooks/useFrames.svelte.d.ts +9 -0
- package/dist/hooks/useFrames.svelte.js +50 -0
- package/dist/hooks/useGeometries.svelte.d.ts +7 -0
- package/dist/hooks/useGeometries.svelte.js +58 -0
- package/dist/hooks/useMotionClient.svelte.d.ts +8 -0
- package/dist/hooks/useMotionClient.svelte.js +31 -0
- package/dist/hooks/useObjectEvents.svelte.d.ts +9 -0
- package/dist/hooks/useObjectEvents.svelte.js +31 -0
- package/dist/hooks/useObjects.svelte.d.ts +7 -0
- package/dist/hooks/useObjects.svelte.js +33 -0
- package/dist/hooks/usePartID.svelte.d.ts +6 -0
- package/dist/hooks/usePartID.svelte.js +14 -0
- package/dist/hooks/usePersistentUUIDs.svelte.d.ts +5 -0
- package/dist/hooks/usePersistentUUIDs.svelte.js +14 -0
- package/dist/hooks/usePointclouds.svelte.d.ts +7 -0
- package/dist/hooks/usePointclouds.svelte.js +58 -0
- package/dist/hooks/usePose.svelte.d.ts +3 -0
- package/dist/hooks/usePose.svelte.js +44 -0
- package/dist/hooks/usePoses.svelte.d.ts +12 -0
- package/dist/hooks/usePoses.svelte.js +63 -0
- package/dist/hooks/useRefreshRates.svelte.d.ts +5 -0
- package/dist/hooks/useRefreshRates.svelte.js +23 -0
- package/dist/hooks/useSelection.svelte.d.ts +40 -0
- package/dist/hooks/useSelection.svelte.js +92 -0
- package/dist/hooks/useShapes.svelte.d.ts +17 -0
- package/dist/hooks/useShapes.svelte.js +264 -0
- package/dist/hooks/useStaticGeometries.svelte.d.ts +9 -0
- package/dist/hooks/useStaticGeometries.svelte.js +37 -0
- package/dist/hooks/useVisibility.svelte.d.ts +5 -0
- package/dist/hooks/useVisibility.svelte.js +22 -0
- package/dist/hooks/xr/useAnchors.svelte.d.ts +0 -0
- package/dist/hooks/xr/useAnchors.svelte.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/keybindings.d.ts +12 -0
- package/dist/keybindings.js +12 -0
- package/dist/loaders/pcd/index.d.ts +4 -0
- package/dist/loaders/pcd/index.js +13 -0
- package/dist/loaders/pcd/worker.d.ts +1 -0
- package/dist/loaders/pcd/worker.js +26 -0
- package/dist/three/AxesHelper.d.ts +5 -0
- package/dist/three/AxesHelper.js +35 -0
- package/dist/three/BatchedArrow.d.ts +30 -0
- package/dist/three/BatchedArrow.js +126 -0
- package/dist/three/BoxHelper.d.ts +50 -0
- package/dist/three/BoxHelper.js +134 -0
- package/dist/three/CapsuleGeometry.d.ts +10 -0
- package/dist/three/CapsuleGeometry.js +17 -0
- package/dist/transform.d.ts +11 -0
- package/dist/transform.js +65 -0
- package/package.json +110 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Mesh, Vector3, Color, BoxGeometry, BufferAttribute, MeshBasicMaterial } from 'three';
|
|
2
|
+
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
|
|
3
|
+
export class AxesHelper extends Mesh {
|
|
4
|
+
constructor(size = 0.1, thickness = 0.005) {
|
|
5
|
+
const axisGeometries = [];
|
|
6
|
+
const axes = [
|
|
7
|
+
{ dir: new Vector3(1, 0, 0), color: new Color(0xff0000) }, // X - Red
|
|
8
|
+
{ dir: new Vector3(0, 1, 0), color: new Color(0x00ff00) }, // Y - Green
|
|
9
|
+
{ dir: new Vector3(0, 0, 1), color: new Color(0x0000ff) }, // Z - Blue
|
|
10
|
+
];
|
|
11
|
+
const dimensions = new Vector3();
|
|
12
|
+
for (const axis of axes) {
|
|
13
|
+
dimensions.set(axis.dir.x ? size : thickness, axis.dir.y ? size : thickness, axis.dir.z ? size : thickness);
|
|
14
|
+
const geometry = new BoxGeometry(dimensions.x, dimensions.y, dimensions.z);
|
|
15
|
+
// Translate so it starts at the origin (like traditional AxesHelper)
|
|
16
|
+
geometry.translate(dimensions.x / 2, dimensions.y / 2, dimensions.z / 2);
|
|
17
|
+
// Add vertex colors
|
|
18
|
+
const { count } = geometry.attributes.position;
|
|
19
|
+
const colorArray = new Float32Array(count * 3);
|
|
20
|
+
for (let i = 0; i < count; i++) {
|
|
21
|
+
colorArray[i * 3 + 0] = axis.color.r;
|
|
22
|
+
colorArray[i * 3 + 1] = axis.color.g;
|
|
23
|
+
colorArray[i * 3 + 2] = axis.color.b;
|
|
24
|
+
}
|
|
25
|
+
geometry.setAttribute('color', new BufferAttribute(colorArray, 3));
|
|
26
|
+
axisGeometries.push(geometry);
|
|
27
|
+
}
|
|
28
|
+
const mergedGeometry = mergeGeometries(axisGeometries);
|
|
29
|
+
const material = new MeshBasicMaterial({ vertexColors: true });
|
|
30
|
+
super(mergedGeometry, material);
|
|
31
|
+
}
|
|
32
|
+
dispose() {
|
|
33
|
+
this.geometry.dispose();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BatchedMesh, MeshBasicMaterial, Object3D, Vector3, Box3, Matrix4 } from 'three';
|
|
2
|
+
interface Arrow {
|
|
3
|
+
shaftId: number;
|
|
4
|
+
headId: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class BatchedArrow {
|
|
7
|
+
batchedMesh: BatchedMesh;
|
|
8
|
+
shaftGeoId: number;
|
|
9
|
+
coneGeoId: number;
|
|
10
|
+
shaftWidth: number;
|
|
11
|
+
_arrows: Map<number, Arrow>;
|
|
12
|
+
_idToArrowId: Map<number, number>;
|
|
13
|
+
_pool: Arrow[];
|
|
14
|
+
_idCounter: number;
|
|
15
|
+
constructor({ maxArrows, shaftWidth, material, }?: {
|
|
16
|
+
maxArrows?: number | undefined;
|
|
17
|
+
shaftWidth?: number | undefined;
|
|
18
|
+
material?: MeshBasicMaterial | undefined;
|
|
19
|
+
});
|
|
20
|
+
addArrow(dir: Vector3, origin: Vector3, length?: number, color?: string): number;
|
|
21
|
+
getArrowId(instanceId: number): number | undefined;
|
|
22
|
+
getBoundingBoxAt(arrowId: number, target: Box3): Box3 | undefined;
|
|
23
|
+
removeArrow(arrowId: number): void;
|
|
24
|
+
clear(): void;
|
|
25
|
+
getObject3d(id: number): Object3D<import("three").Object3DEventMap>;
|
|
26
|
+
_computeTransform(origin: Vector3, dir: Vector3, lengthY: number, scaleXZ?: number): Matrix4;
|
|
27
|
+
_quaternionFromDirection(dir: Vector3): import("three").Quaternion;
|
|
28
|
+
get object3d(): BatchedMesh;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { BatchedMesh, BoxGeometry, ConeGeometry, MeshBasicMaterial, Object3D, Vector3, Color, Box3, Matrix4, } from 'three';
|
|
2
|
+
const axis = new Vector3();
|
|
3
|
+
const object3d = new Object3D();
|
|
4
|
+
const vec3 = new Vector3();
|
|
5
|
+
const box1 = new Box3();
|
|
6
|
+
const box2 = new Box3();
|
|
7
|
+
const mat4_1 = new Matrix4();
|
|
8
|
+
const mat4_2 = new Matrix4();
|
|
9
|
+
let index = 0;
|
|
10
|
+
export class BatchedArrow {
|
|
11
|
+
batchedMesh;
|
|
12
|
+
shaftGeoId = -1;
|
|
13
|
+
coneGeoId = -1;
|
|
14
|
+
shaftWidth = 0;
|
|
15
|
+
_arrows = new Map(); // arrowId -> { shaftId, headId }
|
|
16
|
+
_idToArrowId = new Map();
|
|
17
|
+
_pool = [];
|
|
18
|
+
_idCounter = 0;
|
|
19
|
+
constructor({ maxArrows = 20_000, shaftWidth = 0.001, material = new MeshBasicMaterial({ color: 0xffff00, toneMapped: false }), } = {}) {
|
|
20
|
+
const shaftGeo = new BoxGeometry(1, 1, 1);
|
|
21
|
+
shaftGeo.translate(0, 0.5, 0);
|
|
22
|
+
const coneGeo = new ConeGeometry(0.5, 1, 5, 1);
|
|
23
|
+
coneGeo.translate(0, -0.5, 0);
|
|
24
|
+
const shaftVertexCount = shaftGeo.getAttribute('position').count;
|
|
25
|
+
const coneVertexCount = coneGeo.getAttribute('position').count;
|
|
26
|
+
const shaftIndexCount = shaftGeo.index?.count ?? shaftVertexCount;
|
|
27
|
+
const coneIndexCount = coneGeo.index?.count ?? coneVertexCount;
|
|
28
|
+
const maxVertexCount = maxArrows * (shaftVertexCount + coneVertexCount);
|
|
29
|
+
const maxIndexCount = maxArrows * (shaftIndexCount + coneIndexCount);
|
|
30
|
+
this.batchedMesh = new BatchedMesh(maxArrows * 2, maxVertexCount, maxIndexCount, material);
|
|
31
|
+
this.batchedMesh.name = `batched arrows ${++index}`;
|
|
32
|
+
this.batchedMesh.frustumCulled = false;
|
|
33
|
+
this.shaftWidth = shaftWidth;
|
|
34
|
+
this.shaftGeoId = this.batchedMesh.addGeometry(shaftGeo);
|
|
35
|
+
this.coneGeoId = this.batchedMesh.addGeometry(coneGeo);
|
|
36
|
+
}
|
|
37
|
+
addArrow(dir, origin, length = 0.1, color) {
|
|
38
|
+
dir.normalize();
|
|
39
|
+
const headLength = length * 0.2;
|
|
40
|
+
const headWidth = headLength * 0.2;
|
|
41
|
+
let shaftId;
|
|
42
|
+
let headId;
|
|
43
|
+
const instance = this._pool.pop();
|
|
44
|
+
if (instance) {
|
|
45
|
+
;
|
|
46
|
+
({ shaftId, headId } = instance);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
shaftId = this.batchedMesh.addInstance(this.shaftGeoId);
|
|
50
|
+
headId = this.batchedMesh.addInstance(this.coneGeoId);
|
|
51
|
+
}
|
|
52
|
+
// Apply shaft transform
|
|
53
|
+
const shaftMatrix = this._computeTransform(origin, dir, length - headLength, this.shaftWidth);
|
|
54
|
+
this.batchedMesh.setMatrixAt(shaftId, shaftMatrix);
|
|
55
|
+
// Compute cone position = origin + dir * length
|
|
56
|
+
const coneOrigin = vec3.copy(dir).multiplyScalar(length).add(origin);
|
|
57
|
+
const coneMatrix = this._computeTransform(coneOrigin, dir, headLength, headWidth * 4);
|
|
58
|
+
this.batchedMesh.setMatrixAt(headId, coneMatrix);
|
|
59
|
+
if (color) {
|
|
60
|
+
const col = new Color(color);
|
|
61
|
+
this.batchedMesh.setColorAt(shaftId, col);
|
|
62
|
+
this.batchedMesh.setColorAt(headId, col);
|
|
63
|
+
}
|
|
64
|
+
this.batchedMesh.setVisibleAt(shaftId, true);
|
|
65
|
+
this.batchedMesh.setVisibleAt(headId, true);
|
|
66
|
+
const arrowId = this._idCounter++;
|
|
67
|
+
this._arrows.set(arrowId, { shaftId, headId });
|
|
68
|
+
this._idToArrowId.set(shaftId, arrowId);
|
|
69
|
+
this._idToArrowId.set(headId, arrowId);
|
|
70
|
+
return arrowId;
|
|
71
|
+
}
|
|
72
|
+
getArrowId(instanceId) {
|
|
73
|
+
return this._idToArrowId.get(instanceId);
|
|
74
|
+
}
|
|
75
|
+
getBoundingBoxAt(arrowId, target) {
|
|
76
|
+
const arrow = this._arrows.get(arrowId);
|
|
77
|
+
if (arrow) {
|
|
78
|
+
const headBox = this.batchedMesh.getBoundingBoxAt(this.coneGeoId, box1);
|
|
79
|
+
const tailBox = this.batchedMesh.getBoundingBoxAt(this.shaftGeoId, box2);
|
|
80
|
+
if (headBox && tailBox) {
|
|
81
|
+
this.batchedMesh.getMatrixAt(arrow.headId, mat4_1);
|
|
82
|
+
this.batchedMesh.getMatrixAt(arrow.shaftId, mat4_2);
|
|
83
|
+
target.copy(headBox.applyMatrix4(mat4_1)).union(tailBox.applyMatrix4(mat4_2));
|
|
84
|
+
return target;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
removeArrow(arrowId) {
|
|
89
|
+
const arrow = this._arrows.get(arrowId);
|
|
90
|
+
if (!arrow)
|
|
91
|
+
return;
|
|
92
|
+
this.batchedMesh.setVisibleAt(arrow.shaftId, false);
|
|
93
|
+
this.batchedMesh.setVisibleAt(arrow.headId, false);
|
|
94
|
+
this._pool.push(arrow);
|
|
95
|
+
this._arrows.delete(arrowId);
|
|
96
|
+
}
|
|
97
|
+
clear() {
|
|
98
|
+
for (const id of this._arrows.keys()) {
|
|
99
|
+
this.removeArrow(id);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
getObject3d(id) {
|
|
103
|
+
this.batchedMesh.getMatrixAt(id, object3d.matrix);
|
|
104
|
+
object3d.updateMatrix();
|
|
105
|
+
return object3d;
|
|
106
|
+
}
|
|
107
|
+
_computeTransform(origin, dir, lengthY, scaleXZ = 1) {
|
|
108
|
+
object3d.position.copy(origin);
|
|
109
|
+
object3d.quaternion.copy(this._quaternionFromDirection(dir));
|
|
110
|
+
object3d.scale.set(scaleXZ, lengthY, scaleXZ);
|
|
111
|
+
object3d.updateMatrix();
|
|
112
|
+
return object3d.matrix.clone();
|
|
113
|
+
}
|
|
114
|
+
_quaternionFromDirection(dir) {
|
|
115
|
+
if (dir.y > 0.99999)
|
|
116
|
+
return object3d.quaternion.set(0, 0, 0, 1);
|
|
117
|
+
if (dir.y < -0.99999)
|
|
118
|
+
return object3d.quaternion.set(1, 0, 0, 0);
|
|
119
|
+
axis.set(dir.z, 0, -dir.x).normalize();
|
|
120
|
+
const radians = Math.acos(dir.y);
|
|
121
|
+
return object3d.quaternion.setFromAxisAngle(axis, radians);
|
|
122
|
+
}
|
|
123
|
+
get object3d() {
|
|
124
|
+
return this.batchedMesh;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Box3, LineSegments, Object3D } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Helper object to graphically show the world-axis-aligned bounding box
|
|
4
|
+
* around an object. The actual bounding box is handled with {@link Box3},
|
|
5
|
+
* this is just a visual helper for debugging. It can be automatically
|
|
6
|
+
* resized with {@link BoxHelper#update} when the object it's created from
|
|
7
|
+
* is transformed. Note that the object must have a geometry for this to work,
|
|
8
|
+
* so it won't work with sprites.
|
|
9
|
+
*
|
|
10
|
+
* ```js
|
|
11
|
+
* const sphere = new THREE.SphereGeometry();
|
|
12
|
+
* const object = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( 0xff0000 ) );
|
|
13
|
+
* const box = new THREE.BoxHelper( object, 0xffff00 );
|
|
14
|
+
* scene.add( box );
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @augments LineSegments
|
|
18
|
+
*/
|
|
19
|
+
declare class BoxHelper extends LineSegments {
|
|
20
|
+
type: string;
|
|
21
|
+
matrixAutoUpdate: boolean;
|
|
22
|
+
object: Object3D | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Constructs a new box helper.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object3D} [object] - The 3D object to show the world-axis-aligned bounding box.
|
|
27
|
+
* @param {number|Color|string} [color=0xffff00] - The box's color.
|
|
28
|
+
*/
|
|
29
|
+
constructor(object: Object3D, color?: number);
|
|
30
|
+
/**
|
|
31
|
+
* Updates the helper's geometry to match the dimensions of the object,
|
|
32
|
+
* including any children.
|
|
33
|
+
*/
|
|
34
|
+
update(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Updates the wireframe box for the passed object.
|
|
37
|
+
*
|
|
38
|
+
* @param {Object3D} object - The 3D object to create the helper for.
|
|
39
|
+
* @return {BoxHelper} A reference to this instance.
|
|
40
|
+
*/
|
|
41
|
+
setFromObject(object: Object3D): this;
|
|
42
|
+
setFromBox3(box: Box3): this;
|
|
43
|
+
copy(source: BoxHelper, recursive: boolean): this;
|
|
44
|
+
/**
|
|
45
|
+
* Frees the GPU-related resources allocated by this instance. Call this
|
|
46
|
+
* method whenever this instance is no longer used in your app.
|
|
47
|
+
*/
|
|
48
|
+
dispose(): void;
|
|
49
|
+
}
|
|
50
|
+
export { BoxHelper };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Box3, LineSegments, LineBasicMaterial, BufferAttribute, BufferGeometry, Object3D, Material, } from 'three';
|
|
2
|
+
const _box = /*@__PURE__*/ new Box3();
|
|
3
|
+
/**
|
|
4
|
+
* Helper object to graphically show the world-axis-aligned bounding box
|
|
5
|
+
* around an object. The actual bounding box is handled with {@link Box3},
|
|
6
|
+
* this is just a visual helper for debugging. It can be automatically
|
|
7
|
+
* resized with {@link BoxHelper#update} when the object it's created from
|
|
8
|
+
* is transformed. Note that the object must have a geometry for this to work,
|
|
9
|
+
* so it won't work with sprites.
|
|
10
|
+
*
|
|
11
|
+
* ```js
|
|
12
|
+
* const sphere = new THREE.SphereGeometry();
|
|
13
|
+
* const object = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( 0xff0000 ) );
|
|
14
|
+
* const box = new THREE.BoxHelper( object, 0xffff00 );
|
|
15
|
+
* scene.add( box );
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @augments LineSegments
|
|
19
|
+
*/
|
|
20
|
+
class BoxHelper extends LineSegments {
|
|
21
|
+
type = 'BoxHelper';
|
|
22
|
+
matrixAutoUpdate = false;
|
|
23
|
+
object;
|
|
24
|
+
/**
|
|
25
|
+
* Constructs a new box helper.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object3D} [object] - The 3D object to show the world-axis-aligned bounding box.
|
|
28
|
+
* @param {number|Color|string} [color=0xffff00] - The box's color.
|
|
29
|
+
*/
|
|
30
|
+
constructor(object, color = 0xffff00) {
|
|
31
|
+
const indices = new Uint16Array([
|
|
32
|
+
0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
|
|
33
|
+
]);
|
|
34
|
+
const positions = new Float32Array(8 * 3);
|
|
35
|
+
const geometry = new BufferGeometry();
|
|
36
|
+
geometry.setIndex(new BufferAttribute(indices, 1));
|
|
37
|
+
geometry.setAttribute('position', new BufferAttribute(positions, 3));
|
|
38
|
+
super(geometry, new LineBasicMaterial({ color: color, toneMapped: false }));
|
|
39
|
+
/**
|
|
40
|
+
* The 3D object being visualized.
|
|
41
|
+
*
|
|
42
|
+
* @type {Object3D}
|
|
43
|
+
*/
|
|
44
|
+
this.object = object;
|
|
45
|
+
this.update();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Updates the helper's geometry to match the dimensions of the object,
|
|
49
|
+
* including any children.
|
|
50
|
+
*/
|
|
51
|
+
update() {
|
|
52
|
+
if (this.object !== undefined) {
|
|
53
|
+
_box.setFromObject(this.object);
|
|
54
|
+
}
|
|
55
|
+
if (_box.isEmpty())
|
|
56
|
+
return;
|
|
57
|
+
const min = _box.min;
|
|
58
|
+
const max = _box.max;
|
|
59
|
+
/*
|
|
60
|
+
5____4
|
|
61
|
+
1/___0/|
|
|
62
|
+
| 6__|_7
|
|
63
|
+
2/___3/
|
|
64
|
+
|
|
65
|
+
0: max.x, max.y, max.z
|
|
66
|
+
1: min.x, max.y, max.z
|
|
67
|
+
2: min.x, min.y, max.z
|
|
68
|
+
3: max.x, min.y, max.z
|
|
69
|
+
4: max.x, max.y, min.z
|
|
70
|
+
5: min.x, max.y, min.z
|
|
71
|
+
6: min.x, min.y, min.z
|
|
72
|
+
7: max.x, min.y, min.z
|
|
73
|
+
*/
|
|
74
|
+
const position = this.geometry.attributes.position;
|
|
75
|
+
const array = position.array;
|
|
76
|
+
array[0] = max.x;
|
|
77
|
+
array[1] = max.y;
|
|
78
|
+
array[2] = max.z;
|
|
79
|
+
array[3] = min.x;
|
|
80
|
+
array[4] = max.y;
|
|
81
|
+
array[5] = max.z;
|
|
82
|
+
array[6] = min.x;
|
|
83
|
+
array[7] = min.y;
|
|
84
|
+
array[8] = max.z;
|
|
85
|
+
array[9] = max.x;
|
|
86
|
+
array[10] = min.y;
|
|
87
|
+
array[11] = max.z;
|
|
88
|
+
array[12] = max.x;
|
|
89
|
+
array[13] = max.y;
|
|
90
|
+
array[14] = min.z;
|
|
91
|
+
array[15] = min.x;
|
|
92
|
+
array[16] = max.y;
|
|
93
|
+
array[17] = min.z;
|
|
94
|
+
array[18] = min.x;
|
|
95
|
+
array[19] = min.y;
|
|
96
|
+
array[20] = min.z;
|
|
97
|
+
array[21] = max.x;
|
|
98
|
+
array[22] = min.y;
|
|
99
|
+
array[23] = min.z;
|
|
100
|
+
position.needsUpdate = true;
|
|
101
|
+
this.geometry.computeBoundingSphere();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Updates the wireframe box for the passed object.
|
|
105
|
+
*
|
|
106
|
+
* @param {Object3D} object - The 3D object to create the helper for.
|
|
107
|
+
* @return {BoxHelper} A reference to this instance.
|
|
108
|
+
*/
|
|
109
|
+
setFromObject(object) {
|
|
110
|
+
this.object = object;
|
|
111
|
+
this.update();
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
setFromBox3(box) {
|
|
115
|
+
this.object = undefined;
|
|
116
|
+
_box.copy(box);
|
|
117
|
+
this.update();
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
copy(source, recursive) {
|
|
121
|
+
super.copy(source, recursive);
|
|
122
|
+
this.object = source.object;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Frees the GPU-related resources allocated by this instance. Call this
|
|
127
|
+
* method whenever this instance is no longer used in your app.
|
|
128
|
+
*/
|
|
129
|
+
dispose() {
|
|
130
|
+
this.geometry.dispose();
|
|
131
|
+
this.material.dispose();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export { BoxHelper };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LatheGeometry } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* An alternate definition of a THREE.CapsuleGeometry: the length
|
|
4
|
+
* represents the entire length of the capsule, including the rounded ends,
|
|
5
|
+
* rather than just the midsection, which is the default THREE.CapsuleGeometry definition.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CapsuleGeometry extends LatheGeometry {
|
|
8
|
+
type: string;
|
|
9
|
+
constructor(radius?: number, length?: number, capSegments?: number, radialSegments?: number);
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LatheGeometry, Path } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* An alternate definition of a THREE.CapsuleGeometry: the length
|
|
4
|
+
* represents the entire length of the capsule, including the rounded ends,
|
|
5
|
+
* rather than just the midsection, which is the default THREE.CapsuleGeometry definition.
|
|
6
|
+
*/
|
|
7
|
+
export class CapsuleGeometry extends LatheGeometry {
|
|
8
|
+
type = 'CapsuleGeometry';
|
|
9
|
+
constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
|
|
10
|
+
const path = new Path();
|
|
11
|
+
const midsectionLength = length - 2 * radius;
|
|
12
|
+
path.absarc(0, -midsectionLength / 2, radius, Math.PI * 1.5, 0);
|
|
13
|
+
path.absarc(0, midsectionLength / 2, radius, 0, Math.PI * 0.5);
|
|
14
|
+
super(path.getPoints(capSegments), radialSegments);
|
|
15
|
+
this.rotateX(-Math.PI / 2);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Geometry, Pose } from '@viamrobotics/sdk';
|
|
2
|
+
import { type Object3D, Quaternion, Vector3 } from 'three';
|
|
3
|
+
export declare const createPose: (pose?: Pose) => Pose;
|
|
4
|
+
export declare const createGeometry: (geometryType?: Geometry["geometryType"], label?: string) => Geometry;
|
|
5
|
+
export declare const quaternionToPose: (quaternion: Quaternion, pose: Partial<Pose>) => void;
|
|
6
|
+
export declare const vector3ToPose: (vec3: Vector3, pose: Partial<Pose>) => void;
|
|
7
|
+
export declare const object3dToPose: (object3d: Object3D, pose: Partial<Pose>) => Partial<import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>>;
|
|
8
|
+
export declare const poseToQuaternion: (pose: Partial<Pose>, quaternion: Quaternion) => void;
|
|
9
|
+
export declare const poseToVector3: (pose: Partial<Pose>, vec3: Vector3) => void;
|
|
10
|
+
export declare const poseToObject3d: (pose: Partial<Pose>, object3d: Object3D) => void;
|
|
11
|
+
export declare const scaleToDimensions: (scale: Vector3, geometry: Geometry["geometryType"]) => void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { OrientationVector } from '@viamrobotics/three';
|
|
2
|
+
import { MathUtils, Quaternion, Vector3 } from 'three';
|
|
3
|
+
const ov = new OrientationVector();
|
|
4
|
+
export const createPose = (pose) => {
|
|
5
|
+
return {
|
|
6
|
+
x: pose?.x ?? 0,
|
|
7
|
+
y: pose?.y ?? 0,
|
|
8
|
+
z: pose?.z ?? 0,
|
|
9
|
+
oX: pose?.oX ?? 0,
|
|
10
|
+
oY: pose?.oY ?? 0,
|
|
11
|
+
oZ: pose?.oZ ?? 1,
|
|
12
|
+
theta: pose?.theta ?? 0,
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export const createGeometry = (geometryType, label = '') => {
|
|
16
|
+
return {
|
|
17
|
+
center: createPose(),
|
|
18
|
+
label,
|
|
19
|
+
geometryType: geometryType ?? { case: undefined, value: undefined },
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const quaternionToPose = (quaternion, pose) => {
|
|
23
|
+
ov.setFromQuaternion(quaternion);
|
|
24
|
+
pose.oX = ov.x;
|
|
25
|
+
pose.oY = ov.y;
|
|
26
|
+
pose.oZ = ov.z;
|
|
27
|
+
pose.theta = MathUtils.radToDeg(ov.th);
|
|
28
|
+
};
|
|
29
|
+
export const vector3ToPose = (vec3, pose) => {
|
|
30
|
+
pose.x = vec3.x * 1000;
|
|
31
|
+
pose.y = vec3.y * 1000;
|
|
32
|
+
pose.z = vec3.z * 1000;
|
|
33
|
+
};
|
|
34
|
+
export const object3dToPose = (object3d, pose) => {
|
|
35
|
+
vector3ToPose(object3d.position, pose);
|
|
36
|
+
quaternionToPose(object3d.quaternion, pose);
|
|
37
|
+
return pose;
|
|
38
|
+
};
|
|
39
|
+
export const poseToQuaternion = (pose, quaternion) => {
|
|
40
|
+
const th = MathUtils.degToRad(pose.theta ?? 0);
|
|
41
|
+
ov.set(pose.oX, pose.oY, pose.oZ, th);
|
|
42
|
+
ov.toQuaternion(quaternion);
|
|
43
|
+
};
|
|
44
|
+
export const poseToVector3 = (pose, vec3) => {
|
|
45
|
+
vec3.set(pose.x ?? 0, pose.y ?? 0, pose.z ?? 0).multiplyScalar(0.001);
|
|
46
|
+
};
|
|
47
|
+
export const poseToObject3d = (pose, object3d) => {
|
|
48
|
+
poseToVector3(pose, object3d.position);
|
|
49
|
+
poseToQuaternion(pose, object3d.quaternion);
|
|
50
|
+
};
|
|
51
|
+
export const scaleToDimensions = (scale, geometry) => {
|
|
52
|
+
if (geometry.case === 'box') {
|
|
53
|
+
geometry.value.dimsMm ??= { x: 0, y: 0, z: 0 };
|
|
54
|
+
geometry.value.dimsMm.x *= scale.x;
|
|
55
|
+
geometry.value.dimsMm.y *= scale.y;
|
|
56
|
+
geometry.value.dimsMm.z *= scale.z;
|
|
57
|
+
}
|
|
58
|
+
else if (geometry.case === 'capsule') {
|
|
59
|
+
geometry.value.radiusMm *= scale.x;
|
|
60
|
+
geometry.value.lengthMm *= scale.y;
|
|
61
|
+
}
|
|
62
|
+
else if (geometry.case === 'sphere') {
|
|
63
|
+
geometry.value.radiusMm *= scale.x;
|
|
64
|
+
}
|
|
65
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@viamrobotics/motion-tools",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Motion visualization with Viam",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@ag-grid-community/client-side-row-model": "^32.3.5",
|
|
9
|
+
"@ag-grid-community/core": "^32.3.5",
|
|
10
|
+
"@ag-grid-community/styles": "^32.3.5",
|
|
11
|
+
"@changesets/cli": "^2.29.4",
|
|
12
|
+
"@dimforge/rapier3d-compat": "^0.17.0",
|
|
13
|
+
"@eslint/compat": "^1.2.9",
|
|
14
|
+
"@eslint/js": "^9.27.0",
|
|
15
|
+
"@playwright/test": "^1.52.0",
|
|
16
|
+
"@skeletonlabs/skeleton": "3.1.3",
|
|
17
|
+
"@skeletonlabs/skeleton-svelte": "1.2.2",
|
|
18
|
+
"@sveltejs/adapter-static": "^3.0.8",
|
|
19
|
+
"@sveltejs/kit": "^2.21.1",
|
|
20
|
+
"@sveltejs/package": "^2.3.11",
|
|
21
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
22
|
+
"@tailwindcss/forms": "^0.5.10",
|
|
23
|
+
"@tailwindcss/vite": "^4.1.7",
|
|
24
|
+
"@tanstack/svelte-query": "^5.76.2",
|
|
25
|
+
"@tanstack/svelte-query-devtools": "^5.76.2",
|
|
26
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
27
|
+
"@testing-library/svelte": "^5.2.8",
|
|
28
|
+
"@threlte/core": "^8.0.4",
|
|
29
|
+
"@threlte/extras": "^9.2.1",
|
|
30
|
+
"@threlte/rapier": "^3.1.4",
|
|
31
|
+
"@threlte/xr": "^1.0.5",
|
|
32
|
+
"@types/bun": "^1.2.14",
|
|
33
|
+
"@types/lodash-es": "^4.17.12",
|
|
34
|
+
"@types/three": "^0.176.0",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
36
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
37
|
+
"@viamrobotics/prime-core": "^0.1.5",
|
|
38
|
+
"@viamrobotics/sdk": "0.42.0",
|
|
39
|
+
"@viamrobotics/svelte-sdk": "0.1.4",
|
|
40
|
+
"@viamrobotics/three": "^0.0.9",
|
|
41
|
+
"@vitejs/plugin-basic-ssl": "^2.0.0",
|
|
42
|
+
"@zag-js/svelte": "1.12.4",
|
|
43
|
+
"@zag-js/tree-view": "1.12.4",
|
|
44
|
+
"camera-controls": "^2.10.1",
|
|
45
|
+
"eslint": "^9.27.0",
|
|
46
|
+
"eslint-config-prettier": "^10.1.5",
|
|
47
|
+
"eslint-plugin-svelte": "^3.9.0",
|
|
48
|
+
"globals": "^16.1.0",
|
|
49
|
+
"idb-keyval": "^6.2.2",
|
|
50
|
+
"jsdom": "^26.1.0",
|
|
51
|
+
"lodash-es": "^4.17.21",
|
|
52
|
+
"lucide-svelte": "^0.511.0",
|
|
53
|
+
"prettier": "^3.5.3",
|
|
54
|
+
"prettier-plugin-svelte": "^3.4.0",
|
|
55
|
+
"prettier-plugin-tailwindcss": "^0.6.11",
|
|
56
|
+
"publint": "^0.3.12",
|
|
57
|
+
"runed": "^0.28.0",
|
|
58
|
+
"svelte": "5.33.0",
|
|
59
|
+
"svelte-check": "^4.2.1",
|
|
60
|
+
"svelte-virtuallists": "^1.4.2",
|
|
61
|
+
"tailwindcss": "^4.1.7",
|
|
62
|
+
"three": "^0.176.0",
|
|
63
|
+
"threlte-uikit": "^1.0.0",
|
|
64
|
+
"tsx": "^4.19.4",
|
|
65
|
+
"typescript": "^5.8.3",
|
|
66
|
+
"typescript-eslint": "^8.32.1",
|
|
67
|
+
"vite": "^6.3.5",
|
|
68
|
+
"vite-plugin-mkcert": "^1.17.8",
|
|
69
|
+
"vitest": "^3.1.4"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"@tanstack/svelte-query": ">=5",
|
|
73
|
+
"@viamrobotics/sdk": ">=0.38",
|
|
74
|
+
"@viamrobotics/svelte-sdk": ">=0.1",
|
|
75
|
+
"svelte": ">=5"
|
|
76
|
+
},
|
|
77
|
+
"packageManager": "pnpm@8.15.6+sha256.01c01eeb990e379b31ef19c03e9d06a14afa5250b82e81303f88721c99ff2e6f",
|
|
78
|
+
"svelte": "./dist/index.js",
|
|
79
|
+
"types": "./dist/index.d.ts",
|
|
80
|
+
"exports": {
|
|
81
|
+
".": {
|
|
82
|
+
"types": "./dist/index.d.ts",
|
|
83
|
+
"svelte": "./dist/index.js"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"repository": {
|
|
87
|
+
"type": "git",
|
|
88
|
+
"url": "git+https://github.com/viam-labs/motion-tools.git"
|
|
89
|
+
},
|
|
90
|
+
"files": [
|
|
91
|
+
"dist",
|
|
92
|
+
"!dist/**/*.test.*",
|
|
93
|
+
"!dist/**/*.spec.*"
|
|
94
|
+
],
|
|
95
|
+
"scripts": {
|
|
96
|
+
"dev": "tsx server/check-bun && bun run server/server.ts",
|
|
97
|
+
"build": "vite build && npm run prepack",
|
|
98
|
+
"preview": "vite preview",
|
|
99
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
100
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
101
|
+
"format": "prettier --write .",
|
|
102
|
+
"lint": "prettier --check . && eslint .",
|
|
103
|
+
"test:unit": "vitest",
|
|
104
|
+
"test:client": "go test ./... -count=1",
|
|
105
|
+
"test": "pnpm test:unit -- --run",
|
|
106
|
+
"test:e2e": "playwright test",
|
|
107
|
+
"model-pipeline:run": "node scripts/model-pipeline.js",
|
|
108
|
+
"release": "changeset publish"
|
|
109
|
+
}
|
|
110
|
+
}
|