@viamrobotics/motion-tools 0.9.3 → 0.9.5
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/README.md +2 -1
- package/dist/WorldObject.d.ts +20 -1
- package/dist/WorldObject.js +5 -0
- package/dist/components/App.svelte +15 -1
- package/dist/components/App.svelte.d.ts +1 -0
- package/dist/components/AxesHelper.svelte +1 -0
- package/dist/components/CameraControls.svelte +9 -1
- package/dist/components/DotSprite.svelte +48 -33
- package/dist/components/DotSprite.svelte.d.ts +3 -2
- package/dist/components/Focus.svelte +36 -3
- package/dist/components/Geometry.svelte +5 -1
- package/dist/components/MeasureTool.svelte +38 -55
- package/dist/components/Pointcloud.svelte +1 -3
- package/dist/components/PointerMissBox.svelte +7 -1
- package/dist/components/PointerMissBox.svelte.d.ts +2 -17
- package/dist/components/Scene.svelte +24 -15
- package/dist/components/SceneProviders.svelte +1 -2
- package/dist/components/Selected.svelte +1 -0
- package/dist/components/Tree/Settings.svelte +3 -0
- package/dist/components/Tree/TreeContainer.svelte +3 -1
- package/dist/components/Tree/buildTree.d.ts +4 -1
- package/dist/components/Tree/buildTree.js +23 -1
- package/dist/components/WorldObjects.svelte +15 -5
- package/dist/components/WorldState.svelte +28 -0
- package/dist/components/WorldState.svelte.d.ts +7 -0
- package/dist/components/portal/usePortalContext.svelte.js +2 -5
- package/dist/hooks/useMouseRaycaster.svelte.d.ts +17 -0
- package/dist/hooks/useMouseRaycaster.svelte.js +108 -0
- package/dist/hooks/useObjectEvents.svelte.js +1 -12
- package/dist/hooks/useSelection.svelte.js +12 -2
- package/dist/hooks/useSettings.svelte.d.ts +4 -2
- package/dist/hooks/useSettings.svelte.js +6 -2
- package/dist/hooks/useWorldState.svelte.d.ts +19 -0
- package/dist/hooks/useWorldState.svelte.js +97 -0
- package/package.json +42 -40
- package/dist/components/Labels.svelte +0 -0
- package/dist/components/Labels.svelte.d.ts +0 -26
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## motion-tools
|
|
2
2
|
|
|
3
|
-
`motion-tools`
|
|
3
|
+
`motion-tools` aims to provide a visualization interface for any spatial information using Viam's APIs. This typically means motion-related monitoring, testing, and debugging.
|
|
4
4
|
|
|
5
5
|
### Getting started
|
|
6
6
|
|
|
@@ -30,6 +30,7 @@ VITE_CONFIGS='
|
|
|
30
30
|
"signalingAddress": "https://app.viam.com:443"
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
'
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
### Executing drawing commands
|
package/dist/WorldObject.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Geometry, Pose } from '@viamrobotics/sdk';
|
|
1
|
+
import type { Geometry, Pose, TransformWithUUID } from '@viamrobotics/sdk';
|
|
2
2
|
import { BatchedMesh, Box3, Object3D, Vector3, type ColorRepresentation } from 'three';
|
|
3
3
|
export type PointsGeometry = {
|
|
4
4
|
case: 'points';
|
|
@@ -34,3 +34,22 @@ export declare class WorldObject<T extends Geometries = Geometries> {
|
|
|
34
34
|
metadata: Metadata;
|
|
35
35
|
constructor(name: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
|
|
36
36
|
}
|
|
37
|
+
export declare const fromTransform: (transform: TransformWithUUID) => WorldObject<{
|
|
38
|
+
case: undefined;
|
|
39
|
+
value?: undefined;
|
|
40
|
+
} | {
|
|
41
|
+
case: "sphere";
|
|
42
|
+
value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Sphere>;
|
|
43
|
+
} | {
|
|
44
|
+
case: "box";
|
|
45
|
+
value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").RectangularPrism>;
|
|
46
|
+
} | {
|
|
47
|
+
case: "capsule";
|
|
48
|
+
value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Capsule>;
|
|
49
|
+
} | {
|
|
50
|
+
case: "mesh";
|
|
51
|
+
value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Mesh>;
|
|
52
|
+
} | {
|
|
53
|
+
case: "pointcloud";
|
|
54
|
+
value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").PointCloud>;
|
|
55
|
+
}>;
|
package/dist/WorldObject.js
CHANGED
|
@@ -16,3 +16,8 @@ export class WorldObject {
|
|
|
16
16
|
this.metadata = metadata ?? {};
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
export const fromTransform = (transform) => {
|
|
20
|
+
const metadata = { ...transform.metadata?.fields };
|
|
21
|
+
const worldObject = new WorldObject(transform.referenceFrame, transform.poseInObserverFrame?.pose, transform.poseInObserverFrame?.referenceFrame, transform.physicalObject?.geometryType, metadata);
|
|
22
|
+
return worldObject;
|
|
23
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
3
|
import { Canvas } from '@threlte/core'
|
|
4
|
+
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
|
5
|
+
|
|
4
6
|
import Scene from './Scene.svelte'
|
|
5
7
|
import TreeContainer from './Tree/TreeContainer.svelte'
|
|
6
8
|
import Details from './Details.svelte'
|
|
@@ -10,19 +12,31 @@
|
|
|
10
12
|
import { createPartIDContext } from '../hooks/usePartID.svelte'
|
|
11
13
|
import Dashboard from './dashboard/Dashboard.svelte'
|
|
12
14
|
import { domPortal } from '../portal'
|
|
15
|
+
import { provideSettings } from '../hooks/useSettings.svelte'
|
|
13
16
|
|
|
14
17
|
interface Props {
|
|
15
18
|
partID?: string
|
|
19
|
+
enableKeybindings?: boolean
|
|
16
20
|
children?: Snippet
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
let { partID = '', children: appChildren }: Props = $props()
|
|
23
|
+
let { partID = '', enableKeybindings = true, children: appChildren }: Props = $props()
|
|
24
|
+
|
|
25
|
+
const settings = provideSettings()
|
|
26
|
+
|
|
27
|
+
$effect(() => {
|
|
28
|
+
settings.current.enableKeybindings = enableKeybindings
|
|
29
|
+
})
|
|
20
30
|
|
|
21
31
|
createPartIDContext(() => partID)
|
|
22
32
|
|
|
23
33
|
let root = $state.raw<HTMLElement>()
|
|
24
34
|
</script>
|
|
25
35
|
|
|
36
|
+
{#if settings.current.enableQueryDevtools}
|
|
37
|
+
<SvelteQueryDevtools initialIsOpen />
|
|
38
|
+
{/if}
|
|
39
|
+
|
|
26
40
|
<div
|
|
27
41
|
class="relative h-full w-full overflow-hidden"
|
|
28
42
|
bind:this={root}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { MathUtils } from 'three'
|
|
2
3
|
import { CameraControls, type CameraControlsRef, Gizmo } from '@threlte/extras'
|
|
3
4
|
import { useTransformControls } from '../hooks/useControls.svelte'
|
|
4
5
|
import KeyboardControls from './KeyboardControls.svelte'
|
|
5
6
|
import Portal from './portal/Portal.svelte'
|
|
6
7
|
import Button from './dashboard/Button.svelte'
|
|
7
8
|
import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
|
|
9
|
+
import { useSettings } from '../hooks/useSettings.svelte'
|
|
8
10
|
|
|
11
|
+
const settings = useSettings()
|
|
9
12
|
const drawAPI = useDrawAPI()
|
|
10
13
|
const transformControls = useTransformControls()
|
|
11
14
|
|
|
15
|
+
const enableKeybindings = $derived(settings.current.enableKeybindings)
|
|
16
|
+
|
|
12
17
|
let ref = $state.raw<CameraControlsRef>()
|
|
13
18
|
|
|
14
19
|
$effect(() => {
|
|
@@ -22,6 +27,7 @@
|
|
|
22
27
|
|
|
23
28
|
$effect(() => {
|
|
24
29
|
if (ref) {
|
|
30
|
+
;(window as unknown as { MathUtils: typeof MathUtils }).MathUtils = MathUtils
|
|
25
31
|
;(window as unknown as { cameraControls: CameraControlsRef }).cameraControls = ref
|
|
26
32
|
}
|
|
27
33
|
})
|
|
@@ -45,7 +51,9 @@
|
|
|
45
51
|
enabled={!transformControls.active}
|
|
46
52
|
>
|
|
47
53
|
{#snippet children({ ref }: { ref: CameraControlsRef })}
|
|
48
|
-
|
|
54
|
+
{#if enableKeybindings}
|
|
55
|
+
<KeyboardControls cameraControls={ref} />
|
|
56
|
+
{/if}
|
|
49
57
|
<Gizmo />
|
|
50
58
|
{/snippet}
|
|
51
59
|
</CameraControls>
|
|
@@ -1,44 +1,59 @@
|
|
|
1
|
-
<script
|
|
2
|
-
module
|
|
3
|
-
lang="ts"
|
|
4
|
-
>
|
|
1
|
+
<script lang="ts">
|
|
5
2
|
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
const size = 128
|
|
9
|
-
const canvas = new OffscreenCanvas(size, size)
|
|
10
|
-
const ctx = canvas.getContext('2d')
|
|
3
|
+
import type { ColorRepresentation, Vector3Tuple, Group } from 'three'
|
|
4
|
+
import { HTML } from '@threlte/extras'
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ctx.beginPath()
|
|
15
|
-
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2)
|
|
16
|
-
ctx.fillStyle = 'white'
|
|
17
|
-
ctx.fill()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const map = new CanvasTexture(canvas)
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<script lang="ts">
|
|
24
|
-
interface Props extends ThrelteProps<typeof Sprite> {
|
|
6
|
+
interface Props extends ThrelteProps<typeof Group> {
|
|
7
|
+
position: Vector3Tuple
|
|
25
8
|
color?: ColorRepresentation
|
|
26
9
|
opacity?: number
|
|
27
10
|
}
|
|
28
11
|
|
|
29
|
-
let { color, opacity = 1, ref = $bindable(), ...rest }: Props = $props()
|
|
12
|
+
let { position, color, opacity = 1, ref = $bindable(), ...rest }: Props = $props()
|
|
30
13
|
</script>
|
|
31
14
|
|
|
32
|
-
<T.
|
|
15
|
+
<T.Group
|
|
33
16
|
bind:ref
|
|
34
|
-
scale={0.05}
|
|
35
17
|
{...rest}
|
|
18
|
+
{position}
|
|
36
19
|
>
|
|
37
|
-
<T.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
20
|
+
<T.Mesh
|
|
21
|
+
bvh={{ enabled: false }}
|
|
22
|
+
raycast={() => null}
|
|
23
|
+
scale={0.01}
|
|
24
|
+
renderOrder={1}
|
|
25
|
+
>
|
|
26
|
+
<T.SphereGeometry />
|
|
27
|
+
<T.MeshBasicMaterial
|
|
28
|
+
color={color ?? 'black'}
|
|
29
|
+
transparent
|
|
30
|
+
depthTest={false}
|
|
31
|
+
{opacity}
|
|
32
|
+
/>
|
|
33
|
+
</T.Mesh>
|
|
34
|
+
|
|
35
|
+
<HTML
|
|
36
|
+
class="pointer-events-none mb-2 w-16 -translate-x-1/2 -translate-y-[calc(100%+10px)] border border-black bg-white px-1 py-0.5 text-xs text-wrap"
|
|
37
|
+
>
|
|
38
|
+
<div class="flex justify-between">
|
|
39
|
+
<span class="text-subtle-2">x</span>
|
|
40
|
+
<div>
|
|
41
|
+
{position[0].toFixed(2)}<span class="text-subtle-2">m</span>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="flex justify-between">
|
|
46
|
+
<span class="text-subtle-2">y</span>
|
|
47
|
+
<div>
|
|
48
|
+
{position[1].toFixed(2)}<span class="text-subtle-2">m</span>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="flex justify-between">
|
|
53
|
+
<span class="text-subtle-2">z</span>
|
|
54
|
+
<div>
|
|
55
|
+
{position[2].toFixed(2)}<span class="text-subtle-2">m</span>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</HTML>
|
|
59
|
+
</T.Group>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Props as ThrelteProps } from '@threlte/core';
|
|
2
|
-
import {
|
|
3
|
-
interface Props extends ThrelteProps<typeof
|
|
2
|
+
import type { ColorRepresentation, Vector3Tuple, Group } from 'three';
|
|
3
|
+
interface Props extends ThrelteProps<typeof Group> {
|
|
4
|
+
position: Vector3Tuple;
|
|
4
5
|
color?: ColorRepresentation;
|
|
5
6
|
opacity?: number;
|
|
6
7
|
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import { T } from '@threlte/core'
|
|
3
3
|
import { TrackballControls, Gizmo } from '@threlte/extras'
|
|
4
4
|
import { Box3, type Object3D, Vector3 } from 'three'
|
|
5
|
+
import { TrackballControls as ThreeTrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
|
|
5
6
|
import Camera from './Camera.svelte'
|
|
7
|
+
import Portal from './portal/Portal.svelte'
|
|
8
|
+
import Button from './dashboard/Button.svelte'
|
|
6
9
|
|
|
7
10
|
interface Props {
|
|
8
11
|
object3d: Object3D
|
|
@@ -16,6 +19,8 @@
|
|
|
16
19
|
let center = $state.raw<[number, number, number]>([0, 0, 0])
|
|
17
20
|
let size = $state.raw<[number, number, number]>([0, 0, 0])
|
|
18
21
|
|
|
22
|
+
let controls = $state.raw<ThreeTrackballControls>()
|
|
23
|
+
|
|
19
24
|
$effect.pre(() => {
|
|
20
25
|
box.setFromObject(object3d)
|
|
21
26
|
size = box.getSize(vec).toArray()
|
|
@@ -23,11 +28,39 @@
|
|
|
23
28
|
})
|
|
24
29
|
</script>
|
|
25
30
|
|
|
31
|
+
<Portal id="dashboard">
|
|
32
|
+
<fieldset>
|
|
33
|
+
<Button
|
|
34
|
+
active
|
|
35
|
+
icon="camera-outline"
|
|
36
|
+
description="Reset camera"
|
|
37
|
+
onclick={() => {
|
|
38
|
+
controls?.reset()
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
</fieldset>
|
|
42
|
+
</Portal>
|
|
43
|
+
|
|
26
44
|
<Camera position={[size[0] + 1, size[0] + 1, size[0] + 1]}>
|
|
27
|
-
<TrackballControls
|
|
45
|
+
<TrackballControls
|
|
46
|
+
bind:ref={controls}
|
|
47
|
+
target={center}
|
|
48
|
+
>
|
|
28
49
|
<Gizmo />
|
|
29
50
|
</TrackballControls>
|
|
30
51
|
</Camera>
|
|
31
52
|
|
|
32
|
-
<T
|
|
33
|
-
|
|
53
|
+
<T
|
|
54
|
+
is={object3d}
|
|
55
|
+
bvh={{
|
|
56
|
+
enabled: object3d.type === 'Points',
|
|
57
|
+
maxDepth: 40,
|
|
58
|
+
maxLeafTris: 20,
|
|
59
|
+
}}
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<T.BoxHelper
|
|
63
|
+
args={[object3d, 'red']}
|
|
64
|
+
bvh={{ enabled: false }}
|
|
65
|
+
raycast={() => null}
|
|
66
|
+
/>
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
{name}
|
|
63
63
|
{uuid}
|
|
64
64
|
{...rest}
|
|
65
|
+
bvh={{ enabled: false }}
|
|
65
66
|
>
|
|
66
67
|
{#if geometry?.case === 'mesh'}
|
|
67
68
|
{@const mesh = geometry.value.mesh as Uint8Array<ArrayBuffer>}
|
|
@@ -112,7 +113,10 @@
|
|
|
112
113
|
/>
|
|
113
114
|
|
|
114
115
|
{#if geo}
|
|
115
|
-
<T.LineSegments
|
|
116
|
+
<T.LineSegments
|
|
117
|
+
raycast={() => null}
|
|
118
|
+
bvh={{ enabled: false }}
|
|
119
|
+
>
|
|
116
120
|
<T.EdgesGeometry args={[geo, 0]} />
|
|
117
121
|
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
118
122
|
</T.LineSegments>
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte'
|
|
3
|
-
import {
|
|
4
|
-
import { T
|
|
5
|
-
import { HTML, MeshLineGeometry, MeshLineMaterial
|
|
3
|
+
import { Vector3, type Intersection } from 'three'
|
|
4
|
+
import { T } from '@threlte/core'
|
|
5
|
+
import { HTML, MeshLineGeometry, MeshLineMaterial } from '@threlte/extras'
|
|
6
6
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
7
7
|
import Button from './dashboard/Button.svelte'
|
|
8
8
|
import Portal from './portal/Portal.svelte'
|
|
9
9
|
import DotSprite from './DotSprite.svelte'
|
|
10
|
+
import { useMouseRaycaster } from '../hooks/useMouseRaycaster.svelte'
|
|
11
|
+
import { useFocused } from '../hooks/useSelection.svelte'
|
|
10
12
|
|
|
13
|
+
const focus = useFocused()
|
|
11
14
|
const settings = useSettings()
|
|
12
|
-
const { camera } = useThrelte()
|
|
13
|
-
const interactivity = useInteractivity()
|
|
14
|
-
const raycaster = new Raycaster()
|
|
15
15
|
|
|
16
16
|
const htmlPosition = new Vector3()
|
|
17
|
-
const pointerDown = new Vector2()
|
|
18
|
-
const pointerUp = new Vector2()
|
|
19
17
|
|
|
20
18
|
let step: 'idle' | 'p1' | 'p2' = 'idle'
|
|
21
19
|
|
|
22
|
-
let intersection
|
|
20
|
+
let intersection = $state.raw<Intersection>()
|
|
23
21
|
let p1 = $state.raw<Vector3>()
|
|
24
22
|
let p2 = $state.raw<Vector3>()
|
|
25
23
|
|
|
26
24
|
const enabled = $derived(settings.current.enableMeasure)
|
|
27
25
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
pointerUp.set(event.clientX, event.clientY)
|
|
26
|
+
const { onclick, onmove, raycaster } = useMouseRaycaster(() => ({
|
|
27
|
+
enabled,
|
|
28
|
+
}))
|
|
29
|
+
raycaster.firstHitOnly = true
|
|
30
|
+
raycaster.params.Points.threshold = 0.005
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
onmove((event) => {
|
|
33
|
+
intersection = event.intersections[0]
|
|
34
|
+
})
|
|
38
35
|
|
|
36
|
+
onclick(() => {
|
|
39
37
|
if (step === 'idle' && intersection) {
|
|
40
38
|
p1 = intersection.point.clone()
|
|
41
39
|
step = 'p1'
|
|
@@ -47,38 +45,18 @@
|
|
|
47
45
|
p2 = undefined
|
|
48
46
|
step = 'idle'
|
|
49
47
|
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const { start, stop } = useTask(
|
|
53
|
-
() => {
|
|
54
|
-
if (interactivity.hovered.size === 0) {
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
for (const [, event] of interactivity.hovered) {
|
|
59
|
-
raycaster.setFromCamera(interactivity.pointer.current, camera.current)
|
|
60
|
-
intersection = raycaster.intersectObject(event.object)[0]
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
{ autoStart: false }
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
$effect(() => {
|
|
67
|
-
if (!enabled) {
|
|
68
|
-
untrack(() => {
|
|
69
|
-
p1 = undefined
|
|
70
|
-
p2 = undefined
|
|
71
|
-
step = 'idle'
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
48
|
})
|
|
75
49
|
|
|
50
|
+
const clear = () => {
|
|
51
|
+
p1 = undefined
|
|
52
|
+
p2 = undefined
|
|
53
|
+
step = 'idle'
|
|
54
|
+
}
|
|
55
|
+
|
|
76
56
|
$effect(() => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
stop()
|
|
81
|
-
}
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
58
|
+
;(focus.current, enabled)
|
|
59
|
+
untrack(() => clear())
|
|
82
60
|
})
|
|
83
61
|
</script>
|
|
84
62
|
|
|
@@ -96,12 +74,11 @@
|
|
|
96
74
|
</fieldset>
|
|
97
75
|
</Portal>
|
|
98
76
|
|
|
99
|
-
<svelte:window
|
|
100
|
-
onpointerdown={enabled ? onpointerdown : undefined}
|
|
101
|
-
onpointerup={enabled ? onpointerup : undefined}
|
|
102
|
-
/>
|
|
103
|
-
|
|
104
77
|
{#if enabled}
|
|
78
|
+
{#if intersection}
|
|
79
|
+
<DotSprite position={intersection?.point.toArray()} />
|
|
80
|
+
{/if}
|
|
81
|
+
|
|
105
82
|
{#if p1}
|
|
106
83
|
<DotSprite position={p1.toArray()} />
|
|
107
84
|
{/if}
|
|
@@ -111,12 +88,18 @@
|
|
|
111
88
|
{/if}
|
|
112
89
|
|
|
113
90
|
{#if p1 && p2}
|
|
114
|
-
<T.Mesh
|
|
91
|
+
<T.Mesh
|
|
92
|
+
raycast={() => null}
|
|
93
|
+
bvh={{ enabled: false }}
|
|
94
|
+
renderOrder={1}
|
|
95
|
+
>
|
|
115
96
|
<MeshLineGeometry points={[p1, p2]} />
|
|
116
97
|
<MeshLineMaterial
|
|
117
|
-
width={
|
|
98
|
+
width={2.5}
|
|
118
99
|
depthTest={false}
|
|
119
100
|
color="black"
|
|
101
|
+
attenuate={false}
|
|
102
|
+
transparent
|
|
120
103
|
/>
|
|
121
104
|
</T.Mesh>
|
|
122
105
|
<HTML
|
|
@@ -124,7 +107,7 @@
|
|
|
124
107
|
position={htmlPosition.lerpVectors(p1, p2, 0.5).toArray()}
|
|
125
108
|
>
|
|
126
109
|
<div class="border border-black bg-white px-1 py-0.5 text-xs">
|
|
127
|
-
{p1.distanceTo(p2).toFixed(2)}m
|
|
110
|
+
{p1.distanceTo(p2).toFixed(2)}<span class="text-subtle-2">m</span>
|
|
128
111
|
</div>
|
|
129
112
|
</HTML>
|
|
130
113
|
{/if}
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
PointsMaterial,
|
|
7
7
|
OrthographicCamera,
|
|
8
8
|
} from 'three'
|
|
9
|
-
|
|
10
9
|
import { T, useTask, useThrelte } from '@threlte/core'
|
|
11
10
|
import type { WorldObject } from '../WorldObject'
|
|
12
11
|
import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
|
|
13
|
-
import { meshBounds } from '@threlte/extras'
|
|
14
12
|
import { poseToObject3d } from '../transform'
|
|
15
13
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
16
14
|
import type { Snippet } from 'svelte'
|
|
@@ -85,8 +83,8 @@
|
|
|
85
83
|
is={points}
|
|
86
84
|
name={object.name}
|
|
87
85
|
uuid={object.uuid}
|
|
88
|
-
raycast={meshBounds}
|
|
89
86
|
{...events}
|
|
87
|
+
bvh={{ maxDepth: 40, maxLeafTris: 20 }}
|
|
90
88
|
>
|
|
91
89
|
<T is={geometry} />
|
|
92
90
|
<T is={material} />
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { BackSide, Vector3 } from 'three'
|
|
2
|
+
import { BackSide, Mesh, Vector3 } from 'three'
|
|
3
3
|
import { T, useThrelte } from '@threlte/core'
|
|
4
4
|
import { MeshDiscardMaterial } from '@threlte/extras'
|
|
5
5
|
import { useSelected } from '../hooks/useSelection.svelte'
|
|
6
6
|
import { useTransformControls } from '../hooks/useControls.svelte'
|
|
7
|
+
import { useSettings } from '../hooks/useSettings.svelte'
|
|
7
8
|
|
|
8
9
|
const { camera } = useThrelte()
|
|
10
|
+
const settings = useSettings()
|
|
9
11
|
const selected = useSelected()
|
|
10
12
|
const transformControls = useTransformControls()
|
|
11
13
|
const cameraDown = new Vector3()
|
|
12
14
|
|
|
15
|
+
const enabled = $derived(!settings.current.enableMeasure)
|
|
16
|
+
|
|
13
17
|
const size = 1_000
|
|
14
18
|
</script>
|
|
15
19
|
|
|
16
20
|
<T.Mesh
|
|
21
|
+
raycast={enabled ? Mesh.prototype.raycast : () => null}
|
|
22
|
+
bvh={{ enabled: false }}
|
|
17
23
|
onpointerdown={() => {
|
|
18
24
|
cameraDown.copy(camera.current.position)
|
|
19
25
|
}}
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 PointerMissBox: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type PointerMissBox = InstanceType<typeof PointerMissBox>;
|
|
1
|
+
declare const PointerMissBox: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type PointerMissBox = ReturnType<typeof PointerMissBox>;
|
|
18
3
|
export default PointerMissBox;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Vector3 } from 'three'
|
|
3
3
|
import { T } from '@threlte/core'
|
|
4
|
-
import { Grid, interactivity, PerfMonitor } from '@threlte/extras'
|
|
4
|
+
import { Grid, interactivity, PerfMonitor, bvh } from '@threlte/extras'
|
|
5
5
|
import { PortalTarget } from './portal'
|
|
6
6
|
import WorldObjects from './WorldObjects.svelte'
|
|
7
7
|
import Selected from './Selected.svelte'
|
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
let { children }: Props = $props()
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const settings = useSettings()
|
|
28
|
+
const focusedObject3d = useFocusedObject3d()
|
|
29
|
+
const origin = useOrigin()
|
|
30
|
+
|
|
31
|
+
const { raycaster, enabled } = interactivity({
|
|
28
32
|
filter: (items) => {
|
|
29
33
|
const item = items.find((item) => {
|
|
30
34
|
return item.object.visible === undefined || item.object.visible === true
|
|
@@ -33,12 +37,14 @@
|
|
|
33
37
|
return item ? [item] : []
|
|
34
38
|
},
|
|
35
39
|
})
|
|
40
|
+
$effect.pre(() => {
|
|
41
|
+
enabled.set(!settings.current.enableMeasure)
|
|
42
|
+
})
|
|
43
|
+
raycaster.firstHitOnly = true
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
const focusedObject3d = useFocusedObject3d()
|
|
39
|
-
const origin = useOrigin()
|
|
45
|
+
bvh(() => ({ helper: false }))
|
|
40
46
|
|
|
41
|
-
const
|
|
47
|
+
const focusedObject = $derived(focusedObject3d.current)
|
|
42
48
|
|
|
43
49
|
const { isPresenting } = useXR()
|
|
44
50
|
</script>
|
|
@@ -52,8 +58,11 @@
|
|
|
52
58
|
rotation.x={$isPresenting ? -Math.PI / 2 : 0}
|
|
53
59
|
rotation.z={origin.rotation}
|
|
54
60
|
>
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
<PointerMissBox />
|
|
62
|
+
<MeasureTool />
|
|
63
|
+
|
|
64
|
+
{#if focusedObject}
|
|
65
|
+
<Focus object3d={focusedObject} />
|
|
57
66
|
{:else}
|
|
58
67
|
{#if !$isPresenting}
|
|
59
68
|
<Camera position={[3, 3, 3]}>
|
|
@@ -61,18 +70,13 @@
|
|
|
61
70
|
</Camera>
|
|
62
71
|
{/if}
|
|
63
72
|
|
|
64
|
-
<PortalTarget id="world" />
|
|
65
|
-
|
|
66
|
-
<MeasureTool />
|
|
67
73
|
<StaticGeometries />
|
|
68
|
-
|
|
69
|
-
<WorldObjects />
|
|
70
|
-
<PointerMissBox />
|
|
71
|
-
|
|
72
74
|
<Selected />
|
|
73
75
|
|
|
74
76
|
{#if !$isPresenting && settings.current.grid}
|
|
75
77
|
<Grid
|
|
78
|
+
raycast={() => null}
|
|
79
|
+
bvh={{ enabled: false }}
|
|
76
80
|
plane="xy"
|
|
77
81
|
sectionColor="#333"
|
|
78
82
|
infiniteGrid
|
|
@@ -84,6 +88,11 @@
|
|
|
84
88
|
{/if}
|
|
85
89
|
{/if}
|
|
86
90
|
|
|
91
|
+
<T.Group attach={focusedObject ? false : undefined}>
|
|
92
|
+
<PortalTarget id="world" />
|
|
93
|
+
<WorldObjects />
|
|
94
|
+
</T.Group>
|
|
95
|
+
|
|
87
96
|
{@render children?.()}
|
|
88
97
|
|
|
89
98
|
<T.DirectionalLight position={[3, 3, 3]} />
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
import { provideObjects } from '../hooks/useObjects.svelte'
|
|
14
14
|
import { provideMotionClient } from '../hooks/useMotionClient.svelte'
|
|
15
15
|
import { provideLogs } from '../hooks/useLogs.svelte'
|
|
16
|
-
import { provideSettings } from '../hooks/useSettings.svelte'
|
|
17
16
|
import { provideOrigin } from './xr/useOrigin.svelte'
|
|
18
17
|
|
|
19
18
|
interface Props {
|
|
@@ -24,7 +23,6 @@
|
|
|
24
23
|
|
|
25
24
|
const partID = usePartID()
|
|
26
25
|
|
|
27
|
-
provideSettings()
|
|
28
26
|
provideTransformControls()
|
|
29
27
|
provideVisibility()
|
|
30
28
|
provideMachineSettings()
|
|
@@ -39,6 +37,7 @@
|
|
|
39
37
|
providePointclouds(() => partID.current)
|
|
40
38
|
provideMotionClient(() => partID.current)
|
|
41
39
|
provideObjects()
|
|
40
|
+
|
|
42
41
|
const { focus } = provideSelection()
|
|
43
42
|
</script>
|
|
44
43
|
|