@viamrobotics/motion-tools 1.26.1 → 1.26.2
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/buf/common/v1/common_pb.d.ts +19 -0
- package/dist/buf/common/v1/common_pb.js +32 -0
- package/dist/components/BatchedArrows.svelte +31 -15
- package/dist/components/Entities/Entities.svelte +3 -8
- package/dist/components/Entities/Frame.svelte +25 -9
- package/dist/components/Entities/Frame.svelte.d.ts +0 -2
- package/dist/components/Entities/GLTF.svelte +5 -4
- package/dist/components/Entities/Line.svelte +5 -4
- package/dist/components/Entities/Mesh.svelte +12 -18
- package/dist/components/Entities/Points.svelte +5 -4
- 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/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 +21 -7
- 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 -45
- package/dist/ecs/traits.js +57 -28
- 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 +148 -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/useFrames.svelte.js +23 -11
- package/dist/hooks/useGeometries.svelte.js +4 -2
- package/dist/hooks/usePartConfig.svelte.js +38 -3
- package/dist/hooks/useWorldState.svelte.js +10 -2
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useThrelte } from '@threlte/core';
|
|
2
2
|
import {} from 'koota';
|
|
3
3
|
import { getContext, setContext } from 'svelte';
|
|
4
|
-
import { Color, Vector3, Vector4 } from 'three';
|
|
4
|
+
import { Color, Matrix4, Vector3, Vector4 } from 'three';
|
|
5
5
|
import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
|
|
6
6
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
7
7
|
import { UuidTool } from 'uuid-tool';
|
|
@@ -11,7 +11,7 @@ import { asRGB, STRIDE } from '../buffer';
|
|
|
11
11
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
12
12
|
import { createBox, createCapsule, createSphere } from '../geometry';
|
|
13
13
|
import { parsePlyInput } from '../ply';
|
|
14
|
-
import { createPose, createPoseFromFrame } from '../transform';
|
|
14
|
+
import { createPose, createPoseFromFrame, poseToMatrix } from '../transform';
|
|
15
15
|
import { useCameraControls } from './useControls.svelte';
|
|
16
16
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
17
17
|
import { useLogs } from './useLogs.svelte';
|
|
@@ -126,7 +126,11 @@ export const provideDrawAPI = () => {
|
|
|
126
126
|
const parent = frame.parent;
|
|
127
127
|
const existing = entities.get(name);
|
|
128
128
|
if (existing) {
|
|
129
|
-
existing.
|
|
129
|
+
const matrix = existing.get(traits.Matrix);
|
|
130
|
+
if (matrix) {
|
|
131
|
+
poseToMatrix(pose, matrix);
|
|
132
|
+
existing.changed(traits.Matrix);
|
|
133
|
+
}
|
|
130
134
|
hierarchy.setParent(existing, parent);
|
|
131
135
|
continue;
|
|
132
136
|
}
|
|
@@ -146,7 +150,7 @@ export const provideDrawAPI = () => {
|
|
|
146
150
|
if (frame.geometry) {
|
|
147
151
|
entityTraits.push(geometryTrait());
|
|
148
152
|
}
|
|
149
|
-
entityTraits.push(traits.Name(name), traits.
|
|
153
|
+
entityTraits.push(traits.Name(name), traits.Matrix(poseToMatrix(pose, new Matrix4())), traits.DrawAPI, traits.ReferenceFrame, traits.Removable, traits.ShowAxesHelper);
|
|
150
154
|
const entity = world.spawn(...entityTraits);
|
|
151
155
|
entities.set(name, entity);
|
|
152
156
|
}
|
|
@@ -157,7 +161,11 @@ export const provideDrawAPI = () => {
|
|
|
157
161
|
const pose = createPose(data.center);
|
|
158
162
|
const existing = entities.get(name);
|
|
159
163
|
if (existing) {
|
|
160
|
-
existing.
|
|
164
|
+
const matrix = existing.get(traits.Matrix);
|
|
165
|
+
if (matrix) {
|
|
166
|
+
poseToMatrix(pose, matrix);
|
|
167
|
+
existing.changed(traits.Matrix);
|
|
168
|
+
}
|
|
161
169
|
return;
|
|
162
170
|
}
|
|
163
171
|
const geometryTrait = () => {
|
|
@@ -179,7 +187,7 @@ export const provideDrawAPI = () => {
|
|
|
179
187
|
const entityTraits = [
|
|
180
188
|
traits.Name(data.label ?? ++geometryIndex),
|
|
181
189
|
...hierarchy.parentTraits(parent),
|
|
182
|
-
traits.
|
|
190
|
+
traits.Matrix(poseToMatrix(pose, new Matrix4())),
|
|
183
191
|
traits.Color(colorUtil.set(color)),
|
|
184
192
|
geometryTrait(),
|
|
185
193
|
traits.DrawAPI,
|
|
@@ -2,9 +2,10 @@ import { MachineConnectionEvent, Transform } from '@viamrobotics/sdk';
|
|
|
2
2
|
import { createRobotQuery, useConnectionStatus, useMachineStatus, useRobotClient, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import {} from 'koota';
|
|
4
4
|
import { getContext, setContext, untrack } from 'svelte';
|
|
5
|
+
import { Matrix4 } from 'three';
|
|
5
6
|
import { resourceNameToColor, subtypeToColor } from '../color';
|
|
6
7
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
7
|
-
import { createPose } from '../transform';
|
|
8
|
+
import { createPose, isPoseEqual, poseToMatrix } from '../transform';
|
|
8
9
|
import { useConfigFrames } from './useConfigFrames.svelte';
|
|
9
10
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
10
11
|
import { useFrameEditSession } from './useFrameEditSession.svelte';
|
|
@@ -171,34 +172,45 @@ export const provideFrames = (partID) => {
|
|
|
171
172
|
}
|
|
172
173
|
hierarchy.setParent(existing, parent);
|
|
173
174
|
if (color) {
|
|
174
|
-
existing.
|
|
175
|
+
const cur = existing.get(traits.Color);
|
|
176
|
+
if (!cur || cur.r !== color.r || cur.g !== color.g || cur.b !== color.b) {
|
|
177
|
+
existing.set(traits.Color, color);
|
|
178
|
+
}
|
|
175
179
|
}
|
|
176
|
-
if (center) {
|
|
180
|
+
if (center && !isPoseEqual(existing.get(traits.Center), center)) {
|
|
177
181
|
existing.set(traits.Center, center);
|
|
178
182
|
}
|
|
179
183
|
traits.updateGeometryTrait(existing, frame.physicalObject);
|
|
180
184
|
if (!isEditMode && !partConfig.hasPendingSave) {
|
|
181
|
-
existing.
|
|
185
|
+
const baseline = existing.get(traits.Matrix);
|
|
186
|
+
if (baseline) {
|
|
187
|
+
poseToMatrix(pose, baseline);
|
|
188
|
+
existing.changed(traits.Matrix);
|
|
189
|
+
}
|
|
182
190
|
}
|
|
183
|
-
if (!existing.has(traits.
|
|
184
|
-
existing.add(traits.
|
|
191
|
+
if (!existing.has(traits.LiveMatrix)) {
|
|
192
|
+
existing.add(traits.LiveMatrix(poseToMatrix(pose, new Matrix4())));
|
|
185
193
|
}
|
|
186
|
-
// Skip the
|
|
194
|
+
// Skip the EditedMatrix overwrite while in edit mode. The merged
|
|
187
195
|
// `frames` source can differ from query.data once didRecentlyEdit
|
|
188
196
|
// flips (fragment overrides, round-trip drift), and writing those
|
|
189
197
|
// values would shift entities whose parents the user is portaling
|
|
190
198
|
// into — the gizmo's drag target moves underneath it. Once we're
|
|
191
199
|
// back in monitor mode, the next sync resumes the overwrite.
|
|
192
200
|
if (!isEditMode) {
|
|
193
|
-
existing.
|
|
201
|
+
const edited = existing.get(traits.EditedMatrix);
|
|
202
|
+
if (edited) {
|
|
203
|
+
poseToMatrix(pose, edited);
|
|
204
|
+
existing.changed(traits.EditedMatrix);
|
|
205
|
+
}
|
|
194
206
|
}
|
|
195
207
|
continue;
|
|
196
208
|
}
|
|
197
209
|
const entityTraits = [
|
|
198
210
|
traits.Name(name),
|
|
199
|
-
traits.
|
|
200
|
-
traits.
|
|
201
|
-
traits.
|
|
211
|
+
traits.Matrix(poseToMatrix(pose, new Matrix4())),
|
|
212
|
+
traits.EditedMatrix(poseToMatrix(pose, new Matrix4())),
|
|
213
|
+
traits.LiveMatrix(poseToMatrix(pose, new Matrix4())),
|
|
202
214
|
traits.FramesAPI,
|
|
203
215
|
traits.Transformable,
|
|
204
216
|
traits.ShowAxesHelper,
|
|
@@ -7,7 +7,7 @@ import { resourceColors } from '../color';
|
|
|
7
7
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
8
8
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
9
9
|
import { updateGeometryTrait } from '../ecs/traits';
|
|
10
|
-
import { createPose } from '../transform';
|
|
10
|
+
import { createPose, isPoseEqual } from '../transform';
|
|
11
11
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
12
12
|
import { useLogs } from './useLogs.svelte';
|
|
13
13
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
@@ -91,7 +91,9 @@ export const provideGeometries = (partID) => {
|
|
|
91
91
|
const existing = entities.get(entityKey);
|
|
92
92
|
if (existing) {
|
|
93
93
|
hierarchy.setParent(existing, name);
|
|
94
|
-
existing.
|
|
94
|
+
if (!isPoseEqual(existing.get(traits.Center), center)) {
|
|
95
|
+
existing.set(traits.Center, center);
|
|
96
|
+
}
|
|
95
97
|
updateGeometryTrait(existing, geometry);
|
|
96
98
|
continue;
|
|
97
99
|
}
|
|
@@ -204,9 +204,40 @@ export const usePartConfig = () => {
|
|
|
204
204
|
return getContext(key);
|
|
205
205
|
};
|
|
206
206
|
const useEmbeddedPartConfig = (props) => {
|
|
207
|
+
let hasPendingSave = $state(false);
|
|
208
|
+
let prevIsDirty = false;
|
|
209
|
+
let cleanSnapshot;
|
|
210
|
+
const snapshot = (current) => {
|
|
211
|
+
const json = current?.toJson?.();
|
|
212
|
+
return json === undefined ? undefined : JSON.stringify(json);
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* The host app owns saving, and we aren't notified directly. Set hasPendingSave
|
|
216
|
+
* to watch isDirty: true -> false transitions, representing a save.
|
|
217
|
+
*
|
|
218
|
+
* `useFrames` clears the flag on the next `revision` change
|
|
219
|
+
* once the server reports the new framesystem.
|
|
220
|
+
*/
|
|
221
|
+
$effect.pre(() => {
|
|
222
|
+
const dirty = props.isDirty;
|
|
223
|
+
const current = props.current;
|
|
224
|
+
if (prevIsDirty && !dirty) {
|
|
225
|
+
const next = snapshot(current);
|
|
226
|
+
if (next !== undefined && cleanSnapshot !== undefined && next !== cleanSnapshot) {
|
|
227
|
+
hasPendingSave = true;
|
|
228
|
+
}
|
|
229
|
+
cleanSnapshot = next;
|
|
230
|
+
}
|
|
231
|
+
else if (!prevIsDirty && !dirty) {
|
|
232
|
+
cleanSnapshot = snapshot(current);
|
|
233
|
+
}
|
|
234
|
+
prevIsDirty = dirty;
|
|
235
|
+
});
|
|
207
236
|
return {
|
|
208
237
|
hasEditPermissions: true,
|
|
209
|
-
hasPendingSave
|
|
238
|
+
get hasPendingSave() {
|
|
239
|
+
return hasPendingSave;
|
|
240
|
+
},
|
|
210
241
|
get isDirty() {
|
|
211
242
|
return props.isDirty;
|
|
212
243
|
},
|
|
@@ -220,8 +251,12 @@ const useEmbeddedPartConfig = (props) => {
|
|
|
220
251
|
const struct = Struct.fromJson(config);
|
|
221
252
|
return props.setLocalPartConfig(struct);
|
|
222
253
|
},
|
|
223
|
-
clearPendingSave() {
|
|
224
|
-
|
|
254
|
+
clearPendingSave() {
|
|
255
|
+
hasPendingSave = false;
|
|
256
|
+
},
|
|
257
|
+
setPendingSave() {
|
|
258
|
+
hasPendingSave = true;
|
|
259
|
+
},
|
|
225
260
|
};
|
|
226
261
|
};
|
|
227
262
|
const useStandalonePartConfig = (partID) => {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { useThrelte } from '@threlte/core';
|
|
2
2
|
import { Struct, TransformChangeType, WorldStateStoreClient, } from '@viamrobotics/sdk';
|
|
3
3
|
import { createResourceClient, createResourceQuery, createResourceStream, useResourceNames, } from '@viamrobotics/svelte-sdk';
|
|
4
|
+
import { Matrix4 } from 'three';
|
|
4
5
|
import { asFloat32Array, inMeters } from '../buffer';
|
|
5
6
|
import { createChunkLoader } from '../chunking';
|
|
6
7
|
import { drawTransform, updateMetadata } from '../draw';
|
|
7
8
|
import { traits, useWorld } from '../ecs';
|
|
8
9
|
import { isPointCloud } from '../geometry';
|
|
9
10
|
import { metadataFromStruct } from '../metadata';
|
|
10
|
-
import { createPose } from '../transform';
|
|
11
|
+
import { createPose, poseToMatrix } from '../transform';
|
|
11
12
|
import { usePartID } from './usePartID.svelte';
|
|
12
13
|
import { useRelationships } from './useRelationships.svelte';
|
|
13
14
|
export const provideWorldStates = () => {
|
|
@@ -133,7 +134,14 @@ const createWorldState = (client) => {
|
|
|
133
134
|
for (const path of changes) {
|
|
134
135
|
if (typeof path === 'string') {
|
|
135
136
|
if (path.startsWith('poseInObserverFrame.pose')) {
|
|
136
|
-
entity.
|
|
137
|
+
const matrix = entity.get(traits.Matrix);
|
|
138
|
+
if (matrix) {
|
|
139
|
+
poseToMatrix(createPose(transform.poseInObserverFrame?.pose), matrix);
|
|
140
|
+
entity.changed(traits.Matrix);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
entity.add(traits.Matrix(poseToMatrix(createPose(transform.poseInObserverFrame?.pose), new Matrix4())));
|
|
144
|
+
}
|
|
137
145
|
}
|
|
138
146
|
else if (path.startsWith('physicalObject') && transform.physicalObject) {
|
|
139
147
|
traits.updateGeometryTrait(entity, transform.physicalObject);
|
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.26.
|
|
3
|
+
"version": "1.26.2",
|
|
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
|
-
};
|