@viamrobotics/motion-tools 0.4.0 → 0.5.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/README.md +21 -11
- package/dist/WorldObject.d.ts +3 -3
- package/dist/WorldObject.js +1 -1
- package/dist/color.d.ts +16 -1
- package/dist/color.js +56 -1
- package/dist/components/App.svelte +4 -20
- package/dist/components/AxesHelper.svelte +69 -9
- package/dist/components/AxesHelper.svelte.d.ts +9 -2
- package/dist/components/Camera.svelte +5 -12
- package/dist/components/Details.svelte +46 -15
- package/dist/components/Focus.svelte +0 -2
- package/dist/components/Frame.svelte +4 -0
- package/dist/components/Geometry.svelte +32 -20
- package/dist/components/Geometry.svelte.d.ts +3 -2
- package/dist/components/Pointcloud.svelte +4 -4
- package/dist/components/Pointcloud.svelte.d.ts +1 -1
- package/dist/components/Scene.svelte +1 -1
- package/dist/components/SceneProviders.svelte +3 -2
- package/dist/components/Tree/Tree.svelte +11 -2
- package/dist/components/Tree/Tree.svelte.d.ts +2 -0
- package/dist/components/Tree/TreeContainer.svelte +21 -40
- package/dist/components/WorldObject.svelte +1 -0
- package/dist/components/dashboard/Button.svelte +47 -0
- package/dist/components/dashboard/Button.svelte.d.ts +12 -0
- package/dist/components/dashboard/Dashboard.svelte +77 -0
- package/dist/components/dashboard/Dashboard.svelte.d.ts +26 -0
- package/dist/components/xr/XR.svelte +20 -14
- package/dist/components/xr/XR.svelte.d.ts +17 -2
- package/dist/hooks/useDraggable.svelte.d.ts +10 -2
- package/dist/hooks/useDraggable.svelte.js +24 -13
- package/dist/hooks/useFrames.svelte.js +1 -1
- package/dist/hooks/useGeometries.svelte.js +1 -2
- package/dist/hooks/usePointclouds.svelte.js +3 -3
- package/dist/hooks/useSelection.svelte.d.ts +1 -1
- package/dist/hooks/useSelection.svelte.js +18 -2
- package/dist/hooks/useSettings.svelte.d.ts +9 -0
- package/dist/hooks/useSettings.svelte.js +25 -0
- package/dist/hooks/useShapes.svelte.js +5 -5
- package/dist/lib.d.ts +3 -1
- package/dist/lib.js +6 -1
- package/dist/loaders/pcd/index.d.ts +2 -4
- package/dist/loaders/pcd/index.js +7 -6
- package/dist/loaders/pcd/worker.d.ts +7 -1
- package/dist/loaders/pcd/worker.js +3 -5
- package/dist/test/createRandomPcdBinary.d.ts +1 -0
- package/dist/test/createRandomPcdBinary.js +31 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +1 -0
- package/dist/three/OrientationVector.d.ts +71 -0
- package/dist/three/OrientationVector.js +233 -0
- package/dist/transform.js +1 -1
- package/package.json +28 -25
- package/dist/three/AxesHelper.d.ts +0 -5
- package/dist/three/AxesHelper.js +0 -35
package/README.md
CHANGED
|
@@ -11,18 +11,28 @@ Open the machine config page (bottom right) and enter in connection details to v
|
|
|
11
11
|
|
|
12
12
|
## Todo
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
14
|
+
----- hard -----
|
|
15
|
+
|
|
16
|
+
- animated sequence of motion plan
|
|
17
|
+
- Give better fetching / connection state info
|
|
18
|
+
- configure frames in app
|
|
19
|
+
- embed in teleop
|
|
20
|
+
|
|
21
|
+
----- medium -----
|
|
22
|
+
|
|
23
|
+
- remote IP access when custom drawing, to draw on remote computers
|
|
24
|
+
- geometries need to be parented to parent
|
|
25
25
|
- color pallet for resource to color
|
|
26
|
+
- measurement tool
|
|
27
|
+
|
|
28
|
+
----- easy ------
|
|
29
|
+
|
|
30
|
+
- double click to set trackball center in object view
|
|
31
|
+
- Set default pointcloud color in settings
|
|
32
|
+
- points are not sized right in ortho cam view
|
|
33
|
+
- bounding boxes should include just the thing and not children
|
|
34
|
+
|
|
35
|
+
--- action items ----
|
|
26
36
|
|
|
27
37
|
## Env files
|
|
28
38
|
|
package/dist/WorldObject.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Geometry, Pose } from '@viamrobotics/sdk';
|
|
2
|
-
import { Box3, Object3D, Vector3 } from 'three';
|
|
2
|
+
import { BatchedMesh, Box3, Object3D, Vector3 } from 'three';
|
|
3
3
|
export type PointsGeometry = {
|
|
4
4
|
case: 'points';
|
|
5
|
-
value: Float32Array
|
|
5
|
+
value: Float32Array<ArrayBuffer>;
|
|
6
6
|
};
|
|
7
7
|
export type LinesGeometry = {
|
|
8
8
|
case: 'line';
|
|
@@ -18,7 +18,7 @@ export type Metadata = {
|
|
|
18
18
|
points?: Vector3[];
|
|
19
19
|
batched?: {
|
|
20
20
|
id: number;
|
|
21
|
-
|
|
21
|
+
object: BatchedMesh;
|
|
22
22
|
};
|
|
23
23
|
getBoundingBoxAt?: (box: Box3) => void;
|
|
24
24
|
};
|
package/dist/WorldObject.js
CHANGED
package/dist/color.d.ts
CHANGED
|
@@ -6,4 +6,19 @@ import { Color, type ColorRepresentation } from 'three';
|
|
|
6
6
|
* @returns A new THREE.Color instance with the darkened color.
|
|
7
7
|
*/
|
|
8
8
|
export declare const darkenColor: (value: ColorRepresentation, percent: number) => Color;
|
|
9
|
-
export declare const
|
|
9
|
+
export declare const colors: {
|
|
10
|
+
readonly selected: string;
|
|
11
|
+
readonly default: string;
|
|
12
|
+
readonly arm: {
|
|
13
|
+
readonly selected: string;
|
|
14
|
+
readonly default: string;
|
|
15
|
+
};
|
|
16
|
+
readonly camera: {
|
|
17
|
+
readonly selected: string;
|
|
18
|
+
readonly default: string;
|
|
19
|
+
};
|
|
20
|
+
readonly gripper: {
|
|
21
|
+
readonly selected: string;
|
|
22
|
+
readonly default: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
package/dist/color.js
CHANGED
|
@@ -1,4 +1,44 @@
|
|
|
1
1
|
import { Color } from 'three';
|
|
2
|
+
import twColors from 'tailwindcss/colors';
|
|
3
|
+
// Step 3: linear sRGB → sRGB
|
|
4
|
+
const linearToSrgb = (x) => {
|
|
5
|
+
return x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
|
|
6
|
+
};
|
|
7
|
+
// Step 4: sRGB → hex
|
|
8
|
+
const toHex = (x) => {
|
|
9
|
+
const hex = Math.round(x * 255)
|
|
10
|
+
.toString(16)
|
|
11
|
+
.padStart(2, '0');
|
|
12
|
+
return hex;
|
|
13
|
+
};
|
|
14
|
+
const oklchToHex = (raw) => {
|
|
15
|
+
const match = raw.match(/oklch\(\s*([\d.]+)%\s+([\d.]+)\s+([\d.]+)\s*\)/);
|
|
16
|
+
if (!match) {
|
|
17
|
+
return '#000000';
|
|
18
|
+
}
|
|
19
|
+
const l = parseFloat(match[1]) / 100;
|
|
20
|
+
const c = parseFloat(match[2]);
|
|
21
|
+
const h = parseFloat(match[3]);
|
|
22
|
+
// Convert h from degrees to radians
|
|
23
|
+
const hRad = (h * Math.PI) / 180;
|
|
24
|
+
// Step 1: OKLCH → OKLab
|
|
25
|
+
const aa = c * Math.cos(hRad);
|
|
26
|
+
const bb = c * Math.sin(hRad);
|
|
27
|
+
// Step 2: OKLab → linear sRGB
|
|
28
|
+
const l_ = l + 0.3963377774 * aa + 0.2158037573 * bb;
|
|
29
|
+
const m_ = l - 0.1055613458 * aa - 0.0638541728 * bb;
|
|
30
|
+
const s_ = l - 0.0894841775 * aa - 1.291485548 * bb;
|
|
31
|
+
const l_cubed = l_ ** 3;
|
|
32
|
+
const m_cubed = m_ ** 3;
|
|
33
|
+
const s_cubed = s_ ** 3;
|
|
34
|
+
const r_linear = +4.0767416621 * l_cubed - 3.3077115913 * m_cubed + 0.2309699292 * s_cubed;
|
|
35
|
+
const g_linear = -1.2684380046 * l_cubed + 2.6097574011 * m_cubed - 0.3413193965 * s_cubed;
|
|
36
|
+
const b_linear = -0.0041960863 * l_cubed - 0.7034186147 * m_cubed + 1.707614701 * s_cubed;
|
|
37
|
+
const r = Math.max(0, Math.min(1, linearToSrgb(r_linear)));
|
|
38
|
+
const g = Math.max(0, Math.min(1, linearToSrgb(g_linear)));
|
|
39
|
+
const b = Math.max(0, Math.min(1, linearToSrgb(b_linear)));
|
|
40
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
41
|
+
};
|
|
2
42
|
/**
|
|
3
43
|
* Darkens a THREE.Color by a given percentage while preserving hue.
|
|
4
44
|
* @param color The original THREE.Color instance.
|
|
@@ -12,4 +52,19 @@ export const darkenColor = (value, percent) => {
|
|
|
12
52
|
hsl.l = Math.max(0, hsl.l * (1 - percent / 100));
|
|
13
53
|
return color.setHSL(hsl.h, hsl.s, hsl.l);
|
|
14
54
|
};
|
|
15
|
-
export const
|
|
55
|
+
export const colors = {
|
|
56
|
+
selected: oklchToHex(twColors.red['900']),
|
|
57
|
+
default: oklchToHex(twColors.red['500']),
|
|
58
|
+
arm: {
|
|
59
|
+
selected: oklchToHex(twColors.amber['900']),
|
|
60
|
+
default: oklchToHex(twColors.amber['500']),
|
|
61
|
+
},
|
|
62
|
+
camera: {
|
|
63
|
+
selected: oklchToHex(twColors.blue['900']),
|
|
64
|
+
default: oklchToHex(twColors.blue['500']),
|
|
65
|
+
},
|
|
66
|
+
gripper: {
|
|
67
|
+
selected: oklchToHex(twColors.cyan['900']),
|
|
68
|
+
default: oklchToHex(twColors.cyan['500']),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
3
|
import { Canvas } from '@threlte/core'
|
|
4
|
-
import { XRButton } from '@threlte/xr'
|
|
5
4
|
import Scene from './Scene.svelte'
|
|
6
5
|
import TreeContainer from './Tree/TreeContainer.svelte'
|
|
7
6
|
import Details from './Details.svelte'
|
|
8
7
|
import SceneProviders from './SceneProviders.svelte'
|
|
9
8
|
import DomPortal from './DomPortal.svelte'
|
|
10
|
-
import { PersistedState } from 'runed'
|
|
11
9
|
import XR from './xr/XR.svelte'
|
|
12
10
|
import { World } from '@threlte/rapier'
|
|
13
11
|
import { createPartIDContext } from '../hooks/usePartID.svelte'
|
|
12
|
+
import Dashboard from './dashboard/Dashboard.svelte'
|
|
14
13
|
|
|
15
14
|
interface Props {
|
|
16
15
|
partID?: string
|
|
@@ -21,19 +20,9 @@
|
|
|
21
20
|
|
|
22
21
|
createPartIDContext(() => partID)
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let root: HTMLElement
|
|
23
|
+
let root = $state<HTMLElement>()
|
|
27
24
|
</script>
|
|
28
25
|
|
|
29
|
-
<svelte:window
|
|
30
|
-
onkeydown={(event) => {
|
|
31
|
-
if (event.ctrlKey && event.key.toLowerCase() === 'a') {
|
|
32
|
-
enableXR.current = !enableXR.current
|
|
33
|
-
}
|
|
34
|
-
}}
|
|
35
|
-
/>
|
|
36
|
-
|
|
37
26
|
<div
|
|
38
27
|
class="relative h-full w-full"
|
|
39
28
|
bind:this={root}
|
|
@@ -45,12 +34,11 @@
|
|
|
45
34
|
<Scene>
|
|
46
35
|
{@render appChildren?.()}
|
|
47
36
|
|
|
48
|
-
|
|
49
|
-
<XR />
|
|
50
|
-
{/if}
|
|
37
|
+
<XR />
|
|
51
38
|
</Scene>
|
|
52
39
|
|
|
53
40
|
<DomPortal element={root}>
|
|
41
|
+
<Dashboard />
|
|
54
42
|
<Details />
|
|
55
43
|
</DomPortal>
|
|
56
44
|
|
|
@@ -64,7 +52,3 @@
|
|
|
64
52
|
</World>
|
|
65
53
|
</Canvas>
|
|
66
54
|
</div>
|
|
67
|
-
|
|
68
|
-
{#if enableXR.current}
|
|
69
|
-
<XRButton mode="immersive-ar" />
|
|
70
|
-
{/if}
|
|
@@ -1,17 +1,77 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { Color } from 'three'
|
|
4
|
+
import { Line2 } from 'three/examples/jsm/lines/Line2.js'
|
|
5
|
+
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js'
|
|
6
|
+
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
|
|
7
|
+
|
|
8
|
+
interface Props extends ThrelteProps<Line2> {
|
|
9
|
+
length?: number
|
|
10
|
+
width?: number
|
|
11
|
+
axesColors?: [x: string, y: string, z: string]
|
|
12
|
+
depthTest?: boolean
|
|
8
13
|
}
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
const {
|
|
16
|
+
length = 1,
|
|
17
|
+
width = 0.1,
|
|
18
|
+
axesColors = ['red', 'green', 'blue'],
|
|
19
|
+
depthTest = true,
|
|
20
|
+
...rest
|
|
21
|
+
}: Props = $props()
|
|
22
|
+
|
|
23
|
+
const TOTAL_VERTICES = 9
|
|
24
|
+
const VERTEX_COMPONENTS = 3
|
|
25
|
+
|
|
26
|
+
const line = new Line2()
|
|
27
|
+
const material = new LineMaterial()
|
|
28
|
+
const geometry = new LineGeometry()
|
|
29
|
+
const color = new Color()
|
|
30
|
+
const colors = new Float32Array(TOTAL_VERTICES * VERTEX_COMPONENTS)
|
|
31
|
+
const positions = new Float32Array(TOTAL_VERTICES * VERTEX_COMPONENTS)
|
|
32
|
+
|
|
33
|
+
// Assign colors per vertex
|
|
34
|
+
$effect.pre(() => {
|
|
35
|
+
for (let i = 0, l = axesColors.length; i < l; i += 1) {
|
|
36
|
+
const axis = axesColors[i]
|
|
37
|
+
|
|
38
|
+
color.set(axis)
|
|
39
|
+
|
|
40
|
+
const axisBufferStart = i * TOTAL_VERTICES
|
|
41
|
+
const axisBufferEnd = axisBufferStart + TOTAL_VERTICES
|
|
42
|
+
|
|
43
|
+
for (let j = axisBufferStart; j < axisBufferEnd; j += VERTEX_COMPONENTS) {
|
|
44
|
+
colors[j + 0] = color.r
|
|
45
|
+
colors[j + 1] = color.g
|
|
46
|
+
colors[j + 2] = color.b
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
geometry.setColors(colors)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const X_AXIS_X_COMPONENT_INDEX = 3
|
|
54
|
+
const Y_AXIS_Y_COMPONENT_INDEX = 13
|
|
55
|
+
const Z_AXIS_Z_COMPONENT_INDEX = 23
|
|
56
|
+
|
|
57
|
+
$effect.pre(() => {
|
|
58
|
+
positions[X_AXIS_X_COMPONENT_INDEX] = length
|
|
59
|
+
positions[Y_AXIS_Y_COMPONENT_INDEX] = length
|
|
60
|
+
positions[Z_AXIS_Z_COMPONENT_INDEX] = length
|
|
61
|
+
geometry.setPositions(positions)
|
|
62
|
+
})
|
|
11
63
|
</script>
|
|
12
64
|
|
|
13
65
|
<T
|
|
14
|
-
is={
|
|
15
|
-
raycast={meshBounds}
|
|
66
|
+
is={line}
|
|
16
67
|
{...rest}
|
|
17
|
-
|
|
68
|
+
raycast={() => null}
|
|
69
|
+
>
|
|
70
|
+
<T is={geometry} />
|
|
71
|
+
<T
|
|
72
|
+
is={material}
|
|
73
|
+
vertexColors
|
|
74
|
+
linewidth={width}
|
|
75
|
+
{depthTest}
|
|
76
|
+
/>
|
|
77
|
+
</T>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { type Props as ThrelteProps } from '@threlte/core';
|
|
2
|
+
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
|
|
3
|
+
interface Props extends ThrelteProps<Line2> {
|
|
4
|
+
length?: number;
|
|
5
|
+
width?: number;
|
|
6
|
+
axesColors?: [x: string, y: string, z: string];
|
|
7
|
+
depthTest?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const AxesHelper: import("svelte").Component<Props, {}, "">;
|
|
3
10
|
type AxesHelper = ReturnType<typeof AxesHelper>;
|
|
4
11
|
export default AxesHelper;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { PersistedState } from 'runed'
|
|
3
2
|
import { T } from '@threlte/core'
|
|
4
3
|
import { PerspectiveCamera, OrthographicCamera } from 'three'
|
|
4
|
+
import { useSettings } from '../hooks/useSettings.svelte'
|
|
5
5
|
|
|
6
6
|
let { children, ...rest } = $props()
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const settings = useSettings()
|
|
9
|
+
const mode = $derived(settings.current.cameraMode)
|
|
9
10
|
|
|
10
11
|
const perspective = new PerspectiveCamera()
|
|
11
12
|
perspective.near = 0.01
|
|
@@ -18,15 +19,7 @@
|
|
|
18
19
|
orthographic.zoom = 200
|
|
19
20
|
</script>
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
onkeydown={({ key }) => {
|
|
23
|
-
if (key.toLowerCase() === 'c') {
|
|
24
|
-
mode.current = mode.current === 'perspective' ? 'orthographic' : 'perspective'
|
|
25
|
-
}
|
|
26
|
-
}}
|
|
27
|
-
/>
|
|
28
|
-
|
|
29
|
-
{#if mode.current === 'perspective'}
|
|
22
|
+
{#if mode === 'perspective'}
|
|
30
23
|
<T
|
|
31
24
|
is={perspective}
|
|
32
25
|
makeDefault
|
|
@@ -34,7 +27,7 @@
|
|
|
34
27
|
>
|
|
35
28
|
{@render children?.()}
|
|
36
29
|
</T>
|
|
37
|
-
{:else if mode
|
|
30
|
+
{:else if mode === 'orthographic'}
|
|
38
31
|
<T
|
|
39
32
|
is={orthographic}
|
|
40
33
|
makeDefault
|
|
@@ -1,22 +1,50 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { Quaternion, Vector3 } from 'three'
|
|
3
3
|
import { Check, Copy } from 'lucide-svelte'
|
|
4
4
|
import { Button, Icon } from '@viamrobotics/prime-core'
|
|
5
|
+
import {
|
|
6
|
+
useSelectedObject,
|
|
7
|
+
useFocusedObject,
|
|
8
|
+
useFocused,
|
|
9
|
+
useFocusedObject3d,
|
|
10
|
+
useSelectedObject3d,
|
|
11
|
+
} from '../hooks/useSelection.svelte'
|
|
12
|
+
import { useDraggable } from '../hooks/useDraggable.svelte'
|
|
13
|
+
import { OrientationVector } from '../three/OrientationVector'
|
|
5
14
|
|
|
6
15
|
const focused = useFocused()
|
|
7
|
-
const selectedObject = useSelectedObject()
|
|
8
16
|
const focusedObject = useFocusedObject()
|
|
17
|
+
const focusedObject3d = useFocusedObject3d()
|
|
18
|
+
|
|
19
|
+
const selectedObject = useSelectedObject()
|
|
20
|
+
const selectedObject3d = useSelectedObject3d()
|
|
21
|
+
|
|
9
22
|
const object = $derived(focusedObject.current ?? selectedObject.current)
|
|
23
|
+
const object3d = $derived(focusedObject3d.current ?? selectedObject3d.current)
|
|
24
|
+
|
|
25
|
+
const worldPosition = $derived(object3d?.getWorldPosition(new Vector3()))
|
|
26
|
+
const worldQuaternion = $derived(object3d?.getWorldQuaternion(new Quaternion()))
|
|
27
|
+
const worldOrientation = $derived(
|
|
28
|
+
worldQuaternion ? new OrientationVector().setFromQuaternion(worldQuaternion) : undefined
|
|
29
|
+
)
|
|
10
30
|
|
|
11
31
|
let copied = $state(false)
|
|
32
|
+
|
|
33
|
+
const draggable = useDraggable('details')
|
|
12
34
|
</script>
|
|
13
35
|
|
|
14
36
|
{#if object}
|
|
15
|
-
{@const { geometry
|
|
16
|
-
<div
|
|
37
|
+
{@const { geometry } = object}
|
|
38
|
+
<div
|
|
39
|
+
class="border-medium bg-extralight absolute top-0 right-0 z-10 m-2 w-60 border p-2 text-xs"
|
|
40
|
+
style:transform="translate({draggable.current.x}px, {draggable.current.y}px)"
|
|
41
|
+
>
|
|
17
42
|
<div class="flex items-center justify-between gap-2 pb-2">
|
|
18
43
|
<div class="flex items-center gap-1">
|
|
19
|
-
<button
|
|
44
|
+
<button
|
|
45
|
+
onmousedown={draggable.onDragStart}
|
|
46
|
+
onmouseup={draggable.onDragEnd}
|
|
47
|
+
>
|
|
20
48
|
<Icon name="drag" />
|
|
21
49
|
</button>
|
|
22
50
|
{object.name}
|
|
@@ -44,43 +72,46 @@
|
|
|
44
72
|
</h3>
|
|
45
73
|
|
|
46
74
|
<div class="flex flex-col gap-2.5">
|
|
47
|
-
{#if
|
|
75
|
+
{#if worldPosition}
|
|
48
76
|
<div>
|
|
49
|
-
<strong class="font-semibold">position</strong>
|
|
77
|
+
<strong class="font-semibold">world position</strong>
|
|
78
|
+
|
|
50
79
|
<div class="flex gap-3">
|
|
51
80
|
<div>
|
|
52
81
|
<span class="text-subtle-2">x</span>
|
|
53
|
-
{
|
|
82
|
+
{(worldPosition.x * 1000).toFixed(2)}
|
|
54
83
|
</div>
|
|
55
84
|
<div>
|
|
56
85
|
<span class="text-subtle-2">y</span>
|
|
57
|
-
{
|
|
86
|
+
{(worldPosition.y * 1000).toFixed(2)}
|
|
58
87
|
</div>
|
|
59
88
|
<div>
|
|
60
89
|
<span class="text-subtle-2">z</span>
|
|
61
|
-
{
|
|
90
|
+
{(worldPosition.z * 1000).toFixed(2)}
|
|
62
91
|
</div>
|
|
63
92
|
</div>
|
|
64
93
|
</div>
|
|
94
|
+
{/if}
|
|
65
95
|
|
|
96
|
+
{#if worldOrientation}
|
|
66
97
|
<div>
|
|
67
|
-
<strong class="font-semibold">orientation</strong>
|
|
98
|
+
<strong class="font-semibold">world orientation</strong>
|
|
68
99
|
<div class="flex gap-3">
|
|
69
100
|
<div>
|
|
70
101
|
<span class="text-subtle-2">x</span>
|
|
71
|
-
{
|
|
102
|
+
{worldOrientation.x.toFixed(2)}
|
|
72
103
|
</div>
|
|
73
104
|
<div>
|
|
74
105
|
<span class="text-subtle-2">y</span>
|
|
75
|
-
{
|
|
106
|
+
{worldOrientation.y.toFixed(2)}
|
|
76
107
|
</div>
|
|
77
108
|
<div>
|
|
78
109
|
<span class="text-subtle-2">z</span>
|
|
79
|
-
{
|
|
110
|
+
{worldOrientation.z.toFixed(2)}
|
|
80
111
|
</div>
|
|
81
112
|
<div>
|
|
82
113
|
<span class="text-subtle-2">th</span>
|
|
83
|
-
{
|
|
114
|
+
{worldOrientation.th.toFixed(2)}
|
|
84
115
|
</div>
|
|
85
116
|
</div>
|
|
86
117
|
</div>
|
|
@@ -14,13 +14,11 @@
|
|
|
14
14
|
const vec = new Vector3()
|
|
15
15
|
|
|
16
16
|
let center = $state.raw<[number, number, number]>([0, 0, 0])
|
|
17
|
-
// let size = $state.raw<[number, number, number]>([0, 0, 0])
|
|
18
17
|
|
|
19
18
|
$effect(() => {
|
|
20
19
|
if (object3d) {
|
|
21
20
|
box.setFromObject(object3d)
|
|
22
21
|
center = box.getCenter(vec).toArray()
|
|
23
|
-
// size = box.getSize(vec).toArray()
|
|
24
22
|
}
|
|
25
23
|
})
|
|
26
24
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import type { WorldObject } from '../WorldObject'
|
|
5
5
|
import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
|
|
6
6
|
import Geometry from './Geometry.svelte'
|
|
7
|
+
import { useSelected } from '../hooks/useSelection.svelte'
|
|
8
|
+
import { colors } from '../color'
|
|
7
9
|
|
|
8
10
|
interface Props {
|
|
9
11
|
uuid: string
|
|
@@ -16,11 +18,13 @@
|
|
|
16
18
|
|
|
17
19
|
let { uuid, ...rest }: Props = $props()
|
|
18
20
|
|
|
21
|
+
const selected = useSelected()
|
|
19
22
|
const events = useObjectEvents(() => uuid)
|
|
20
23
|
</script>
|
|
21
24
|
|
|
22
25
|
<Geometry
|
|
23
26
|
{uuid}
|
|
27
|
+
color={selected.current === uuid ? colors.selected : undefined}
|
|
24
28
|
{...events}
|
|
25
29
|
{...rest}
|
|
26
30
|
/>
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { T } from '@threlte/core'
|
|
2
|
+
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
3
3
|
import { type Snippet } from 'svelte'
|
|
4
4
|
import { meshBounds, MeshLineGeometry, MeshLineMaterial } from '@threlte/extras'
|
|
5
5
|
import { BufferGeometry, DoubleSide, FrontSide, Mesh, Object3D } from 'three'
|
|
6
6
|
import { CapsuleGeometry } from '../three/CapsuleGeometry'
|
|
7
7
|
import { poseToObject3d } from '../transform'
|
|
8
|
-
import { darkenColor } from '../color'
|
|
8
|
+
import { colors, darkenColor } from '../color'
|
|
9
9
|
import AxesHelper from './AxesHelper.svelte'
|
|
10
10
|
import type { WorldObject } from '../WorldObject'
|
|
11
11
|
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js'
|
|
12
12
|
|
|
13
13
|
const plyLoader = new PLYLoader()
|
|
14
14
|
|
|
15
|
-
interface Props {
|
|
15
|
+
interface Props extends ThrelteProps<Object3D> {
|
|
16
16
|
uuid: string
|
|
17
17
|
name: string
|
|
18
18
|
geometry?: WorldObject['geometry']
|
|
19
19
|
pose: WorldObject['pose']
|
|
20
20
|
metadata: WorldObject['metadata']
|
|
21
21
|
children?: Snippet<[{ ref: Object3D }]>
|
|
22
|
-
|
|
22
|
+
color?: string
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
let {
|
|
25
|
+
let {
|
|
26
|
+
uuid,
|
|
27
|
+
name,
|
|
28
|
+
geometry,
|
|
29
|
+
metadata,
|
|
30
|
+
pose,
|
|
31
|
+
color: overrideColor,
|
|
32
|
+
children,
|
|
33
|
+
...rest
|
|
34
|
+
}: Props = $props()
|
|
26
35
|
|
|
27
36
|
const type = $derived(geometry?.case)
|
|
28
37
|
const mesh = $derived.by(() => {
|
|
@@ -40,6 +49,12 @@
|
|
|
40
49
|
})
|
|
41
50
|
|
|
42
51
|
let geo = $state<BufferGeometry>()
|
|
52
|
+
|
|
53
|
+
const oncreate = (ref: BufferGeometry) => {
|
|
54
|
+
geo = ref
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const color = $derived(overrideColor ?? metadata.color ?? colors.default)
|
|
43
58
|
</script>
|
|
44
59
|
|
|
45
60
|
<T
|
|
@@ -50,49 +65,46 @@
|
|
|
50
65
|
>
|
|
51
66
|
{#if geometry?.case === 'mesh'}
|
|
52
67
|
{@const meshGeometry = plyLoader.parse(atob(geometry.value.mesh as unknown as string))}
|
|
53
|
-
<T
|
|
68
|
+
<T
|
|
69
|
+
is={meshGeometry}
|
|
70
|
+
{oncreate}
|
|
71
|
+
/>
|
|
54
72
|
{:else if geometry?.case === 'line' && metadata.points}
|
|
55
73
|
<MeshLineGeometry points={metadata.points} />
|
|
56
74
|
{:else if geometry?.case === 'box'}
|
|
57
75
|
{@const dimsMm = geometry.value.dimsMm ?? { x: 0, y: 0, z: 0 }}
|
|
58
76
|
<T.BoxGeometry
|
|
59
77
|
args={[dimsMm.x * 0.001, dimsMm.y * 0.001, dimsMm.z * 0.001]}
|
|
60
|
-
oncreate
|
|
61
|
-
geo = ref
|
|
62
|
-
}}
|
|
78
|
+
{oncreate}
|
|
63
79
|
/>
|
|
64
80
|
{:else if geometry?.case === 'sphere'}
|
|
65
81
|
{@const radiusMm = geometry.value.radiusMm ?? 0}
|
|
66
82
|
<T.SphereGeometry
|
|
67
83
|
args={[radiusMm * 0.001]}
|
|
68
|
-
oncreate
|
|
69
|
-
geo = ref
|
|
70
|
-
}}
|
|
84
|
+
{oncreate}
|
|
71
85
|
/>
|
|
72
86
|
{:else if geometry?.case === 'capsule'}
|
|
73
87
|
{@const { lengthMm, radiusMm } = geometry.value}
|
|
74
88
|
<T
|
|
75
89
|
is={CapsuleGeometry}
|
|
76
90
|
args={[radiusMm * 0.001, lengthMm * 0.001]}
|
|
77
|
-
oncreate
|
|
78
|
-
geo = ref
|
|
79
|
-
}}
|
|
91
|
+
{oncreate}
|
|
80
92
|
/>
|
|
81
93
|
{:else}
|
|
82
94
|
<AxesHelper
|
|
83
|
-
width={
|
|
95
|
+
width={3}
|
|
84
96
|
length={0.1}
|
|
85
97
|
/>
|
|
86
98
|
{/if}
|
|
87
99
|
|
|
88
100
|
{#if geometry?.case === 'line'}
|
|
89
101
|
<MeshLineMaterial
|
|
90
|
-
|
|
102
|
+
{color}
|
|
91
103
|
width={0.005}
|
|
92
104
|
/>
|
|
93
105
|
{:else if geometry}
|
|
94
106
|
<T.MeshToonMaterial
|
|
95
|
-
|
|
107
|
+
{color}
|
|
96
108
|
side={geometry.case === 'mesh' ? DoubleSide : FrontSide}
|
|
97
109
|
transparent
|
|
98
110
|
opacity={0.7}
|
|
@@ -100,8 +112,8 @@
|
|
|
100
112
|
|
|
101
113
|
{#if geo}
|
|
102
114
|
<T.LineSegments raycast={() => null}>
|
|
103
|
-
<T.EdgesGeometry args={[geo,
|
|
104
|
-
<T.LineBasicMaterial color={darkenColor(
|
|
115
|
+
<T.EdgesGeometry args={[geo, 0]} />
|
|
116
|
+
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
105
117
|
</T.LineSegments>
|
|
106
118
|
{/if}
|
|
107
119
|
{/if}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { type Props as ThrelteProps } from '@threlte/core';
|
|
1
2
|
import { type Snippet } from 'svelte';
|
|
2
3
|
import { Object3D } from 'three';
|
|
3
4
|
import type { WorldObject } from '../WorldObject';
|
|
4
|
-
interface Props {
|
|
5
|
+
interface Props extends ThrelteProps<Object3D> {
|
|
5
6
|
uuid: string;
|
|
6
7
|
name: string;
|
|
7
8
|
geometry?: WorldObject['geometry'];
|
|
@@ -10,7 +11,7 @@ interface Props {
|
|
|
10
11
|
children?: Snippet<[{
|
|
11
12
|
ref: Object3D;
|
|
12
13
|
}]>;
|
|
13
|
-
|
|
14
|
+
color?: string;
|
|
14
15
|
}
|
|
15
16
|
declare const Geometry: import("svelte").Component<Props, {}, "">;
|
|
16
17
|
type Geometry = ReturnType<typeof Geometry>;
|