@viamrobotics/motion-tools 0.15.1 → 0.15.3

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.
@@ -56,7 +56,9 @@ export declare class WorldObject<T extends Geometries = Geometries> {
56
56
  geometry?: T;
57
57
  metadata: Metadata;
58
58
  localEditedPose: PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
59
- constructor(name: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
59
+ constructor(name?: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
60
+ toJSON(): Omit<WorldObject, 'toJSON' | 'fromJSON' | 'metadata'>;
61
+ fromJSON(json: WorldObject): this;
60
62
  }
61
63
  export declare const parseMetadata: (fields?: PlainMessage<Struct>["fields"]) => Metadata;
62
64
  export declare const fromTransform: (transform: TransformWithUUID) => WorldObject<PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Geometry>>;
@@ -22,15 +22,14 @@ export const isMetadataKey = (key) => {
22
22
  return METADATA_KEYS.includes(key);
23
23
  };
24
24
  export class WorldObject {
25
- uuid;
26
- name;
25
+ uuid = MathUtils.generateUUID();
26
+ name = '';
27
27
  referenceFrame = $state.raw();
28
28
  pose = $state.raw(createPose());
29
- geometry;
29
+ geometry = $state();
30
30
  metadata = $state({});
31
31
  localEditedPose = $state.raw(createPose());
32
- constructor(name, pose, parent = 'world', geometry, metadata) {
33
- this.uuid = MathUtils.generateUUID();
32
+ constructor(name = '', pose, parent = 'world', geometry, metadata) {
34
33
  this.name = name;
35
34
  this.referenceFrame = parent;
36
35
  this.geometry = geometry;
@@ -42,6 +41,26 @@ export class WorldObject {
42
41
  this.localEditedPose = { ...pose };
43
42
  }
44
43
  }
44
+ toJSON() {
45
+ return {
46
+ uuid: this.uuid,
47
+ name: this.name,
48
+ referenceFrame: $state.snapshot(this.referenceFrame),
49
+ pose: $state.snapshot(this.pose),
50
+ geometry: $state.snapshot(this.geometry),
51
+ localEditedPose: $state.snapshot(this.localEditedPose),
52
+ };
53
+ }
54
+ fromJSON(json) {
55
+ this.uuid = json.uuid;
56
+ this.name = json.name;
57
+ this.referenceFrame = json.referenceFrame;
58
+ this.pose = json.pose;
59
+ this.geometry = json.geometry;
60
+ this.localEditedPose = json.localEditedPose;
61
+ this.metadata = {};
62
+ return this;
63
+ }
45
64
  }
46
65
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
66
  const unwrapValue = (value) => {
@@ -40,7 +40,7 @@
40
40
  metadata={object.metadata}
41
41
  >
42
42
  {#snippet children({ ref })}
43
- {#if selected.current === ref.uuid}
43
+ {#if selected.current === object.uuid}
44
44
  {#key mode}
45
45
  <TransformControls
46
46
  object={ref}
@@ -63,6 +63,8 @@
63
63
  scaleToDimensions(ref.scale, object.geometry.geometryType)
64
64
  ref.scale.setScalar(1)
65
65
  }
66
+
67
+ object.pose = { ...object.pose }
66
68
  }}
67
69
  />
68
70
  {/key}
@@ -0,0 +1,2 @@
1
+ import { WorldObject } from '../../../WorldObject.svelte';
2
+ export declare const createWorldObjectFixture: () => WorldObject<import("../../../WorldObject.svelte").Geometries>;
@@ -0,0 +1,35 @@
1
+ import { WorldObject } from '../../../WorldObject.svelte';
2
+ export const createWorldObjectFixture = () => {
3
+ const object = new WorldObject();
4
+ object.name = 'Test Object';
5
+ object.uuid = '1234-5678';
6
+ object.referenceFrame = 'parent_frame';
7
+ object.pose = {
8
+ x: 10,
9
+ y: 20,
10
+ z: 30,
11
+ oX: 0.1,
12
+ oY: 0.2,
13
+ oZ: 0.3,
14
+ theta: 0.4,
15
+ };
16
+ object.geometry = {
17
+ label: 'my geometry',
18
+ geometryType: {
19
+ case: 'box',
20
+ value: {
21
+ dimsMm: { x: 10, y: 20, z: 30 },
22
+ },
23
+ },
24
+ };
25
+ object.localEditedPose = {
26
+ x: 10,
27
+ y: 20,
28
+ z: 30,
29
+ oX: 0.1,
30
+ oY: 0.2,
31
+ oZ: 0.3,
32
+ theta: 0.4,
33
+ };
34
+ return object;
35
+ };
@@ -6,9 +6,9 @@ import { resourceNameToColor } from '../color';
6
6
  import { usePartConfig } from './usePartConfig.svelte';
7
7
  import { useEnvironment } from './useEnvironment.svelte';
8
8
  import { createPoseFromFrame } from '../transform';
9
- import { usePersistentUUIDs } from './usePersistentUUIDs.svelte';
10
9
  import { createGeometryFromFrame } from '../geometry';
11
10
  import { useResourceByName } from './useResourceByName.svelte';
11
+ import { usePersistentUUIDs } from './usePersistentUUIDs.svelte';
12
12
  const key = Symbol('frames-context');
13
13
  export const provideFrames = (partID) => {
14
14
  const resourceByName = useResourceByName();
@@ -47,12 +47,14 @@ export const provideFrames = (partID) => {
47
47
  }
48
48
  return objects;
49
49
  });
50
- const configFrames = $derived.by(() => {
50
+ const [configFrames, configUnsetFrames] = $derived.by(() => {
51
51
  const components = partConfig.localPartConfig.toJson().components;
52
52
  const objects = [];
53
+ const unsetObjects = [];
53
54
  // deal with part defined frame config
54
55
  for (const component of components ?? []) {
55
56
  if (!component.frame) {
57
+ unsetObjects.push(component.name);
56
58
  continue;
57
59
  }
58
60
  const pose = createPoseFromFrame(component.frame);
@@ -60,7 +62,7 @@ export const provideFrames = (partID) => {
60
62
  const worldObject = new WorldObject(component.name, pose, component.frame.parent, geometry);
61
63
  objects.push(worldObject);
62
64
  }
63
- return objects;
65
+ return [objects, unsetObjects];
64
66
  });
65
67
  const [fragmentFrames, fragmentUnsetFrames] = $derived.by(() => {
66
68
  const { fragment_mods: fragmentMods = [] } = partConfig.localPartConfig.toJson() ?? {};
@@ -94,7 +96,7 @@ export const provideFrames = (partID) => {
94
96
  const result = machineFrames[frame.name];
95
97
  if (result) {
96
98
  result.referenceFrame = frame.referenceFrame;
97
- result.pose = frame.pose;
99
+ result.localEditedPose = frame.pose;
98
100
  result.geometry = frame.geometry;
99
101
  }
100
102
  else {
@@ -107,7 +109,7 @@ export const provideFrames = (partID) => {
107
109
  const result = machineFrames[frame.name];
108
110
  if (result) {
109
111
  result.referenceFrame = frame.referenceFrame;
110
- result.pose = frame.pose;
112
+ result.localEditedPose = frame.pose;
111
113
  result.geometry = frame.geometry;
112
114
  }
113
115
  else {
@@ -115,12 +117,21 @@ export const provideFrames = (partID) => {
115
117
  }
116
118
  }
117
119
  });
120
+ $effect.pre(() => {
121
+ for (const name of configUnsetFrames) {
122
+ delete machineFrames[name];
123
+ }
124
+ });
118
125
  $effect.pre(() => {
119
126
  for (const name of fragmentUnsetFrames) {
120
127
  delete machineFrames[name];
121
128
  }
122
129
  });
123
130
  const current = $derived.by(() => {
131
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
132
+ const _configFrames = configFrames;
133
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
134
+ const _fragmentFrames = fragmentFrames;
124
135
  const results = Object.values(machineFrames);
125
136
  updateUUIDs(results);
126
137
  return results;
@@ -8,6 +8,7 @@ import { useMotionClient } from './useMotionClient.svelte';
8
8
  import { useEnvironment } from './useEnvironment.svelte';
9
9
  import { observe } from '@threlte/core';
10
10
  import { untrack } from 'svelte';
11
+ import { useFrames } from './useFrames.svelte';
11
12
  export const usePose = (name, parent) => {
12
13
  const { refreshRates } = useMachineSettings();
13
14
  const partID = usePartID();
@@ -16,6 +17,7 @@ export const usePose = (name, parent) => {
16
17
  const resource = $derived(resources.current.find((resource) => resource.name === name()));
17
18
  const parentResource = $derived(resources.current.find((resource) => resource.name === parent()));
18
19
  const environment = useEnvironment();
20
+ const frames = useFrames();
19
21
  const client = createResourceClient(MotionClient, () => partID.current, () => motionClient.current ?? '');
20
22
  const interval = $derived(refreshRates.get(RefreshRates.poses));
21
23
  const options = $derived(queryOptions({
@@ -34,7 +36,7 @@ export const usePose = (name, parent) => {
34
36
  },
35
37
  }));
36
38
  const query = fromStore(createQuery(toStore(() => options)));
37
- observe.pre(() => [environment.current.viewerMode], () => {
39
+ observe.pre(() => [environment.current.viewerMode, frames.current], () => {
38
40
  if (environment.current.viewerMode === 'monitor') {
39
41
  untrack(() => query.current).refetch();
40
42
  }
@@ -5,15 +5,25 @@ import { createGeometry } from '../geometry';
5
5
  import { WorldObject } from '../WorldObject.svelte';
6
6
  const key = Symbol('static-geometries-context');
7
7
  export const provideStaticGeometries = () => {
8
- let geometries = $state([]);
8
+ const geometries = $state([]);
9
+ let loaded = $state(false);
9
10
  const debounced = new Debounced(() => geometries, 500);
10
11
  get('static-geometries').then((response) => {
11
12
  if (Array.isArray(response)) {
12
- geometries = response;
13
+ for (const json of response) {
14
+ geometries.push(new WorldObject().fromJSON(json));
15
+ }
13
16
  }
17
+ loaded = true;
14
18
  });
15
19
  $effect(() => {
16
- set('static-geometries', $state.snapshot(debounced.current));
20
+ if (!loaded)
21
+ return;
22
+ const results = [];
23
+ for (const geometry of debounced.current) {
24
+ results.push(geometry.toJSON());
25
+ }
26
+ set('static-geometries', results);
17
27
  });
18
28
  setContext(key, {
19
29
  get current() {
@@ -24,7 +34,7 @@ export const provideStaticGeometries = () => {
24
34
  case: 'box',
25
35
  value: { dimsMm: { x: 100, y: 100, z: 100 } },
26
36
  }));
27
- geometries.push(structuredClone(object));
37
+ geometries.push(object);
28
38
  },
29
39
  remove(name) {
30
40
  const index = geometries.findIndex((geo) => geo.name === name);
@@ -5,7 +5,6 @@ export declare class BatchedArrow {
5
5
  _geometryId: number;
6
6
  _pool: number[];
7
7
  _ids: Set<number>;
8
- _id: number;
9
8
  _max: number;
10
9
  constructor();
11
10
  addArrow(direction: Vector3, origin: Vector3, length?: number, color?: Color, arrowHeadAtPose?: boolean): number;
@@ -12,7 +12,6 @@ export class BatchedArrow {
12
12
  _geometryId;
13
13
  _pool = [];
14
14
  _ids = new Set();
15
- _id = 0;
16
15
  _max = 20_000;
17
16
  constructor() {
18
17
  const material = new MeshBasicMaterial({ color: 0xffffff, toneMapped: false });
@@ -2,7 +2,7 @@ import type { Geometry, Pose } from '@viamrobotics/sdk';
2
2
  import { type Object3D, Matrix4, Quaternion, Vector3 } from 'three';
3
3
  import type { Frame } from './frame';
4
4
  export declare const createPose: (pose?: Pose) => Pose;
5
- export declare const createPoseFromFrame: (frame: Frame) => Pose;
5
+ export declare const createPoseFromFrame: (frame: Partial<Frame>) => Pose;
6
6
  export declare const quaternionToPose: (quaternion: Quaternion, pose: Partial<Pose>) => void;
7
7
  export declare const vector3ToPose: (vec3: Vector3, pose: Partial<Pose>) => void;
8
8
  export declare const object3dToPose: (object3d: Object3D, pose: Partial<Pose>) => Partial<import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>>;
package/dist/transform.js CHANGED
@@ -17,26 +17,26 @@ export const createPose = (pose) => {
17
17
  };
18
18
  };
19
19
  export const createPoseFromFrame = (frame) => {
20
- if (frame.orientation.type === 'quaternion') {
20
+ if (frame.orientation?.type === 'quaternion') {
21
21
  quaternion.copy(frame.orientation.value);
22
22
  ov.setFromQuaternion(quaternion);
23
23
  }
24
- else if (frame.orientation.type === 'euler_angles') {
24
+ else if (frame.orientation?.type === 'euler_angles') {
25
25
  euler.set(frame.orientation.value.roll, frame.orientation.value.pitch, frame.orientation.value.yaw, 'ZYX');
26
26
  quaternion.setFromEuler(euler);
27
27
  ov.setFromQuaternion(quaternion);
28
28
  }
29
- else if (frame.orientation.type === 'ov_radians') {
29
+ else if (frame.orientation?.type === 'ov_radians') {
30
30
  ov.copy(frame.orientation.value);
31
31
  }
32
32
  else {
33
- const th = MathUtils.degToRad(frame.orientation.value.th);
34
- ov.set(frame.orientation.value.x, frame.orientation.value.y, frame.orientation.value.z, th);
33
+ const th = MathUtils.degToRad(frame.orientation?.value.th ?? 0);
34
+ ov.set(frame.orientation?.value.x, frame.orientation?.value.y, frame.orientation?.value.z, th);
35
35
  }
36
36
  return {
37
- x: frame.translation.x ?? 0,
38
- y: frame.translation.y ?? 0,
39
- z: frame.translation.z ?? 0,
37
+ x: frame.translation?.x ?? 0,
38
+ y: frame.translation?.y ?? 0,
39
+ z: frame.translation?.z ?? 0,
40
40
  oX: ov.x,
41
41
  oY: ov.y,
42
42
  oZ: ov.z,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "0.15.1",
3
+ "version": "0.15.3",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -56,7 +56,7 @@
56
56
  "prettier-plugin-tailwindcss": "0.6.14",
57
57
  "publint": "0.3.12",
58
58
  "runed": "0.31.1",
59
- "svelte": "5.38.7",
59
+ "svelte": "5.43.0",
60
60
  "svelte-check": "4.3.1",
61
61
  "svelte-virtuallists": "1.4.2",
62
62
  "tailwindcss": "4.1.13",