@viamrobotics/motion-tools 0.9.4 → 0.10.0
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/WorldObject.svelte.d.ts +55 -0
- package/dist/{WorldObject.js → WorldObject.svelte.js} +9 -2
- package/dist/components/AxesHelper.svelte +1 -0
- 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/Frame.svelte +1 -1
- package/dist/components/Frame.svelte.d.ts +1 -1
- package/dist/components/Geometry.svelte +6 -2
- package/dist/components/Geometry.svelte.d.ts +1 -1
- package/dist/components/Line.svelte +1 -1
- package/dist/components/Line.svelte.d.ts +1 -1
- package/dist/components/MeasureTool.svelte +38 -55
- package/dist/components/Pointcloud.svelte +2 -4
- package/dist/components/Pointcloud.svelte.d.ts +1 -1
- 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 -0
- package/dist/components/Selected.svelte +1 -0
- package/dist/components/Tree/TreeContainer.svelte +3 -1
- package/dist/components/Tree/buildTree.d.ts +5 -2
- package/dist/components/Tree/buildTree.js +23 -1
- package/dist/components/WorldObject.svelte +1 -1
- package/dist/components/WorldObject.svelte.d.ts +1 -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/hooks/useDrawAPI.svelte.d.ts +1 -1
- package/dist/hooks/useDrawAPI.svelte.js +16 -11
- package/dist/hooks/useFrames.svelte.d.ts +1 -1
- package/dist/hooks/useFrames.svelte.js +1 -1
- package/dist/hooks/useGeometries.svelte.d.ts +1 -1
- package/dist/hooks/useGeometries.svelte.js +1 -1
- 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/useObjects.svelte.d.ts +1 -1
- package/dist/hooks/usePersistentUUIDs.svelte.d.ts +1 -1
- package/dist/hooks/usePointclouds.svelte.d.ts +1 -1
- package/dist/hooks/usePointclouds.svelte.js +1 -1
- package/dist/hooks/useSelection.svelte.d.ts +1 -1
- package/dist/hooks/useSelection.svelte.js +12 -2
- package/dist/hooks/useStaticGeometries.svelte.d.ts +1 -1
- package/dist/hooks/useStaticGeometries.svelte.js +1 -1
- package/dist/hooks/useWorldState.svelte.d.ts +19 -0
- package/dist/hooks/useWorldState.svelte.js +97 -0
- package/dist/lib.d.ts +1 -1
- package/dist/lib.js +1 -1
- package/package.json +42 -40
- package/dist/WorldObject.d.ts +0 -36
- package/dist/components/Labels.svelte +0 -0
- package/dist/components/Labels.svelte.d.ts +0 -26
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Geometry, Pose, TransformWithUUID } from '@viamrobotics/sdk';
|
|
2
|
+
import { BatchedMesh, Box3, Object3D, Vector3, type ColorRepresentation } from 'three';
|
|
3
|
+
export type PointsGeometry = {
|
|
4
|
+
case: 'points';
|
|
5
|
+
value: Float32Array<ArrayBuffer>;
|
|
6
|
+
};
|
|
7
|
+
export type LinesGeometry = {
|
|
8
|
+
case: 'line';
|
|
9
|
+
value: Float32Array;
|
|
10
|
+
};
|
|
11
|
+
export type Geometries = Geometry['geometryType'] | PointsGeometry | LinesGeometry;
|
|
12
|
+
export type Metadata = {
|
|
13
|
+
colors?: Float32Array;
|
|
14
|
+
color?: ColorRepresentation;
|
|
15
|
+
gltf?: {
|
|
16
|
+
scene: Object3D;
|
|
17
|
+
};
|
|
18
|
+
points?: Vector3[];
|
|
19
|
+
pointSize?: number;
|
|
20
|
+
lineWidth?: number;
|
|
21
|
+
lineDotColor?: ColorRepresentation;
|
|
22
|
+
batched?: {
|
|
23
|
+
id: number;
|
|
24
|
+
object: BatchedMesh;
|
|
25
|
+
};
|
|
26
|
+
getBoundingBoxAt?: (box: Box3) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare class WorldObject<T extends Geometries = Geometries> {
|
|
29
|
+
uuid: string;
|
|
30
|
+
name: string;
|
|
31
|
+
referenceFrame: string;
|
|
32
|
+
pose: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
|
|
33
|
+
geometry?: T;
|
|
34
|
+
metadata: Metadata;
|
|
35
|
+
constructor(name: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
|
|
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
|
+
}>;
|
|
@@ -4,15 +4,22 @@ export class WorldObject {
|
|
|
4
4
|
uuid;
|
|
5
5
|
name;
|
|
6
6
|
referenceFrame;
|
|
7
|
-
pose;
|
|
7
|
+
pose = $state.raw(createPose());
|
|
8
8
|
geometry;
|
|
9
9
|
metadata;
|
|
10
10
|
constructor(name, pose, parent = 'world', geometry, metadata) {
|
|
11
11
|
this.uuid = MathUtils.generateUUID();
|
|
12
12
|
this.name = name;
|
|
13
13
|
this.referenceFrame = parent;
|
|
14
|
-
this.pose = pose ?? createPose();
|
|
15
14
|
this.geometry = geometry;
|
|
16
15
|
this.metadata = metadata ?? {};
|
|
16
|
+
if (pose) {
|
|
17
|
+
this.pose = pose;
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
}
|
|
21
|
+
export const fromTransform = (transform) => {
|
|
22
|
+
const metadata = { ...transform.metadata?.fields };
|
|
23
|
+
const worldObject = new WorldObject(transform.referenceFrame, transform.poseInObserverFrame?.pose, transform.poseInObserverFrame?.referenceFrame, transform.physicalObject?.geometryType, metadata);
|
|
24
|
+
return worldObject;
|
|
25
|
+
};
|
|
@@ -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
|
+
/>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<script lang="ts">
|
|
8
8
|
import type { Snippet } from 'svelte'
|
|
9
|
-
import type { WorldObject } from '../WorldObject'
|
|
9
|
+
import type { WorldObject } from '../WorldObject.svelte'
|
|
10
10
|
import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
|
|
11
11
|
import Geometry from './Geometry.svelte'
|
|
12
12
|
import { useSelected } from '../hooks/useSelection.svelte'
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { poseToObject3d } from '../transform'
|
|
8
8
|
import { colors, darkenColor } from '../color'
|
|
9
9
|
import AxesHelper from './AxesHelper.svelte'
|
|
10
|
-
import type { WorldObject } from '../WorldObject'
|
|
10
|
+
import type { WorldObject } from '../WorldObject.svelte'
|
|
11
11
|
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js'
|
|
12
12
|
|
|
13
13
|
const plyLoader = new PLYLoader()
|
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
import { type Props as ThrelteProps } from '@threlte/core';
|
|
2
2
|
import { type Snippet } from 'svelte';
|
|
3
3
|
import { Object3D } from 'three';
|
|
4
|
-
import type { WorldObject } from '../WorldObject';
|
|
4
|
+
import type { WorldObject } from '../WorldObject.svelte';
|
|
5
5
|
interface Props extends ThrelteProps<Object3D> {
|
|
6
6
|
uuid: string;
|
|
7
7
|
name: string;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { T } from '@threlte/core'
|
|
3
3
|
import { Instance, InstancedMesh } from '@threlte/extras'
|
|
4
4
|
import Frame from './Frame.svelte'
|
|
5
|
-
import type { WorldObject } from '../WorldObject'
|
|
5
|
+
import type { WorldObject } from '../WorldObject.svelte'
|
|
6
6
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
7
7
|
import type { Snippet } from 'svelte'
|
|
8
8
|
|
|
@@ -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
|
-
import type { WorldObject } from '../WorldObject'
|
|
10
|
+
import type { WorldObject } from '../WorldObject.svelte'
|
|
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]} />
|