@viamrobotics/motion-tools 1.16.0 → 1.18.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/attribute.d.ts +3 -2
- package/dist/attribute.js +24 -16
- package/dist/buf/draw/v1/drawing_pb.d.ts +33 -16
- package/dist/buf/draw/v1/drawing_pb.js +35 -17
- package/dist/buf/draw/v1/metadata_pb.d.ts +44 -3
- package/dist/buf/draw/v1/metadata_pb.js +54 -3
- package/dist/buf/draw/v1/scene_pb.d.ts +6 -6
- package/dist/buf/draw/v1/scene_pb.js +7 -7
- package/dist/buffer.d.ts +54 -45
- package/dist/buffer.js +91 -57
- package/dist/color.d.ts +1 -2
- package/dist/color.js +5 -12
- package/dist/components/App.svelte +18 -3
- package/dist/components/App.svelte.d.ts +15 -2
- package/dist/components/Entities/Arrows/ArrowGroups.svelte +5 -6
- package/dist/components/Entities/Arrows/Arrows.svelte +9 -0
- package/dist/components/Entities/Entities.svelte +18 -1
- package/dist/components/Entities/Frame.svelte +7 -1
- package/dist/components/Entities/GLTF.svelte +13 -2
- package/dist/components/Entities/Line.svelte +46 -18
- package/dist/components/Entities/LineDots.svelte +38 -8
- package/dist/components/Entities/LineDots.svelte.d.ts +2 -2
- package/dist/components/Entities/LineGeometry.svelte +2 -1
- package/dist/components/Entities/LineGeometry.svelte.d.ts +2 -0
- package/dist/components/Entities/Mesh.svelte +8 -1
- package/dist/components/Entities/Points.svelte +22 -11
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +6 -2
- package/dist/components/FileDrop/FileDrop.svelte +5 -1
- package/dist/components/KeyboardControls.svelte +2 -10
- package/dist/components/PCD.svelte +11 -4
- package/dist/components/PCD.svelte.d.ts +3 -1
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Selected.svelte +2 -12
- package/dist/components/Selection/Ellipse.svelte +2 -0
- package/dist/components/Selection/Lasso.svelte +2 -0
- package/dist/components/Selection/Tool.svelte +7 -56
- package/dist/components/Selection/Tool.svelte.d.ts +2 -2
- package/dist/components/Selection/useSelectionPlugin.svelte.d.ts +8 -0
- package/dist/components/Selection/useSelectionPlugin.svelte.js +24 -0
- package/dist/components/Snapshot.svelte +4 -2
- package/dist/components/overlay/AddRelationship.svelte +1 -2
- package/dist/components/overlay/AddRelationship.svelte.d.ts +1 -1
- package/dist/components/overlay/Details.svelte +12 -12
- package/dist/components/overlay/Details.svelte.d.ts +8 -1
- package/dist/components/overlay/settings/Settings.svelte +8 -1
- package/dist/components/xr/XR.svelte +1 -1
- package/dist/draw.d.ts +13 -0
- package/dist/draw.js +428 -0
- package/dist/ecs/traits.d.ts +31 -13
- package/dist/ecs/traits.js +25 -8
- package/dist/geometry.js +3 -0
- package/dist/hooks/useDrawAPI.svelte.js +61 -24
- package/dist/hooks/useDrawService.svelte.d.ts +12 -0
- package/dist/hooks/useDrawService.svelte.js +240 -0
- package/dist/hooks/usePointcloudObjects.svelte.js +7 -2
- package/dist/hooks/usePointclouds.svelte.js +7 -2
- package/dist/hooks/useSettings.svelte.d.ts +2 -1
- package/dist/hooks/useSettings.svelte.js +1 -1
- package/dist/hooks/useWorldState.svelte.js +5 -52
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +2 -0
- package/dist/loaders/pcd/index.d.ts +1 -1
- package/dist/loaders/pcd/messages.d.ts +2 -2
- package/dist/loaders/pcd/worker.inline.d.ts +1 -1
- package/dist/loaders/pcd/worker.inline.js +229 -187
- package/dist/loaders/pcd/worker.js +2 -2
- package/dist/metadata.d.ts +9 -15
- package/dist/metadata.js +45 -9
- package/dist/plugins/bvh.svelte.js +6 -2
- package/dist/snapshot.d.ts +3 -9
- package/dist/snapshot.js +11 -204
- package/dist/three/InstancedArrows/InstancedArrows.js +3 -2
- package/package.json +14 -11
- package/dist/components/xr/Hands.svelte +0 -23
- package/dist/components/xr/Hands.svelte.d.ts +0 -18
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<script lang="ts">
|
|
15
|
+
import type { Entity } from 'koota'
|
|
16
|
+
import type { Snippet } from 'svelte'
|
|
17
|
+
|
|
15
18
|
import { draggable } from '@neodrag/svelte'
|
|
16
19
|
import { isInstanceOf, useTask } from '@threlte/core'
|
|
17
20
|
import { Button, Icon, Input, Select, Tooltip } from '@viamrobotics/prime-core'
|
|
@@ -34,7 +37,11 @@
|
|
|
34
37
|
} from '../../hooks/useSelection.svelte'
|
|
35
38
|
import { createPose } from '../../transform'
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
interface Props {
|
|
41
|
+
details?: Snippet<[{ entity: Entity }]>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { details }: Props = $props()
|
|
38
45
|
|
|
39
46
|
const world = useWorld()
|
|
40
47
|
const controls = useCameraControls()
|
|
@@ -94,7 +101,7 @@
|
|
|
94
101
|
}
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
useTask(
|
|
98
105
|
() => {
|
|
99
106
|
object3d?.getWorldPosition(vec3)
|
|
100
107
|
if (!vec3.equals(worldPosition)) {
|
|
@@ -114,19 +121,11 @@
|
|
|
114
121
|
}
|
|
115
122
|
},
|
|
116
123
|
{
|
|
117
|
-
autoStart: false,
|
|
118
124
|
autoInvalidate: false,
|
|
125
|
+
running: () => object3d !== undefined,
|
|
119
126
|
}
|
|
120
127
|
)
|
|
121
128
|
|
|
122
|
-
$effect.pre(() => {
|
|
123
|
-
if (object3d) {
|
|
124
|
-
start()
|
|
125
|
-
} else {
|
|
126
|
-
stop()
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
|
|
130
129
|
$effect(() => {
|
|
131
130
|
if (entity) {
|
|
132
131
|
const worldPose = createPose({
|
|
@@ -266,7 +265,6 @@
|
|
|
266
265
|
bounds: 'body',
|
|
267
266
|
handle: dragElement,
|
|
268
267
|
}}
|
|
269
|
-
{...rest}
|
|
270
268
|
>
|
|
271
269
|
<div
|
|
272
270
|
class="flex cursor-move items-center justify-between gap-2 pb-2"
|
|
@@ -662,6 +660,8 @@
|
|
|
662
660
|
</div>
|
|
663
661
|
{/if}
|
|
664
662
|
|
|
663
|
+
{@render details?.({ entity })}
|
|
664
|
+
|
|
665
665
|
<h3 class="text-subtle-2 pt-3 pb-2">Actions</h3>
|
|
666
666
|
|
|
667
667
|
{#if focusedEntity.current}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Entity } from 'koota';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
details?: Snippet<[{
|
|
5
|
+
entity: Entity;
|
|
6
|
+
}]>;
|
|
7
|
+
}
|
|
8
|
+
declare const Details: import("svelte").Component<Props, {}, "">;
|
|
2
9
|
type Details = ReturnType<typeof Details>;
|
|
3
10
|
export default Details;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { useResourceNames } from '@viamrobotics/svelte-sdk'
|
|
6
6
|
import { PersistedState } from 'runed'
|
|
7
7
|
import { onMount } from 'svelte'
|
|
8
|
+
import { Color } from 'three'
|
|
8
9
|
|
|
9
10
|
import DashboardButton from '../dashboard/Button.svelte'
|
|
10
11
|
import XRControllerSettings from '../../xr/XRControllerSettings.svelte'
|
|
@@ -54,6 +55,8 @@
|
|
|
54
55
|
|
|
55
56
|
const isOpen = new PersistedState('settings-is-open', false)
|
|
56
57
|
const activeTab = new PersistedState('settings-active-tab', 'Connection')
|
|
58
|
+
|
|
59
|
+
const colorHex = $derived(`#${new Color(settings.current.pointColor).getHexString()}`)
|
|
57
60
|
</script>
|
|
58
61
|
|
|
59
62
|
<Portal id="dashboard">
|
|
@@ -122,7 +125,11 @@
|
|
|
122
125
|
<div class="w-20">
|
|
123
126
|
<Input
|
|
124
127
|
type="color"
|
|
125
|
-
|
|
128
|
+
value={colorHex}
|
|
129
|
+
on:change={(event) => {
|
|
130
|
+
const value = (event.target as HTMLInputElement).value
|
|
131
|
+
settings.current.pointColor = value
|
|
132
|
+
}}
|
|
126
133
|
on:keydown={(event) => event.stopImmediatePropagation()}
|
|
127
134
|
/>
|
|
128
135
|
</div>
|
package/dist/draw.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TransformWithUUID } from '@viamrobotics/sdk';
|
|
2
|
+
import type { Entity, Trait, World } from 'koota';
|
|
3
|
+
import type { Transform as TransformProto } from './buf/common/v1/common_pb';
|
|
4
|
+
import type { Drawing } from './buf/draw/v1/drawing_pb';
|
|
5
|
+
export type Transform = TransformWithUUID | TransformProto;
|
|
6
|
+
type Options = {
|
|
7
|
+
removable?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const drawTransform: (world: World, { referenceFrame, poseInObserverFrame, physicalObject, metadata }: Transform, api: Trait, options?: Options) => Entity;
|
|
10
|
+
export declare const drawDrawing: (world: World, drawing: Drawing, api: Trait, options?: Options) => Entity[];
|
|
11
|
+
export declare const updateTransform: (entity: Entity, { poseInObserverFrame, physicalObject, metadata }: Transform, options?: Options) => void;
|
|
12
|
+
export declare const updateDrawing: (world: World, entities: Entity[], drawing: Drawing, api: Trait, options?: Options) => Entity[];
|
|
13
|
+
export {};
|
package/dist/draw.js
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { Vector3, Vector4 } from 'three';
|
|
2
|
+
import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
|
|
3
|
+
import { createBufferGeometry, updateBufferGeometry } from './attribute';
|
|
4
|
+
import { asFloat32Array, asOpacity, asRGB, inMeters, isSingleColor, isVertexColors, STRIDE, } from './buffer';
|
|
5
|
+
import { traits } from './ecs';
|
|
6
|
+
import { parsePcdInWorker } from './loaders/pcd';
|
|
7
|
+
import { metadataFromStruct } from './metadata';
|
|
8
|
+
import { createPose } from './transform';
|
|
9
|
+
import { ColorFormat } from './buf/draw/v1/metadata_pb';
|
|
10
|
+
import { isPointCloud } from './geometry';
|
|
11
|
+
const vec3 = new Vector3();
|
|
12
|
+
const rgb = { r: 0, g: 0, b: 0 };
|
|
13
|
+
const DEFAULT_LINE_WIDTH = 5;
|
|
14
|
+
const DEFAULT_POINT_SIZE = 10;
|
|
15
|
+
const DEFAULT_NURBS_DEGREE = 3;
|
|
16
|
+
const DEFAULT_NURBS_WEIGHT = 1;
|
|
17
|
+
const DEFAULT_ANIMATION_NAME = '';
|
|
18
|
+
const DEFAULT_ARROWS_COLORS = new Uint8Array([0, 255, 0]);
|
|
19
|
+
const DEFAULT_LINE_COLORS = new Uint8Array([0, 128, 255]);
|
|
20
|
+
const DEFAULT_LINE_DOT_COLORS = new Uint8Array([0, 0, 139]);
|
|
21
|
+
const DEFAULT_POINTS_COLORS = new Uint8Array([51, 51, 51]);
|
|
22
|
+
const DEFAULT_NURBS_COLORS = new Uint8Array([0, 255, 255]);
|
|
23
|
+
const DEFAULT_OPACITY = 1;
|
|
24
|
+
export const drawTransform = (world, { referenceFrame, poseInObserverFrame, physicalObject, metadata }, api, options = { removable: true }) => {
|
|
25
|
+
const entityTraits = [
|
|
26
|
+
traits.Name(referenceFrame),
|
|
27
|
+
traits.Pose(createPose(poseInObserverFrame?.pose)),
|
|
28
|
+
api,
|
|
29
|
+
];
|
|
30
|
+
if (physicalObject) {
|
|
31
|
+
entityTraits.push(traits.Geometry(physicalObject));
|
|
32
|
+
const center = physicalObject.center;
|
|
33
|
+
if (center)
|
|
34
|
+
entityTraits.push(traits.Center(center));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
entityTraits.push(traits.ReferenceFrame);
|
|
38
|
+
}
|
|
39
|
+
if (options.removable)
|
|
40
|
+
entityTraits.push(traits.Removable);
|
|
41
|
+
const parent = poseInObserverFrame?.referenceFrame;
|
|
42
|
+
if (parent && parent !== 'world')
|
|
43
|
+
entityTraits.push(traits.Parent(parent));
|
|
44
|
+
const parsedMetadata = metadataFromStruct(metadata?.fields);
|
|
45
|
+
if (parsedMetadata.showAxesHelper)
|
|
46
|
+
entityTraits.push(traits.ShowAxesHelper);
|
|
47
|
+
if (parsedMetadata.invisible)
|
|
48
|
+
entityTraits.push(traits.Invisible);
|
|
49
|
+
const { colors, opacities } = parsedMetadata;
|
|
50
|
+
const pointCloud = isPointCloud(physicalObject?.geometryType)
|
|
51
|
+
? physicalObject.geometryType.value.pointCloud
|
|
52
|
+
: undefined;
|
|
53
|
+
if (colors && !pointCloud) {
|
|
54
|
+
if (isVertexColors(colors)) {
|
|
55
|
+
entityTraits.push(traits.Colors(colors));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
entityTraits.push(traits.Color(asRGB(colors, rgb)));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
entityTraits.push(traits.Opacity(asOpacity(opacities, DEFAULT_OPACITY)));
|
|
62
|
+
const entity = world.spawn(...entityTraits);
|
|
63
|
+
if (pointCloud)
|
|
64
|
+
parsePointCloud(world, entity, pointCloud, parsedMetadata);
|
|
65
|
+
return entity;
|
|
66
|
+
};
|
|
67
|
+
export const drawDrawing = (world, drawing, api, options = { removable: true }) => {
|
|
68
|
+
const { referenceFrame, poseInObserverFrame, physicalObject, metadata } = drawing;
|
|
69
|
+
if (physicalObject?.geometryType?.case === 'model')
|
|
70
|
+
return drawModel(world, drawing, api, options);
|
|
71
|
+
const entity = world.spawn(traits.Name(referenceFrame), traits.Pose(createPose(poseInObserverFrame?.pose)), api);
|
|
72
|
+
const parent = poseInObserverFrame?.referenceFrame;
|
|
73
|
+
if (parent && parent !== 'world')
|
|
74
|
+
entity.add(traits.Parent(parent));
|
|
75
|
+
if (options.removable)
|
|
76
|
+
entity.add(traits.Removable);
|
|
77
|
+
if (metadata?.showAxesHelper)
|
|
78
|
+
entity.add(traits.ShowAxesHelper);
|
|
79
|
+
if (metadata?.invisible)
|
|
80
|
+
entity.add(traits.Invisible);
|
|
81
|
+
applyShape(entity, drawing);
|
|
82
|
+
return [entity];
|
|
83
|
+
};
|
|
84
|
+
export const updateTransform = (entity, { poseInObserverFrame, physicalObject, metadata }, options = { removable: true }) => {
|
|
85
|
+
entity.set(traits.Pose, createPose(poseInObserverFrame?.pose));
|
|
86
|
+
const parent = poseInObserverFrame?.referenceFrame;
|
|
87
|
+
if (parent && parent !== 'world')
|
|
88
|
+
entity.set(traits.Parent, parent);
|
|
89
|
+
if (physicalObject) {
|
|
90
|
+
traits.updateGeometryTrait(entity, physicalObject);
|
|
91
|
+
const center = physicalObject.center;
|
|
92
|
+
if (center) {
|
|
93
|
+
entity.set(traits.Center, center);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
entity.remove(traits.Center);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const parsedMetadata = metadataFromStruct(metadata?.fields);
|
|
100
|
+
if (parsedMetadata.showAxesHelper)
|
|
101
|
+
entity.add(traits.ShowAxesHelper);
|
|
102
|
+
else
|
|
103
|
+
entity.remove(traits.ShowAxesHelper);
|
|
104
|
+
if (parsedMetadata.invisible)
|
|
105
|
+
entity.add(traits.Invisible);
|
|
106
|
+
else
|
|
107
|
+
entity.remove(traits.Invisible);
|
|
108
|
+
const { colors, opacities } = parsedMetadata;
|
|
109
|
+
if (colors) {
|
|
110
|
+
if (isPointCloud(physicalObject?.geometryType)) {
|
|
111
|
+
updateColors(entity, parsedMetadata);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
addColorTraits(entity, colors);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const opacity = asOpacity(opacities, DEFAULT_OPACITY);
|
|
118
|
+
if (opacity < 1)
|
|
119
|
+
entity.add(traits.Opacity(opacity));
|
|
120
|
+
if (options.removable)
|
|
121
|
+
entity.add(traits.Removable);
|
|
122
|
+
if (!options.removable)
|
|
123
|
+
entity.remove(traits.Removable);
|
|
124
|
+
};
|
|
125
|
+
export const updateDrawing = (world, entities, drawing, api, options = { removable: true }) => {
|
|
126
|
+
const { poseInObserverFrame, physicalObject, metadata } = drawing;
|
|
127
|
+
if (physicalObject?.geometryType?.case === 'model') {
|
|
128
|
+
for (const entity of entities) {
|
|
129
|
+
if (world.has(entity))
|
|
130
|
+
entity.destroy();
|
|
131
|
+
}
|
|
132
|
+
return drawDrawing(world, drawing, api, options);
|
|
133
|
+
}
|
|
134
|
+
if (entities.length === 0)
|
|
135
|
+
return entities;
|
|
136
|
+
const entity = entities[0];
|
|
137
|
+
if (!world.has(entity))
|
|
138
|
+
return entities;
|
|
139
|
+
entity.set(traits.Pose, createPose(poseInObserverFrame?.pose));
|
|
140
|
+
const parent = poseInObserverFrame?.referenceFrame;
|
|
141
|
+
if (parent && parent !== 'world')
|
|
142
|
+
entity.set(traits.Parent, parent);
|
|
143
|
+
if (metadata?.showAxesHelper)
|
|
144
|
+
entity.add(traits.ShowAxesHelper);
|
|
145
|
+
if (!metadata?.showAxesHelper)
|
|
146
|
+
entity.remove(traits.ShowAxesHelper);
|
|
147
|
+
if (metadata?.invisible)
|
|
148
|
+
entity.add(traits.Invisible);
|
|
149
|
+
if (!metadata?.invisible)
|
|
150
|
+
entity.remove(traits.Invisible);
|
|
151
|
+
updateShape(entity, drawing);
|
|
152
|
+
return entities;
|
|
153
|
+
};
|
|
154
|
+
const applyShape = (entity, { physicalObject, metadata }) => {
|
|
155
|
+
const colors = metadata?.colors;
|
|
156
|
+
const opacities = metadata?.opacities;
|
|
157
|
+
const geometryType = physicalObject?.geometryType;
|
|
158
|
+
const opacity = asOpacity(opacities, DEFAULT_OPACITY);
|
|
159
|
+
entity.add(traits.Opacity(opacity));
|
|
160
|
+
switch (geometryType?.case) {
|
|
161
|
+
case 'arrows': {
|
|
162
|
+
const poses = asFloat32Array(geometryType.value.poses);
|
|
163
|
+
entity.add(traits.Positions(poses));
|
|
164
|
+
entity.add(traits.Instances({ count: poses.length / STRIDE.ARROWS }));
|
|
165
|
+
addColorTraits(entity, colors ?? DEFAULT_ARROWS_COLORS);
|
|
166
|
+
entity.add(traits.Arrows({ headAtPose: true }));
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case 'line': {
|
|
170
|
+
const positions = asFloat32Array(geometryType.value.positions, inMeters);
|
|
171
|
+
const center = physicalObject?.center;
|
|
172
|
+
if (center)
|
|
173
|
+
entity.add(traits.Center(center));
|
|
174
|
+
addColorTraits(entity, colors ?? DEFAULT_LINE_COLORS);
|
|
175
|
+
const lineWidth = geometryType.value.lineWidth ?? DEFAULT_LINE_WIDTH;
|
|
176
|
+
entity.add(traits.LineWidth(lineWidth));
|
|
177
|
+
entity.add(traits.DotSize(geometryType.value.dotSize ?? lineWidth));
|
|
178
|
+
entity.add(traits.LinePositions(positions));
|
|
179
|
+
entity.add(traits.DotColors(geometryType.value.dotColors ?? DEFAULT_LINE_DOT_COLORS));
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case 'points': {
|
|
183
|
+
const positions = asFloat32Array(geometryType.value.positions, inMeters);
|
|
184
|
+
const center = physicalObject?.center;
|
|
185
|
+
if (center)
|
|
186
|
+
entity.add(traits.Center(center));
|
|
187
|
+
addColorTraits(entity, colors ?? DEFAULT_POINTS_COLORS);
|
|
188
|
+
entity.add(traits.PointSize(geometryType.value.pointSize ?? DEFAULT_POINT_SIZE));
|
|
189
|
+
entity.add(traits.BufferGeometry(createBufferGeometry(positions, {
|
|
190
|
+
colors: isVertexColors(colors) ? colors : undefined,
|
|
191
|
+
colorFormat: metadata?.colorFormat ?? ColorFormat.UNSPECIFIED,
|
|
192
|
+
})));
|
|
193
|
+
entity.add(traits.Points);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'nurbs': {
|
|
197
|
+
const { degree = DEFAULT_NURBS_DEGREE, knots: knotsBuffer, weights: weightsBuffer, controlPoints: controlPointsBuffer, } = geometryType.value;
|
|
198
|
+
const knots = asFloat32Array(knotsBuffer).values().toArray();
|
|
199
|
+
const weights = weightsBuffer ? asFloat32Array(weightsBuffer) : [];
|
|
200
|
+
const controlPointsArray = asFloat32Array(controlPointsBuffer);
|
|
201
|
+
const numControlPoints = controlPointsArray.length / STRIDE.NURBS_CONTROL_POINTS;
|
|
202
|
+
const controlPoints = Array.from({ length: numControlPoints });
|
|
203
|
+
for (let j = 0; j < numControlPoints; j += 1) {
|
|
204
|
+
const idx = j * STRIDE.NURBS_CONTROL_POINTS;
|
|
205
|
+
vec3
|
|
206
|
+
.set(controlPointsArray[idx], controlPointsArray[idx + 1], controlPointsArray[idx + 2])
|
|
207
|
+
.multiplyScalar(0.001);
|
|
208
|
+
controlPoints[j] = new Vector4(vec3.x, vec3.y, vec3.z, weights[j] ?? DEFAULT_NURBS_WEIGHT);
|
|
209
|
+
}
|
|
210
|
+
const curve = new NURBSCurve(degree, knots, controlPoints);
|
|
211
|
+
const numPoints = 600;
|
|
212
|
+
const points = new Float32Array(numPoints * 3);
|
|
213
|
+
for (let i = 0; i < numPoints; i += 1) {
|
|
214
|
+
const t = i / (numPoints - 1);
|
|
215
|
+
curve.getPointAt(t, vec3);
|
|
216
|
+
points[i * 3 + 0] = vec3.x;
|
|
217
|
+
points[i * 3 + 1] = vec3.y;
|
|
218
|
+
points[i * 3 + 2] = vec3.z;
|
|
219
|
+
}
|
|
220
|
+
const center = physicalObject?.center;
|
|
221
|
+
if (center)
|
|
222
|
+
entity.add(traits.Center(center));
|
|
223
|
+
addColorTraits(entity, colors ?? DEFAULT_NURBS_COLORS);
|
|
224
|
+
entity.add(traits.LineWidth(geometryType.value.lineWidth ?? DEFAULT_LINE_WIDTH));
|
|
225
|
+
entity.add(traits.LinePositions(points));
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
default: {
|
|
229
|
+
const center = physicalObject?.center;
|
|
230
|
+
if (center)
|
|
231
|
+
entity.add(traits.Center(center));
|
|
232
|
+
if (colors)
|
|
233
|
+
addColorTraits(entity, colors);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const drawModel = (world, { referenceFrame, poseInObserverFrame, physicalObject, metadata }, api, { removable = true }) => {
|
|
239
|
+
const entities = [];
|
|
240
|
+
const parent = poseInObserverFrame?.referenceFrame;
|
|
241
|
+
const geometryType = physicalObject?.geometryType;
|
|
242
|
+
if (geometryType?.case !== 'model')
|
|
243
|
+
return entities;
|
|
244
|
+
const baseTraits = [
|
|
245
|
+
traits.Name(referenceFrame),
|
|
246
|
+
traits.Pose(createPose(poseInObserverFrame?.pose)),
|
|
247
|
+
api,
|
|
248
|
+
];
|
|
249
|
+
if (parent && parent !== 'world')
|
|
250
|
+
baseTraits.push(traits.Parent(parent));
|
|
251
|
+
if (removable)
|
|
252
|
+
baseTraits.push(traits.Removable);
|
|
253
|
+
if (metadata?.invisible)
|
|
254
|
+
baseTraits.push(traits.Invisible);
|
|
255
|
+
entities.push(world.spawn(...baseTraits, traits.ReferenceFrame));
|
|
256
|
+
const { scale, animationName } = geometryType.value;
|
|
257
|
+
let i = 1;
|
|
258
|
+
for (const asset of geometryType.value.assets) {
|
|
259
|
+
const subEntityTraits = [
|
|
260
|
+
traits.Name(`${referenceFrame} model ${i++}`),
|
|
261
|
+
traits.Parent(referenceFrame),
|
|
262
|
+
api,
|
|
263
|
+
];
|
|
264
|
+
if (scale)
|
|
265
|
+
subEntityTraits.push(traits.Scale(scale));
|
|
266
|
+
if (asset.content.case === 'url') {
|
|
267
|
+
subEntityTraits.push(traits.GLTF({
|
|
268
|
+
source: { url: asset.content.value },
|
|
269
|
+
animationName: animationName ?? DEFAULT_ANIMATION_NAME,
|
|
270
|
+
}));
|
|
271
|
+
}
|
|
272
|
+
else if (asset.content.value) {
|
|
273
|
+
subEntityTraits.push(traits.GLTF({
|
|
274
|
+
source: { glb: asset.content.value },
|
|
275
|
+
animationName: animationName ?? DEFAULT_ANIMATION_NAME,
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
entities.push(world.spawn(...subEntityTraits));
|
|
279
|
+
}
|
|
280
|
+
return entities;
|
|
281
|
+
};
|
|
282
|
+
const parsePointCloud = (world, entity, pointCloud, metadata) => {
|
|
283
|
+
parsePcdInWorker(new Uint8Array(pointCloud)).then((pointcloud) => {
|
|
284
|
+
if (!world.has(entity)) {
|
|
285
|
+
console.error('Entity was destroyed before pointcloud could be added');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const { colors, colorFormat } = metadata;
|
|
289
|
+
const numPoints = pointcloud.positions.length / STRIDE.POSITIONS;
|
|
290
|
+
if (colors && isSingleColor(colors))
|
|
291
|
+
entity.add(traits.Color(asRGB(colors, rgb)));
|
|
292
|
+
let vertexColors = pointcloud.colors;
|
|
293
|
+
if (colors && colors.length > 0)
|
|
294
|
+
vertexColors = parseColors(colors, numPoints);
|
|
295
|
+
const geometry = createBufferGeometry(pointcloud.positions, {
|
|
296
|
+
colors: vertexColors ?? undefined,
|
|
297
|
+
colorFormat,
|
|
298
|
+
});
|
|
299
|
+
entity.add(traits.BufferGeometry(geometry));
|
|
300
|
+
entity.add(traits.Points);
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
const updateColors = (entity, metadata) => {
|
|
304
|
+
const buffer = entity.get(traits.BufferGeometry);
|
|
305
|
+
if (!buffer) {
|
|
306
|
+
if (metadata.colors)
|
|
307
|
+
addColorTraits(entity, metadata.colors);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const position = buffer.getAttribute('position');
|
|
311
|
+
const count = position?.count ?? 0;
|
|
312
|
+
const array = position?.array;
|
|
313
|
+
updateBufferGeometry(buffer, array, {
|
|
314
|
+
colors: parseColors(metadata.colors, count),
|
|
315
|
+
colorFormat: metadata.colorFormat,
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
const parseColors = (from, count) => {
|
|
319
|
+
const colors = from ?? new Uint8Array([255, 0, 0]);
|
|
320
|
+
if (isVertexColors(colors))
|
|
321
|
+
return colors;
|
|
322
|
+
const expanded = new Uint8Array(count * STRIDE.COLORS_RGB);
|
|
323
|
+
for (let i = 0; i < count; i++) {
|
|
324
|
+
for (let c = 0; c < STRIDE.COLORS_RGB; c++) {
|
|
325
|
+
expanded[i * STRIDE.COLORS_RGB + c] = colors[c];
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return expanded;
|
|
329
|
+
};
|
|
330
|
+
const updateShape = (entity, { physicalObject, metadata }) => {
|
|
331
|
+
const geometryType = physicalObject?.geometryType;
|
|
332
|
+
entity.set(traits.Opacity, asOpacity(metadata?.opacities, DEFAULT_OPACITY));
|
|
333
|
+
switch (geometryType?.case) {
|
|
334
|
+
case 'arrows': {
|
|
335
|
+
const poses = asFloat32Array(geometryType.value.poses, inMeters);
|
|
336
|
+
entity.set(traits.Positions, poses);
|
|
337
|
+
entity.set(traits.Instances, { count: poses.length / STRIDE.ARROWS });
|
|
338
|
+
setColorTraits(entity, metadata?.colors ?? DEFAULT_ARROWS_COLORS);
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case 'line': {
|
|
342
|
+
const positions = asFloat32Array(geometryType.value.positions, inMeters);
|
|
343
|
+
const center = physicalObject?.center;
|
|
344
|
+
if (center)
|
|
345
|
+
entity.set(traits.Center, center);
|
|
346
|
+
setColorTraits(entity, metadata?.colors ?? DEFAULT_LINE_COLORS);
|
|
347
|
+
const lineWidth = geometryType.value.lineWidth ?? DEFAULT_LINE_WIDTH;
|
|
348
|
+
entity.set(traits.LineWidth, lineWidth);
|
|
349
|
+
entity.set(traits.DotSize, geometryType.value.dotSize ?? lineWidth);
|
|
350
|
+
entity.set(traits.LinePositions, positions);
|
|
351
|
+
const dotColors = geometryType.value.dotColors;
|
|
352
|
+
entity.set(traits.DotColors, dotColors ?? DEFAULT_LINE_DOT_COLORS);
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
case 'points': {
|
|
356
|
+
const positions = asFloat32Array(geometryType.value.positions, inMeters);
|
|
357
|
+
const center = physicalObject?.center;
|
|
358
|
+
if (center)
|
|
359
|
+
entity.set(traits.Center, center);
|
|
360
|
+
setColorTraits(entity, metadata?.colors ?? DEFAULT_POINTS_COLORS);
|
|
361
|
+
entity.set(traits.PointSize, geometryType.value.pointSize ?? DEFAULT_POINT_SIZE);
|
|
362
|
+
const vertexColors = isVertexColors(metadata?.colors) ? metadata?.colors : undefined;
|
|
363
|
+
const pointsMetadata = {
|
|
364
|
+
colors: vertexColors,
|
|
365
|
+
colorFormat: metadata?.colorFormat ?? ColorFormat.UNSPECIFIED,
|
|
366
|
+
};
|
|
367
|
+
const buffer = entity.get(traits.BufferGeometry);
|
|
368
|
+
if (buffer) {
|
|
369
|
+
updateBufferGeometry(buffer, positions, pointsMetadata);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
entity.add(traits.BufferGeometry(createBufferGeometry(positions, pointsMetadata)));
|
|
373
|
+
entity.add(traits.Points);
|
|
374
|
+
}
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
case 'nurbs': {
|
|
378
|
+
const { degree = DEFAULT_NURBS_DEGREE, knots: knotsBuffer, weights: weightsBuffer, controlPoints: controlPointsBuffer, } = geometryType.value;
|
|
379
|
+
const knots = [...asFloat32Array(knotsBuffer)];
|
|
380
|
+
const weights = weightsBuffer ? [...asFloat32Array(weightsBuffer)] : [];
|
|
381
|
+
const controlPointsArray = [...asFloat32Array(controlPointsBuffer)];
|
|
382
|
+
const numControlPoints = controlPointsArray.length / STRIDE.NURBS_CONTROL_POINTS;
|
|
383
|
+
const controlPoints = Array.from({ length: numControlPoints });
|
|
384
|
+
for (let j = 0; j < numControlPoints; j += 1) {
|
|
385
|
+
const idx = j * STRIDE.NURBS_CONTROL_POINTS;
|
|
386
|
+
vec3
|
|
387
|
+
.set(controlPointsArray[idx], controlPointsArray[idx + 1], controlPointsArray[idx + 2])
|
|
388
|
+
.multiplyScalar(0.001);
|
|
389
|
+
controlPoints[j] = new Vector4(vec3.x, vec3.y, vec3.z, weights[j] ?? DEFAULT_NURBS_WEIGHT);
|
|
390
|
+
}
|
|
391
|
+
const curve = new NURBSCurve(degree, knots, controlPoints);
|
|
392
|
+
const numPoints = 600;
|
|
393
|
+
const points = new Float32Array(numPoints * 3);
|
|
394
|
+
for (let i = 0; i < numPoints; i += 1) {
|
|
395
|
+
const t = i / (numPoints - 1);
|
|
396
|
+
curve.getPointAt(t, vec3);
|
|
397
|
+
points[i * 3 + 0] = vec3.x;
|
|
398
|
+
points[i * 3 + 1] = vec3.y;
|
|
399
|
+
points[i * 3 + 2] = vec3.z;
|
|
400
|
+
}
|
|
401
|
+
const center = physicalObject?.center;
|
|
402
|
+
if (center)
|
|
403
|
+
entity.set(traits.Center, center);
|
|
404
|
+
setColorTraits(entity, metadata?.colors ?? DEFAULT_NURBS_COLORS);
|
|
405
|
+
entity.set(traits.LineWidth, geometryType.value.lineWidth ?? DEFAULT_LINE_WIDTH);
|
|
406
|
+
entity.set(traits.LinePositions, points);
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const addColorTraits = (entity, colors) => {
|
|
412
|
+
if (isVertexColors(colors)) {
|
|
413
|
+
entity.add(traits.Colors(colors));
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
entity.add(traits.Color(asRGB(colors, rgb)));
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
const setColorTraits = (entity, colors) => {
|
|
420
|
+
if (isVertexColors(colors)) {
|
|
421
|
+
entity.set(traits.Colors, colors);
|
|
422
|
+
entity.remove(traits.Color);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
entity.set(traits.Color, asRGB(colors, rgb));
|
|
426
|
+
entity.remove(traits.Colors);
|
|
427
|
+
}
|
|
428
|
+
};
|
package/dist/ecs/traits.d.ts
CHANGED
|
@@ -80,8 +80,13 @@ export declare const Material: import("koota").Trait<{
|
|
|
80
80
|
}>;
|
|
81
81
|
export declare const DepthTest: import("koota").Trait<() => boolean>;
|
|
82
82
|
export declare const Arrow: import("koota").Trait<() => boolean>;
|
|
83
|
-
export declare const Positions: import("koota").Trait<() => Float32Array<
|
|
84
|
-
|
|
83
|
+
export declare const Positions: import("koota").Trait<() => Float32Array<ArrayBufferLike>>;
|
|
84
|
+
/** Per-vertex RGB colors packed as [r, g, b, ...], stride of 3, values 0-255. */
|
|
85
|
+
export declare const Colors: import("koota").Trait<() => Uint8Array<ArrayBufferLike>>;
|
|
86
|
+
/**
|
|
87
|
+
* Per-vertex opacity values packed as uint8 (0-255).
|
|
88
|
+
*/
|
|
89
|
+
export declare const Opacities: import("koota").Trait<() => Uint8Array<ArrayBuffer>>;
|
|
85
90
|
export declare const Instances: import("koota").Trait<{
|
|
86
91
|
count: number;
|
|
87
92
|
}>;
|
|
@@ -113,23 +118,14 @@ export declare const Capsule: import("koota").Trait<{
|
|
|
113
118
|
export declare const Sphere: import("koota").Trait<{
|
|
114
119
|
r: number;
|
|
115
120
|
}>;
|
|
116
|
-
export declare const PointColor: import("koota").Trait<{
|
|
117
|
-
r: number;
|
|
118
|
-
g: number;
|
|
119
|
-
b: number;
|
|
120
|
-
}>;
|
|
121
|
-
/** format [x, y, z, ...] */
|
|
122
|
-
export declare const LinePositions: import("koota").Trait<() => Float32Array<ArrayBuffer>>;
|
|
123
121
|
export declare const BufferGeometry: import("koota").Trait<() => ThreeBufferGeometry<import("three").NormalBufferAttributes, import("three").BufferGeometryEventMap>>;
|
|
124
|
-
/** format [r, g, b, ...] */
|
|
125
|
-
export declare const VertexColors: import("koota").Trait<() => Float32Array<ArrayBuffer>>;
|
|
126
122
|
export declare const GLTF: import("koota").Trait<() => {
|
|
127
123
|
source: {
|
|
128
124
|
url: string;
|
|
129
125
|
} | {
|
|
130
126
|
gltf: ThreeGltf;
|
|
131
127
|
} | {
|
|
132
|
-
glb: Uint8Array
|
|
128
|
+
glb: Uint8Array;
|
|
133
129
|
};
|
|
134
130
|
animationName: string;
|
|
135
131
|
}>;
|
|
@@ -141,6 +137,7 @@ export declare const Scale: import("koota").Trait<{
|
|
|
141
137
|
export declare const FramesAPI: import("koota").Trait<() => boolean>;
|
|
142
138
|
export declare const GeometriesAPI: import("koota").Trait<() => boolean>;
|
|
143
139
|
export declare const DrawAPI: import("koota").Trait<() => boolean>;
|
|
140
|
+
export declare const DrawServiceAPI: import("koota").Trait<() => boolean>;
|
|
144
141
|
export declare const WorldStateStoreAPI: import("koota").Trait<() => boolean>;
|
|
145
142
|
export declare const SnapshotAPI: import("koota").Trait<() => boolean>;
|
|
146
143
|
/**
|
|
@@ -148,15 +145,36 @@ export declare const SnapshotAPI: import("koota").Trait<() => boolean>;
|
|
|
148
145
|
*/
|
|
149
146
|
export declare const DroppedFile: import("koota").Trait<() => boolean>;
|
|
150
147
|
export declare const ShowAxesHelper: import("koota").Trait<() => boolean>;
|
|
148
|
+
/**
|
|
149
|
+
* Marker trait for entities that should be rendered in screen space (CSS pixels)
|
|
150
|
+
*/
|
|
151
|
+
export declare const ScreenSpace: import("koota").Trait<() => boolean>;
|
|
151
152
|
/**
|
|
152
153
|
* Point size, in mm
|
|
153
154
|
*/
|
|
154
155
|
export declare const PointSize: import("koota").Trait<() => number>;
|
|
155
156
|
/**
|
|
156
|
-
* Line
|
|
157
|
+
* Line positions, format [x, y, z, ...]
|
|
158
|
+
*/
|
|
159
|
+
export declare const LinePositions: import("koota").Trait<() => Float32Array<ArrayBufferLike>>;
|
|
160
|
+
/**
|
|
161
|
+
* Line width, in mm when in world units, or CSS pixels when in screen space
|
|
157
162
|
*/
|
|
158
163
|
export declare const LineWidth: import("koota").Trait<() => number>;
|
|
164
|
+
/**
|
|
165
|
+
* Dot colors for line vertices, format [r, g, b, a, ...]
|
|
166
|
+
*/
|
|
167
|
+
export declare const DotColors: import("koota").Trait<() => Uint8Array<ArrayBufferLike>>;
|
|
168
|
+
/**
|
|
169
|
+
* Dot size for line vertices, in mm when in world units, or CSS pixels when in screen space
|
|
170
|
+
*/
|
|
171
|
+
export declare const DotSize: import("koota").Trait<() => number>;
|
|
159
172
|
export declare const ReferenceFrame: import("koota").Trait<() => boolean>;
|
|
173
|
+
/**
|
|
174
|
+
* Interaction layers for entities
|
|
175
|
+
*/
|
|
176
|
+
export type InteractionLayerValue = 'selectTool';
|
|
177
|
+
export declare const SelectToolInteractionLayer: import("koota").Trait<() => boolean>;
|
|
160
178
|
/**
|
|
161
179
|
* This entity can be safetly removed from the scene by the user
|
|
162
180
|
*/
|