Skip to content

Commit

Permalink
@prime/blocks: adapt navigation map components into generic maplibre …
Browse files Browse the repository at this point in the history
…tools (viamrobotics#543)
  • Loading branch information
micheal-parks authored Jul 24, 2024
1 parent 66a98b0 commit ea44009
Show file tree
Hide file tree
Showing 32 changed files with 1,701 additions and 618 deletions.
19 changes: 9 additions & 10 deletions packages/blocks/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@viamrobotics/prime-blocks",
"version": "0.0.30",
"version": "0.1.0",
"publishConfig": {
"access": "public"
},
Expand Down Expand Up @@ -33,17 +33,15 @@
"prime.css"
],
"peerDependencies": {
"@threlte/core": ">=7",
"@threlte/extras": ">=8",
"@threlte/core": ">=7 <8",
"@threlte/extras": ">=8 <9",
"@viamrobotics/prime-core": ">=0.0.48",
"@viamrobotics/three": ">=0.0.3",
"maplibre-gl": ">=4",
"svelte": ">=4 <5",
"tailwindcss": ">=3",
"three": ">=0.159"
},
"dependencies": {
"maplibre-gl": "^4.1.3"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.3",
Expand All @@ -52,9 +50,9 @@
"@testing-library/dom": "^9.3.3",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/svelte": "^4.1.0",
"@threlte/core": "^7.0.12",
"@threlte/extras": "^8.0.10",
"@types/three": "^0.159.0",
"@threlte/core": "^7.3.1",
"@threlte/extras": "^8.11.4",
"@types/three": "^0.166.0",
"@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.15.0",
"@viamrobotics/eslint-config": "^0.3.0",
Expand All @@ -72,6 +70,7 @@
"eslint-plugin-tailwindcss": "^3.13.0",
"eslint-plugin-unicorn": "^49.0.0",
"jsdom": "^23.0.1",
"maplibre-gl": "^4.5.0",
"postcss": "^8.4.32",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
Expand All @@ -80,7 +79,7 @@
"svelte": "^4.2.8",
"svelte-check": "^3.6.2",
"tailwindcss": "^3.3.7",
"three": "^0.159.0",
"three": "^0.166.1",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"vite": "^5.0.10",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
<script lang="ts">
import * as THREE from 'three';
import { T } from '@threlte/core';
import { Line2 } from 'three/examples/jsm/lines/Line2';
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial';
import { Color } from 'three';
import { T, type Props } from '@threlte/core';
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
interface $$Props extends Props<Line2> {
length?: number;
width?: number;
axesColors?: [x: string, y: string, z: string];
depthTest?: boolean;
}
export let length = 1;
export let width = 0.2;
export let width = 1;
export let axesColors = ['red', 'green', 'blue'];
export let depthTest = true;
const TOTAL_VERTICES = 9;
const VERTEX_COMPONENTS = 3;
const line = new Line2();
const material = new LineMaterial();
const geometry = new LineGeometry();
const color = new THREE.Color();
const color = new Color();
const colors = new Float32Array(TOTAL_VERTICES * VERTEX_COMPONENTS);
const positions = new Float32Array(TOTAL_VERTICES * VERTEX_COMPONENTS);
// An arbitrary division that "feels good" using meter scale.
$: material.linewidth = width / 100;
$: material.linewidth = width;
// Assign colors per vertex
$: {
Expand Down Expand Up @@ -52,11 +59,15 @@ $: {
}
</script>

<T is={line}>
<T
is={line}
{...$$restProps}
raycast={() => null}
>
<T is={geometry} />
<T
is={material}
alphaToCoverage
vertexColors
{depthTest}
/>
</T>
23 changes: 20 additions & 3 deletions packages/blocks/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
// Three.js components
export { default as AxesHelper } from './axes-helper/axes-helper.svelte';

// MapLibre components
export { LngLat, MercatorCoordinate } from 'maplibre-gl';
export { default as MapLibre } from './maplibre/index.svelte';
export { default as MapLibreMarker } from './maplibre/marker.svelte';
export { default as MapLibreDirectionalMarker } from './maplibre/directional-marker.svelte';
export { default as MapLibreControls } from './maplibre/controls.svelte';
export { default as DirectionalMarker } from './maplibre/directional-marker.svelte';
export { default as NavigationControls } from './maplibre/controls/navigation.svelte';
export { default as CenterControls } from './maplibre/controls/center.svelte';
export { default as FollowControls } from './maplibre/controls/follow.svelte';
export { default as SatelliteControls } from './maplibre/controls/satellite.svelte';
export { default as LngLatInput } from './maplibre/lnglat-input.svelte';
export { useMapLibre, useMapLibreEvent } from './maplibre/hooks';
export type { LngLat, GeoPose, Waypoint } from './maplibre/types';
export { useMapLibreThreeRenderer } from './maplibre/plugins/three';
export { useMapLibreThreeRaycast } from './maplibre/plugins/raycast';
export {
lngLatToMercator,
mercatorToCartesian,
lngLatToCartesian,
cartesianToLngLat,
cartesianToMercator,
} from './maplibre/math';
export { GeoPose, Waypoint } from './maplibre/types';

// Slam components
export { default as SlamMap2D } from './slam-map-2d/index.svelte';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<!--
@component
Adds an lat, lng set of inputs for viewing and setting the map center.
-->
<script lang="ts">
import { LngLat } from 'maplibre-gl';
import { persisted } from '@viamrobotics/prime-core';
import { useMapLibre, useMapLibreEvent, type LngLat } from '$lib';
import LngLatInput from '../components/input/lnglat.svelte';
import { useMapLibre, useMapLibreEvent } from '../hooks';
import LngLatInput from '../lnglat-input.svelte';
const { map, mapCenter } = useMapLibre();
const lastPosition = persisted<{ center: LngLat; zoom: number }>(
Expand All @@ -24,10 +29,8 @@ useMapLibreEvent('move', () => {
});
</script>

<div class="flex w-60 flex-wrap items-end justify-between gap-y-2">
<LngLatInput
lng={$mapCenter.lng}
lat={$mapCenter.lat}
on:input={handleInput}
/>
</div>
<LngLatInput
lng={$mapCenter.lng}
lat={$mapCenter.lat}
on:input={handleInput}
/>
60 changes: 60 additions & 0 deletions packages/blocks/src/lib/maplibre/controls/follow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
@component
Adds controls for following a lat, lng point on a map.
-->
<script lang="ts">
import { onMount } from 'svelte';
import { Button, Icon } from '@viamrobotics/prime-core';
import { useMapLibre } from '../hooks';
/** The map point to follow */
export let lng: number | undefined = undefined;
export let lat: number | undefined = undefined;
export let onChange: ((following: boolean) => void) | undefined = undefined;
let following = false;
const { map } = useMapLibre();
let rafID = 0;
const follow = () => {
if (lng && lat && following) {
map.setCenter([lng, lat]);
rafID = requestAnimationFrame(follow);
}
};
const stop = () => {
cancelAnimationFrame(rafID);
following = false;
};
$: if (following) {
requestAnimationFrame(follow);
}
onMount(() => {
map.on('wheel', stop);
map.on('mousedown', stop);
return () => {
cancelAnimationFrame(rafID);
map.off('wheel', stop);
map.off('mousedown', stop);
};
});
</script>

<Button
disabled={lng === undefined || lat === undefined}
on:click={(event) => {
event.stopPropagation();
following = !following;
onChange?.(following);
}}
>
<Icon
name={following ? 'navigation-variant' : 'navigation-variant-outline'}
/>
</Button>
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!--
@component
Adds a set of navigation controls.
Adds a set of maplibre navigation controls.
@example
```html
<MapLibre>
<MapLibreControls />
<NavigationControls />
</MapLibre>
```
Expand All @@ -16,7 +16,7 @@
<script lang="ts">
import { NavigationControl, type ControlPosition } from 'maplibre-gl';
import { onMount } from 'svelte';
import { useMapLibre } from './hooks';
import { useMapLibre } from '../hooks';
export let position: ControlPosition = 'top-right';
Expand Down
25 changes: 25 additions & 0 deletions packages/blocks/src/lib/maplibre/controls/satellite.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
@component
Adds controls for toggling between a satellite and map view.
-->
<script lang="ts">
import { Button } from '@viamrobotics/prime-core';
import { useMapLibre } from '../hooks';
export let satellite = false;
const { map } = useMapLibre();
const onClick = () => {
satellite = !satellite;
map.setLayoutProperty(
'satellite',
'visibility',
satellite ? 'visible' : 'none'
);
};
</script>

<Button on:click={onClick}>
{satellite ? 'Map' : 'Satellite'}
</Button>
4 changes: 2 additions & 2 deletions packages/blocks/src/lib/maplibre/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { onMount, tick } from 'svelte';
import { provideMapContext } from './hooks';
import { Map, type MapOptions } from 'maplibre-gl';
import { style } from './style';
import type { LngLat } from '$lib';
import { LngLat } from '$lib';
/** The minimum camera pitch. */
export let minPitch = 0;
Expand All @@ -42,7 +42,7 @@ export let maxZoom = 22;
* @default { lng: -73.984421, lat: 40.7718116 }
* The Viam Robotics office.
*/
export let center: LngLat = { lng: -73.984_421, lat: 40.771_811_6 };
export let center: LngLat = new LngLat(-73.984_421, 40.771_811_6);
/** A binding to the MapLibre Map instance */
export let map: Map | undefined = undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import { MercatorCoordinate } from 'maplibre-gl';
import type { LngLat } from '$lib';

export const toPrecisionLevel = (number: number, decimals: number): number => {
const multiplier = 10 ** decimals;
return Math.floor(number * multiplier) / multiplier;
};
import { MercatorCoordinate, LngLat } from 'maplibre-gl';

export const lngLatToMercator = (lngLat: LngLat): MercatorCoordinate => {
return MercatorCoordinate.fromLngLat(lngLat, 0);
Expand Down
42 changes: 42 additions & 0 deletions packages/blocks/src/lib/maplibre/plugins/raycast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { onMount } from 'svelte';
import { type Camera, type Raycaster, Vector2, Vector3, Matrix4 } from 'three';
import type { MapMouseEvent } from 'maplibre-gl';
import { useMapLibre } from '../hooks';

/**
* Provides raycasting against THREE objects projected on to a maplibre map.
*/
export const useMapLibreThreeRaycast = (cameraSignal: { current: Camera }) => {
const { map } = useMapLibre();
const pointer = new Vector2();

const handleMouseMove = (event: MapMouseEvent) => {
pointer.set(
(event.point.x / map.transform.width) * 2 - 1,
-(event.point.y / map.transform.height) * 2 + 1
);
};

onMount(() => {
map.on('mousemove', handleMouseMove);
return () => map.off('mousemove', handleMouseMove);
});

const cameraPosition = new Vector3();
const mousePosition = new Vector3();
const viewDirection = new Vector3();
const camInverseProjection = new Matrix4();

const compute = (raycaster: Raycaster) => {
camInverseProjection.copy(cameraSignal.current.projectionMatrix).invert();
cameraPosition.set(0, 0, 0).applyMatrix4(camInverseProjection);
mousePosition
.set(pointer.x, pointer.y, 1)
.applyMatrix4(camInverseProjection);
viewDirection.copy(mousePosition).sub(cameraPosition).normalize();

raycaster.set(cameraPosition, viewDirection);
};

return { compute, pointer };
};
Loading

0 comments on commit ea44009

Please sign in to comment.