@viamrobotics/motion-tools 1.15.0 → 1.15.1
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/buf/common/v1/common_pb.d.ts +45 -0
- package/dist/buf/common/v1/common_pb.js +65 -0
- package/dist/components/App.svelte +2 -0
- package/dist/components/Entities/Geometry.svelte +5 -1
- package/dist/components/Selected.svelte +1 -17
- package/dist/components/overlay/AddFrames.svelte +64 -0
- package/dist/components/overlay/AddFrames.svelte.d.ts +3 -0
- package/dist/components/overlay/Details.svelte +2 -2
- package/dist/components/overlay/FloatingPanel.svelte +7 -2
- package/dist/components/overlay/left-pane/Tree.svelte +21 -26
- package/dist/components/overlay/left-pane/TreeContainer.svelte +9 -22
- package/dist/three/OBBHelper.d.ts +1 -2
- package/dist/three/OBBHelper.js +64 -43
- package/package.json +5 -5
- package/dist/components/overlay/left-pane/AddFrames.svelte +0 -32
- package/dist/components/overlay/left-pane/AddFrames.svelte.d.ts +0 -18
|
@@ -147,6 +147,47 @@ export declare class Orientation extends Message<Orientation> {
|
|
|
147
147
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Orientation;
|
|
148
148
|
static equals(a: Orientation | PlainMessage<Orientation> | undefined, b: Orientation | PlainMessage<Orientation> | undefined): boolean;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* @generated from message viam.common.v1.PoseCloud
|
|
152
|
+
*/
|
|
153
|
+
export declare class PoseCloud extends Message<PoseCloud> {
|
|
154
|
+
/**
|
|
155
|
+
* @generated from field: double x = 1;
|
|
156
|
+
*/
|
|
157
|
+
x: number;
|
|
158
|
+
/**
|
|
159
|
+
* @generated from field: double y = 2;
|
|
160
|
+
*/
|
|
161
|
+
y: number;
|
|
162
|
+
/**
|
|
163
|
+
* @generated from field: double z = 3;
|
|
164
|
+
*/
|
|
165
|
+
z: number;
|
|
166
|
+
/**
|
|
167
|
+
* @generated from field: double o_x = 4;
|
|
168
|
+
*/
|
|
169
|
+
oX: number;
|
|
170
|
+
/**
|
|
171
|
+
* @generated from field: double o_y = 5;
|
|
172
|
+
*/
|
|
173
|
+
oY: number;
|
|
174
|
+
/**
|
|
175
|
+
* @generated from field: double o_z = 6;
|
|
176
|
+
*/
|
|
177
|
+
oZ: number;
|
|
178
|
+
/**
|
|
179
|
+
* @generated from field: double theta = 7;
|
|
180
|
+
*/
|
|
181
|
+
theta: number;
|
|
182
|
+
constructor(data?: PartialMessage<PoseCloud>);
|
|
183
|
+
static readonly runtime: typeof proto3;
|
|
184
|
+
static readonly typeName = "viam.common.v1.PoseCloud";
|
|
185
|
+
static readonly fields: FieldList;
|
|
186
|
+
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PoseCloud;
|
|
187
|
+
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PoseCloud;
|
|
188
|
+
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PoseCloud;
|
|
189
|
+
static equals(a: PoseCloud | PlainMessage<PoseCloud> | undefined, b: PoseCloud | PlainMessage<PoseCloud> | undefined): boolean;
|
|
190
|
+
}
|
|
150
191
|
/**
|
|
151
192
|
* PoseInFrame contains a pose and the reference frame in which it was observed
|
|
152
193
|
*
|
|
@@ -161,6 +202,10 @@ export declare class PoseInFrame extends Message<PoseInFrame> {
|
|
|
161
202
|
* @generated from field: viam.common.v1.Pose pose = 2;
|
|
162
203
|
*/
|
|
163
204
|
pose?: Pose;
|
|
205
|
+
/**
|
|
206
|
+
* @generated from field: optional viam.common.v1.PoseCloud goal_cloud = 3;
|
|
207
|
+
*/
|
|
208
|
+
goalCloud?: PoseCloud;
|
|
164
209
|
constructor(data?: PartialMessage<PoseInFrame>);
|
|
165
210
|
static readonly runtime: typeof proto3;
|
|
166
211
|
static readonly typeName = "viam.common.v1.PoseInFrame";
|
|
@@ -205,6 +205,66 @@ export class Orientation extends Message {
|
|
|
205
205
|
return proto3.util.equals(Orientation, a, b);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* @generated from message viam.common.v1.PoseCloud
|
|
210
|
+
*/
|
|
211
|
+
export class PoseCloud extends Message {
|
|
212
|
+
/**
|
|
213
|
+
* @generated from field: double x = 1;
|
|
214
|
+
*/
|
|
215
|
+
x = 0;
|
|
216
|
+
/**
|
|
217
|
+
* @generated from field: double y = 2;
|
|
218
|
+
*/
|
|
219
|
+
y = 0;
|
|
220
|
+
/**
|
|
221
|
+
* @generated from field: double z = 3;
|
|
222
|
+
*/
|
|
223
|
+
z = 0;
|
|
224
|
+
/**
|
|
225
|
+
* @generated from field: double o_x = 4;
|
|
226
|
+
*/
|
|
227
|
+
oX = 0;
|
|
228
|
+
/**
|
|
229
|
+
* @generated from field: double o_y = 5;
|
|
230
|
+
*/
|
|
231
|
+
oY = 0;
|
|
232
|
+
/**
|
|
233
|
+
* @generated from field: double o_z = 6;
|
|
234
|
+
*/
|
|
235
|
+
oZ = 0;
|
|
236
|
+
/**
|
|
237
|
+
* @generated from field: double theta = 7;
|
|
238
|
+
*/
|
|
239
|
+
theta = 0;
|
|
240
|
+
constructor(data) {
|
|
241
|
+
super();
|
|
242
|
+
proto3.util.initPartial(data, this);
|
|
243
|
+
}
|
|
244
|
+
static runtime = proto3;
|
|
245
|
+
static typeName = "viam.common.v1.PoseCloud";
|
|
246
|
+
static fields = proto3.util.newFieldList(() => [
|
|
247
|
+
{ no: 1, name: "x", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
248
|
+
{ no: 2, name: "y", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
249
|
+
{ no: 3, name: "z", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
250
|
+
{ no: 4, name: "o_x", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
251
|
+
{ no: 5, name: "o_y", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
252
|
+
{ no: 6, name: "o_z", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
253
|
+
{ no: 7, name: "theta", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
|
254
|
+
]);
|
|
255
|
+
static fromBinary(bytes, options) {
|
|
256
|
+
return new PoseCloud().fromBinary(bytes, options);
|
|
257
|
+
}
|
|
258
|
+
static fromJson(jsonValue, options) {
|
|
259
|
+
return new PoseCloud().fromJson(jsonValue, options);
|
|
260
|
+
}
|
|
261
|
+
static fromJsonString(jsonString, options) {
|
|
262
|
+
return new PoseCloud().fromJsonString(jsonString, options);
|
|
263
|
+
}
|
|
264
|
+
static equals(a, b) {
|
|
265
|
+
return proto3.util.equals(PoseCloud, a, b);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
208
268
|
/**
|
|
209
269
|
* PoseInFrame contains a pose and the reference frame in which it was observed
|
|
210
270
|
*
|
|
@@ -219,6 +279,10 @@ export class PoseInFrame extends Message {
|
|
|
219
279
|
* @generated from field: viam.common.v1.Pose pose = 2;
|
|
220
280
|
*/
|
|
221
281
|
pose;
|
|
282
|
+
/**
|
|
283
|
+
* @generated from field: optional viam.common.v1.PoseCloud goal_cloud = 3;
|
|
284
|
+
*/
|
|
285
|
+
goalCloud;
|
|
222
286
|
constructor(data) {
|
|
223
287
|
super();
|
|
224
288
|
proto3.util.initPartial(data, this);
|
|
@@ -228,6 +292,7 @@ export class PoseInFrame extends Message {
|
|
|
228
292
|
static fields = proto3.util.newFieldList(() => [
|
|
229
293
|
{ no: 1, name: "reference_frame", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
|
230
294
|
{ no: 2, name: "pose", kind: "message", T: Pose },
|
|
295
|
+
{ no: 3, name: "goal_cloud", kind: "message", T: PoseCloud, opt: true },
|
|
231
296
|
]);
|
|
232
297
|
static fromBinary(bytes, options) {
|
|
233
298
|
return new PoseInFrame().fromBinary(bytes, options);
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
import FileDrop from './FileDrop/FileDrop.svelte'
|
|
31
31
|
import HoveredEntities from './hover/HoveredEntities.svelte'
|
|
32
|
+
import AddFrames from './overlay/AddFrames.svelte'
|
|
32
33
|
import LiveUpdatesBanner from './overlay/LiveUpdatesBanner.svelte'
|
|
33
34
|
import Logs from './overlay/Logs.svelte'
|
|
34
35
|
import ArmPositions from './overlay/widgets/ArmPositions.svelte'
|
|
@@ -144,6 +145,7 @@
|
|
|
144
145
|
|
|
145
146
|
<Settings />
|
|
146
147
|
<Logs />
|
|
148
|
+
<AddFrames />
|
|
147
149
|
</div>
|
|
148
150
|
{/snippet}
|
|
149
151
|
</SceneProviders>
|
|
@@ -16,19 +16,7 @@
|
|
|
16
16
|
const selectedEntity = useSelectedEntity()
|
|
17
17
|
const selectedObject3d = useSelectedObject3d()
|
|
18
18
|
|
|
19
|
-
const object = $derived.
|
|
20
|
-
if (!selectedObject3d.current) {
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Create a clone in the case of meshes, which could be frames with geometries,
|
|
25
|
-
// so that our bounding box doesn't include children
|
|
26
|
-
if (isInstanceOf(selectedObject3d.current, 'Mesh')) {
|
|
27
|
-
return selectedObject3d.current?.clone(false)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return selectedObject3d.current
|
|
31
|
-
})
|
|
19
|
+
const object = $derived(selectedObject3d.current)
|
|
32
20
|
|
|
33
21
|
const { start, stop } = useTask(
|
|
34
22
|
() => {
|
|
@@ -44,10 +32,6 @@
|
|
|
44
32
|
mesh.getBoundingBoxAt(selectedEntity.instance, box3)
|
|
45
33
|
obb.fromBox3(box3)
|
|
46
34
|
obbHelper.setFromOBB(obb)
|
|
47
|
-
} else if (isInstanceOf(selectedObject3d.current, 'Mesh')) {
|
|
48
|
-
selectedObject3d.current?.getWorldPosition(object.position)
|
|
49
|
-
selectedObject3d.current?.getWorldQuaternion(object.quaternion)
|
|
50
|
-
obbHelper.setFromObject(object)
|
|
51
35
|
} else {
|
|
52
36
|
obbHelper.setFromObject(object)
|
|
53
37
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Portal } from '@threlte/extras'
|
|
3
|
+
import { Button } from '@viamrobotics/prime-core'
|
|
4
|
+
|
|
5
|
+
import { useFramelessComponents } from '../../hooks/useFramelessComponents.svelte'
|
|
6
|
+
import { usePartConfig } from '../../hooks/usePartConfig.svelte'
|
|
7
|
+
import { usePartID } from '../../hooks/usePartID.svelte'
|
|
8
|
+
|
|
9
|
+
import DashboardButton from './dashboard/Button.svelte'
|
|
10
|
+
import FloatingPanel from './FloatingPanel.svelte'
|
|
11
|
+
|
|
12
|
+
const partID = usePartID()
|
|
13
|
+
const framelessComponents = useFramelessComponents()
|
|
14
|
+
const partConfig = usePartConfig()
|
|
15
|
+
|
|
16
|
+
let selectedComponent = $derived(framelessComponents.current[0] ?? '')
|
|
17
|
+
|
|
18
|
+
let isOpen = $state(false)
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
{#if partID.current && partConfig.hasEditPermissions}
|
|
22
|
+
<Portal id="dashboard">
|
|
23
|
+
<fieldset>
|
|
24
|
+
<DashboardButton
|
|
25
|
+
active
|
|
26
|
+
icon="axis-arrow"
|
|
27
|
+
description="Add frames"
|
|
28
|
+
onclick={() => {
|
|
29
|
+
isOpen = !isOpen
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
</fieldset>
|
|
33
|
+
</Portal>
|
|
34
|
+
|
|
35
|
+
<FloatingPanel
|
|
36
|
+
{isOpen}
|
|
37
|
+
defaultSize={{ width: 300, height: 150 }}
|
|
38
|
+
>
|
|
39
|
+
<div class="flex h-full flex-col items-center justify-center gap-2 overflow-auto p-3 text-xs">
|
|
40
|
+
{#if framelessComponents.current.length > 0}
|
|
41
|
+
<select
|
|
42
|
+
class="border-light hover:border-gray-6 focus:border-gray-9 h-7.5 w-full appearance-none border bg-white px-2 py-1.5 text-xs leading-tight"
|
|
43
|
+
bind:value={selectedComponent}
|
|
44
|
+
>
|
|
45
|
+
{#each framelessComponents.current as component (component)}
|
|
46
|
+
<option>{component}</option>
|
|
47
|
+
{/each}
|
|
48
|
+
</select>
|
|
49
|
+
|
|
50
|
+
<Button
|
|
51
|
+
icon="plus"
|
|
52
|
+
onclick={() => {
|
|
53
|
+
partConfig.createFrame(selectedComponent)
|
|
54
|
+
isOpen = false
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
Add frame
|
|
58
|
+
</Button>
|
|
59
|
+
{:else}
|
|
60
|
+
<p class="text-center">No components without frames</p>
|
|
61
|
+
{/if}
|
|
62
|
+
</div>
|
|
63
|
+
</FloatingPanel>
|
|
64
|
+
{/if}
|
|
@@ -638,9 +638,9 @@
|
|
|
638
638
|
{/if}
|
|
639
639
|
</div>
|
|
640
640
|
|
|
641
|
-
<h3 class="text-subtle-2 pt-3 pb-2">Relationships</h3>
|
|
642
|
-
|
|
643
641
|
{#if linkedEntities.current.length > 0}
|
|
642
|
+
<h3 class="text-subtle-2 pt-3 pb-2">Relationships</h3>
|
|
643
|
+
|
|
644
644
|
<div>
|
|
645
645
|
<div class="mt-0.5 flex flex-col gap-1">
|
|
646
646
|
<strong class="font-semibold">Linked entities</strong>
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
let {
|
|
21
21
|
title = '',
|
|
22
22
|
defaultSize = { width: 700, height: 500 },
|
|
23
|
+
defaultPosition = {
|
|
24
|
+
x: globalThis.innerWidth / 2 - defaultSize.width / 2,
|
|
25
|
+
y: globalThis.innerHeight / 2 - defaultSize.height / 2,
|
|
26
|
+
},
|
|
23
27
|
exitable = true,
|
|
24
28
|
resizable = false,
|
|
25
29
|
persistRect = true,
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
const floatingPanelService = useMachine(floatingPanel.machine, () => ({
|
|
33
37
|
id,
|
|
34
38
|
defaultSize,
|
|
39
|
+
defaultPosition,
|
|
35
40
|
resizable,
|
|
36
41
|
allowOverflow: false,
|
|
37
42
|
persistRect,
|
|
@@ -58,12 +63,12 @@
|
|
|
58
63
|
{...api.getHeaderProps()}
|
|
59
64
|
class="border-medium flex justify-between border-b p-2"
|
|
60
65
|
>
|
|
61
|
-
<
|
|
66
|
+
<h3
|
|
62
67
|
{...api.getTitleProps()}
|
|
63
68
|
class="text-gray-7 text-xs"
|
|
64
69
|
>
|
|
65
70
|
{title}
|
|
66
|
-
</
|
|
71
|
+
</h3>
|
|
67
72
|
|
|
68
73
|
{#if exitable}
|
|
69
74
|
<div
|
|
@@ -176,32 +176,27 @@
|
|
|
176
176
|
{/if}
|
|
177
177
|
{/snippet}
|
|
178
178
|
|
|
179
|
-
<div
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
{
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
{@render treeNode({ node, indexPath: [Number(index)], api })}
|
|
201
|
-
{/each}
|
|
202
|
-
</div>
|
|
203
|
-
{/if}
|
|
204
|
-
</div>
|
|
179
|
+
<div
|
|
180
|
+
{...api.getRootProps()}
|
|
181
|
+
class="h-full overflow-auto text-xs"
|
|
182
|
+
>
|
|
183
|
+
<div {...api.getTreeProps()}>
|
|
184
|
+
{#if rootChildren.length === 0}
|
|
185
|
+
<p class="text-subtle-2 px-2 py-4">No objects displayed</p>
|
|
186
|
+
{:else if rootChildren.length > 200}
|
|
187
|
+
<VirtualList
|
|
188
|
+
class="w-full"
|
|
189
|
+
items={rootChildren}
|
|
190
|
+
>
|
|
191
|
+
{#snippet vl_slot({ index, item })}
|
|
192
|
+
{@render treeNode({ node: item, indexPath: [Number(index)], api })}
|
|
193
|
+
{/snippet}
|
|
194
|
+
</VirtualList>
|
|
195
|
+
{:else}
|
|
196
|
+
{#each rootChildren as node, index (node.entity)}
|
|
197
|
+
{@render treeNode({ node, indexPath: [Number(index)], api })}
|
|
198
|
+
{/each}
|
|
199
|
+
{/if}
|
|
205
200
|
</div>
|
|
206
201
|
</div>
|
|
207
202
|
|
|
@@ -2,25 +2,18 @@
|
|
|
2
2
|
import { type Entity, IsExcluded } from 'koota'
|
|
3
3
|
|
|
4
4
|
import { traits, useQuery, useWorld } from '../../../ecs'
|
|
5
|
-
import { useEnvironment } from '../../../hooks/useEnvironment.svelte'
|
|
6
5
|
import { useFrames } from '../../../hooks/useFrames.svelte'
|
|
7
|
-
import { usePartConfig } from '../../../hooks/usePartConfig.svelte'
|
|
8
|
-
import { usePartID } from '../../../hooks/usePartID.svelte'
|
|
9
6
|
import { useSelectedEntity } from '../../../hooks/useSelection.svelte'
|
|
10
7
|
|
|
11
8
|
import FloatingPanel from '../FloatingPanel.svelte'
|
|
12
|
-
import AddFrames from './AddFrames.svelte'
|
|
13
9
|
import { buildTreeNodes, type TreeNode } from './buildTree'
|
|
14
10
|
import Tree from './Tree.svelte'
|
|
15
11
|
import { provideTreeExpandedContext } from './useExpanded.svelte'
|
|
16
12
|
|
|
17
13
|
provideTreeExpandedContext()
|
|
18
14
|
|
|
19
|
-
const partID = usePartID()
|
|
20
15
|
const selectedEntity = useSelectedEntity()
|
|
21
16
|
|
|
22
|
-
const environment = useEnvironment()
|
|
23
|
-
const partConfig = usePartConfig()
|
|
24
17
|
const frames = useFrames()
|
|
25
18
|
const world = useWorld()
|
|
26
19
|
|
|
@@ -49,19 +42,13 @@
|
|
|
49
42
|
exitable={false}
|
|
50
43
|
resizable
|
|
51
44
|
>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/>
|
|
62
|
-
|
|
63
|
-
{#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
|
|
64
|
-
<AddFrames />
|
|
65
|
-
{/if}
|
|
66
|
-
</div>
|
|
45
|
+
<Tree
|
|
46
|
+
{rootNode}
|
|
47
|
+
{nodeMap}
|
|
48
|
+
onSelectionChange={(event) => {
|
|
49
|
+
const value = event.selectedValue[0]
|
|
50
|
+
|
|
51
|
+
selectedEntity.set(value ? (Number(value) as Entity) : undefined)
|
|
52
|
+
}}
|
|
53
|
+
/>
|
|
67
54
|
</FloatingPanel>
|
|
@@ -9,7 +9,6 @@ export declare class OBBHelper extends LineSegments2 {
|
|
|
9
9
|
elements: number[];
|
|
10
10
|
};
|
|
11
11
|
}): this;
|
|
12
|
-
|
|
13
|
-
setFromObject(object: Object3D): this;
|
|
12
|
+
setFromObject(root: Object3D): this;
|
|
14
13
|
dispose(): void;
|
|
15
14
|
}
|
package/dist/three/OBBHelper.js
CHANGED
|
@@ -1,14 +1,42 @@
|
|
|
1
|
-
import { BoxGeometry, BufferGeometry, EdgesGeometry,
|
|
1
|
+
import { Box3, BoxGeometry, BufferGeometry, EdgesGeometry, Matrix4, Mesh, Object3D, Quaternion, Vector3, } from 'three';
|
|
2
2
|
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
|
|
3
3
|
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
|
|
4
4
|
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
|
|
5
|
+
const box = new Box3();
|
|
6
|
+
const childBox = new Box3();
|
|
7
|
+
const inverseRootMatrixWorld = new Matrix4();
|
|
8
|
+
const rootMatrixWorld = new Matrix4();
|
|
9
|
+
const relativeMatrix = new Matrix4();
|
|
10
|
+
const scaleMatrix = new Matrix4();
|
|
5
11
|
const center = new Vector3();
|
|
6
|
-
const half = new Vector3();
|
|
7
12
|
const size = new Vector3();
|
|
13
|
+
const basis = new Matrix4();
|
|
8
14
|
const quaternion = new Quaternion();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
const corners = [
|
|
16
|
+
new Vector3(),
|
|
17
|
+
new Vector3(),
|
|
18
|
+
new Vector3(),
|
|
19
|
+
new Vector3(),
|
|
20
|
+
new Vector3(),
|
|
21
|
+
new Vector3(),
|
|
22
|
+
new Vector3(),
|
|
23
|
+
new Vector3(),
|
|
24
|
+
];
|
|
25
|
+
const expandBoxByTransformedBox = (box, childBox, matrix) => {
|
|
26
|
+
const min = childBox.min;
|
|
27
|
+
const max = childBox.max;
|
|
28
|
+
corners[0].set(min.x, min.y, min.z).applyMatrix4(matrix);
|
|
29
|
+
corners[1].set(min.x, min.y, max.z).applyMatrix4(matrix);
|
|
30
|
+
corners[2].set(min.x, max.y, min.z).applyMatrix4(matrix);
|
|
31
|
+
corners[3].set(min.x, max.y, max.z).applyMatrix4(matrix);
|
|
32
|
+
corners[4].set(max.x, min.y, min.z).applyMatrix4(matrix);
|
|
33
|
+
corners[5].set(max.x, min.y, max.z).applyMatrix4(matrix);
|
|
34
|
+
corners[6].set(max.x, max.y, min.z).applyMatrix4(matrix);
|
|
35
|
+
corners[7].set(max.x, max.y, max.z).applyMatrix4(matrix);
|
|
36
|
+
for (const corner of corners) {
|
|
37
|
+
box.expandByPoint(corner);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
12
40
|
export class OBBHelper extends LineSegments2 {
|
|
13
41
|
constructor(color = 0x000000, linewidth = 2) {
|
|
14
42
|
const edges = new EdgesGeometry(new BoxGeometry());
|
|
@@ -27,52 +55,45 @@ export class OBBHelper extends LineSegments2 {
|
|
|
27
55
|
this.renderOrder = 999;
|
|
28
56
|
}
|
|
29
57
|
setFromOBB(obb) {
|
|
30
|
-
|
|
31
|
-
const basis = new Matrix4().setFromMatrix3(obb.rotation);
|
|
58
|
+
basis.setFromMatrix3(obb.rotation);
|
|
32
59
|
quaternion.setFromRotationMatrix(basis);
|
|
33
|
-
// scale = full size
|
|
34
60
|
size.copy(obb.halfSize).multiplyScalar(2);
|
|
35
|
-
// compose
|
|
36
61
|
this.matrix.compose(obb.center, quaternion, size);
|
|
37
|
-
this.matrixWorld.copy(this.matrix);
|
|
62
|
+
this.matrixWorld.copy(this.matrix);
|
|
38
63
|
return this;
|
|
39
64
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
setFromObject(root) {
|
|
66
|
+
root.updateWorldMatrix(true, true);
|
|
67
|
+
rootMatrixWorld.copy(root.matrixWorld);
|
|
68
|
+
inverseRootMatrixWorld.copy(rootMatrixWorld).invert();
|
|
69
|
+
box.makeEmpty();
|
|
70
|
+
root.traverse((child) => {
|
|
71
|
+
const mesh = child;
|
|
72
|
+
const geometry = mesh.geometry;
|
|
73
|
+
if (!geometry)
|
|
74
|
+
return;
|
|
75
|
+
if (!geometry.boundingBox) {
|
|
76
|
+
geometry.computeBoundingBox();
|
|
77
|
+
}
|
|
78
|
+
if (!geometry.boundingBox)
|
|
79
|
+
return;
|
|
80
|
+
// Transform this mesh's local bounding box into root-local space
|
|
81
|
+
relativeMatrix.multiplyMatrices(inverseRootMatrixWorld, mesh.matrixWorld);
|
|
82
|
+
childBox.copy(geometry.boundingBox);
|
|
83
|
+
expandBoxByTransformedBox(box, childBox, relativeMatrix);
|
|
84
|
+
});
|
|
85
|
+
if (box.isEmpty()) {
|
|
56
86
|
console.warn('[OBBHelper] No geometry found on object to compute OBB.');
|
|
57
87
|
return this;
|
|
58
88
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
object.getWorldQuaternion(quaternion);
|
|
68
|
-
object.getWorldScale(scale);
|
|
69
|
-
// non-uniform scale supported (no shear): enlarge halfSize by |scale|
|
|
70
|
-
half.copy(size).multiply(absScale.set(Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)));
|
|
71
|
-
worldCenter.copy(center);
|
|
72
|
-
object.localToWorld(worldCenter);
|
|
73
|
-
// compose transform (unit box -> oriented box)
|
|
74
|
-
const fullSize = half.multiplyScalar(2);
|
|
75
|
-
this.matrix.compose(worldCenter, quaternion, fullSize);
|
|
89
|
+
box.getCenter(center);
|
|
90
|
+
box.getSize(size);
|
|
91
|
+
// Place the helper at the center of the bounding box, in root-local space
|
|
92
|
+
this.matrix.makeTranslation(center.x, center.y, center.z);
|
|
93
|
+
// Then inherit the root's full world transform
|
|
94
|
+
this.matrix.premultiply(rootMatrixWorld);
|
|
95
|
+
// Scale the unit box to the OBB extents in root-local axes
|
|
96
|
+
this.matrix.multiply(scaleMatrix.makeScale(size.x, size.y, size.z));
|
|
76
97
|
this.matrixWorld.copy(this.matrix);
|
|
77
98
|
return this;
|
|
78
99
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"@skeletonlabs/skeleton": "3.2.0",
|
|
18
18
|
"@skeletonlabs/skeleton-svelte": "1.5.1",
|
|
19
19
|
"@sveltejs/adapter-static": "3.0.9",
|
|
20
|
-
"@sveltejs/kit": "2.
|
|
21
|
-
"@sveltejs/package": "2.5.
|
|
20
|
+
"@sveltejs/kit": "2.55.0",
|
|
21
|
+
"@sveltejs/package": "2.5.7",
|
|
22
22
|
"@sveltejs/vite-plugin-svelte": "6.1.4",
|
|
23
23
|
"@tailwindcss/forms": "0.5.10",
|
|
24
24
|
"@tailwindcss/vite": "4.1.13",
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"prettier-plugin-tailwindcss": "0.6.14",
|
|
64
64
|
"publint": "0.3.12",
|
|
65
65
|
"runed": "0.31.1",
|
|
66
|
-
"svelte": "5.
|
|
67
|
-
"svelte-check": "4.
|
|
66
|
+
"svelte": "5.53.13",
|
|
67
|
+
"svelte-check": "4.4.5",
|
|
68
68
|
"svelte-virtuallists": "1.4.2",
|
|
69
69
|
"tailwindcss": "4.1.13",
|
|
70
70
|
"three": "0.182.0",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { IconButton } from '@viamrobotics/prime-core'
|
|
3
|
-
|
|
4
|
-
import { useFramelessComponents } from '../../../hooks/useFramelessComponents.svelte'
|
|
5
|
-
import { usePartConfig } from '../../../hooks/usePartConfig.svelte'
|
|
6
|
-
|
|
7
|
-
import Drawer from './Drawer.svelte'
|
|
8
|
-
|
|
9
|
-
const framelessComponents = useFramelessComponents()
|
|
10
|
-
const partConfig = usePartConfig()
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<Drawer name="Add frames">
|
|
14
|
-
<div class="flex max-h-64 flex-col gap-2 overflow-auto p-3">
|
|
15
|
-
{#if framelessComponents.current.length > 0}
|
|
16
|
-
<ul class="space-y-1">
|
|
17
|
-
{#each framelessComponents.current as component (component)}
|
|
18
|
-
<li class="flex items-center gap-2 text-xs text-gray-700">
|
|
19
|
-
{component}
|
|
20
|
-
<IconButton
|
|
21
|
-
label="Add frame"
|
|
22
|
-
icon="plus"
|
|
23
|
-
onclick={() => partConfig.createFrame(component)}
|
|
24
|
-
/>
|
|
25
|
-
</li>
|
|
26
|
-
{/each}
|
|
27
|
-
</ul>
|
|
28
|
-
{:else}
|
|
29
|
-
No components without frames
|
|
30
|
-
{/if}
|
|
31
|
-
</div>
|
|
32
|
-
</Drawer>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const AddFrames: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type AddFrames = InstanceType<typeof AddFrames>;
|
|
18
|
-
export default AddFrames;
|