Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions docs/modules/geo-layers/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Overview


![deck.gl v9](https://img.shields.io/badge/deck.gl-v9-green.svg?style=flat-square")
![WebGPU not supported](https://img.shields.io/badge/webgpu-no-red.svg?style=flat-square")
![deck.gl v9](https://img.shields.io/badge/deck.gl-v9-green.svg?style=flat-square)
![WebGPU partially supported](https://img.shields.io/badge/webgpu-partial-yellow.svg?style=flat-square)

This module provides a suite of geospatial layers for [deck.gl](https://deck.gl).

:::caution
The deck.gl-community repository is semi-maintaned. One of its goals is to collect and preserve valuable deck.gl ecosystem related code that does not have a dedicated home. Some modules may no longer have dedicated maintainers. This means that there is sometimes no one who can respond quickly to issues.
The deck.gl-community repository is semi-maintained. One of its goals is to collect and preserve
valuable deck.gl ecosystem code that does not have a dedicated home. Some modules may no longer
have dedicated maintainers, so responses to issues are not guaranteed.
:::

## Installation
Expand All @@ -18,10 +19,50 @@ npm install @deck.gl-community/geo-layers

## Background

This modules exports various geospatial deck.gl layers developed by the community that could be of use to others.
This module exports geospatial deck.gl layers developed by the community.

## Wind showcase

:::caution Work in progress
The wind-layer API and historical showcase are experimental. `ParticleLayer` has verified WebGL2
and WebGPU GPU simulation. The complete terrain-and-arrows scene remains WebGL2-first because
upstream terrain, polygon, and path support on WebGPU is still in progress.
:::

The [wind showcase guide](./developer-guide/wind-showcase.md) recreates Nicolas Belmonte's
[original deck.gl wind showcase](https://github.com/visgl/deck.gl/tree/master/showcases/wind/src)
using the original 72-hour forecast, smoothed three-dimensional mountain terrain, directional
arrows, and up to one million GPU-animated particles.

```ts
import {
createWindField,
parseWindData,
ParticleLayer,
WindLayer
} from '@deck.gl-community/geo-layers';

const frames = parseWindData(weatherBuffer, stations.length);
const windField = createWindField(stations, frames);

const layers = [
new WindLayer({id: 'wind-arrows', windField, time}),
new ParticleLayer({
id: 'wind-particles',
windField,
time,
numParticles: 100_000
})
];
```

Create and share the wind field once; advance `time` without rebuilding the station triangulation,
weather textures, or GPU particle buffers.

## API Reference

- [Wind field and weather data](./api-reference/wind-field.md) documents the original binary
forecast, positive-west station coordinates, robust triangulation, and geographic interpolation.
- [WindLayer](/docs/modules/geo-layers/api-reference/wind-layer) renders Delaunay-interpolated,
speed-colored wind arrows.
- [ParticleLayer](/docs/modules/geo-layers/api-reference/particle-layer) animates fading trails
Expand All @@ -31,7 +72,7 @@ This modules exports various geospatial deck.gl layers developed by the communit
- [DelaunayCoverLayer](/docs/modules/geo-layers/api-reference/delaunay-cover-layer) renders the
elevation-colored station triangulation.
- [DelaunayInterpolation](/docs/modules/geo-layers/api-reference/delaunay-interpolation) samples
or rasterizes time-varying station measurements without WebGL-only transforms.
or explicitly rasterizes time-varying station measurements independently of the graphics backend.
- [SharedTile2DLayer](/docs/modules/geo-layers/api-reference/shared-tile-2d-layer)
<img src="https://img.shields.io/badge/from-v9.3-green.svg?style=flat-square" alt="from v9.3" />
<img src="https://img.shields.io/badge/experimental-orange.svg?style=flat-square" alt="experimental" />
Expand Down
44 changes: 32 additions & 12 deletions docs/modules/geo-layers/api-reference/delaunay-cover-layer.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
import LayerLiveExample from '@site/src/components/docs/layer-live-example';

# DelaunayCoverLayer

`DelaunayCoverLayer` renders a terrain surface from the same weather-station triangulation used to
interpolate a `WindField`. Each triangle follows measured station elevations and is colored by its
average height. It recreates the elevation surface in the original deck.gl wind showcase.
:::caution Work in progress
The station-surface appearance and API may change. Its `SolidPolygonLayer` sublayer is not yet
fully portable to WebGPU.
:::

`DelaunayCoverLayer` renders one elevation-colored polygon for each triangle in a shared
[`WindField`](./wind-field.md). It visualizes the real station interpolation hull; it is not the
same as the smoothed image-based mountain surface rendered by
[`ElevationLayer`](./elevation-layer.md).

<LayerLiveExample highlight="delaunay-cover-layer" size="tall" />

## Import

```ts
import {DelaunayCoverLayer} from '@deck.gl-community/geo-layers';
```

## Example

const layer = new DelaunayCoverLayer({
id: 'wind-terrain',
```ts
const stationSurface = new DelaunayCoverLayer({
id: 'wind-station-surface',
windField,
elevationScale: 14,
elevationScale: 24,
lowColor: [17, 34, 49, 220],
highColor: [102, 151, 127, 235]
highColor: [102, 151, 127, 235],
opacity: 0.32
});
```

## Properties

- `windField`: A `WindField` returned by `createWindField`.
- `elevationScale`: Multiplier for each station elevation.
- `lowColor`, `highColor`: RGBA colors interpolated by average triangle elevation.
- `windField` (`WindField`, required): shared robust station triangulation and forecast.
- `elevationScale` (`number`, default `1`): station-height multiplier.
- `lowColor` (`Color`, default `[17, 34, 49, 220]`): fill color for the lowest stations.
- `highColor` (`Color`, default `[102, 151, 127, 235]`): fill color for the highest stations.
- Standard deck.gl `CompositeLayer` properties, including `opacity` and `visible`.

## Sub-layers

- `terrain`: A `SolidPolygonLayer` containing the station Delaunay triangles.
- `terrain`: a `SolidPolygonLayer` containing the station-index Delaunay triangles.

See the [Wind Map example](/examples/geo-layers/wind).
Use the example's **Delaunay station surface** control to inspect the triangulation independently
of the smoothed mountains. See the [wind showcase guide](../developer-guide/wind-showcase.md).
83 changes: 62 additions & 21 deletions docs/modules/geo-layers/api-reference/delaunay-interpolation.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,81 @@
import LayerLiveExample from '@site/src/components/docs/layer-live-example';

# DelaunayInterpolation

`DelaunayInterpolation` samples or rasterizes the station-interpolated vector field used by the
wind showcase layers. It replaces the original showcase's off-screen WebGL transform with a
backend-independent implementation suitable for WebGL, WebGPU, preprocessing, and Node.js.
:::caution Work in progress
The wind raster layout and interpolation options may evolve. This utility performs explicit CPU
sampling; GPU particle advection is implemented separately by
[`ParticleLayer`](./particle-layer.md).
:::

`DelaunayInterpolation` samples or rasterizes a station-interpolated geographic wind field. It is
usable in the browser, in Node.js, and as an input-preprocessing step for either graphics backend.

<LayerLiveExample highlight="delaunay-interpolation" size="tall" />

## Import

```ts
import {
createWindField,
DelaunayInterpolation,
parseWindData
} from '@deck.gl-community/geo-layers';
```

const stations = await fetch('/stations.json').then(response => response.json());
const weather = await fetch('/weather.bin').then(response => response.arrayBuffer());
## Sample a geographic location

```ts
const stations = await fetch('/wind/stations.json').then(response => response.json());
const weather = await fetch('/wind/weather.bin').then(response => response.arrayBuffer());
const field = createWindField(stations, parseWindData(weather, stations.length));

const interpolation = new DelaunayInterpolation({field, width: 256});
const interpolation = new DelaunayInterpolation({
field,
width: 128,
height: 64
});

const sample = interpolation.sample([-97, 38], 12.5);

if (sample) {
console.log(sample.direction, sample.speed, sample.temperature);
console.log(sample.velocity, sample.elevation);
}
```

Positions outside the triangulated station hull return `null`. Forecast time interpolates between
adjacent frames and wraps at the end of the forecast.

## Rasterize a forecast frame

```ts
const raster = interpolation.rasterize(12.5);
const center = (Math.floor(raster.height / 2) * raster.width + Math.floor(raster.width / 2)) * 4;

const direction = raster.data[center];
const speed = raster.data[center + 1];
const temperature = raster.data[center + 2];
const elevation = raster.data[center + 3];
```

`sample` returns direction in radians, wind speed, temperature, elevation, and an east/north
velocity vector. Points outside the triangulated station coverage return `null`.
`rasterize` returns [`WindRaster`](./wind-field.md): `{width, height, data}`. Its `Float32Array`
contains row-major `[direction, speed, temperature, elevation]` pixels. Uncovered pixels are zero.

## Constructor properties

- `field` (`WindField`, required): shared indexed station forecast.
- `width` (`number`, default `256`): raster width, at least `2` pixels.
- `height` (`number`, optional): raster height, at least `2` pixels; inferred from the geographic
aspect ratio when omitted.

## Methods

`rasterize` returns `{width, height, data}`, where `data` is a `Float32Array` containing direction,
speed, temperature, and elevation in RGBA component order.
- `sample(position, time?)`: returns a [`WindSample`](./wind-field.md) or `null`.
- `rasterize(time?)`: returns one lazily generated [`WindRaster`](./wind-field.md).

## Related utilities
Do not call `rasterize` for each animated particle or browser frame. `ParticleLayer` caches the
weather textures and performs per-particle movement entirely on the graphics device.

- `parseWindData(buffer, stationCount, frameCount?)`: Decodes the original station-major binary
forecast. The default forecast length is 72 hourly frames.
- `getWindBounds(stations)`: Converts positive-west legacy station longitudes into geographic
bounds.
- `triangulateWindStations(stations)`: Builds a Delaunay triangulation without external
triangulation dependencies.
- `createWindField(stations, frames, options?)`: Creates a spatially indexed, time-varying wind
field shared by all three layers.
- `sampleWindField(field, position, time?)`: Samples a field without constructing an interpolation
wrapper.
See the [wind showcase guide](../developer-guide/wind-showcase.md) and the
[Wind Map example](/examples/geo-layers/wind).
56 changes: 37 additions & 19 deletions docs/modules/geo-layers/api-reference/elevation-layer.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,57 @@
import LayerLiveExample from '@site/src/components/docs/layer-live-example';

# ElevationLayer

`ElevationLayer` renders a grayscale elevation image as a genuinely three-dimensional, illuminated
terrain mesh. It ports the height-map surface used by Nicolas Belmonte's original wind showcase,
including the original elevation image, geographic bounds, and elevation range.
:::caution Work in progress
The terrain API, height-map smoothing, material, and exaggeration are experimental. WebGPU
compatibility depends on upstream `TerrainLayer` and loaders.gl support.
:::

`ElevationLayer` decodes a grayscale height map into illuminated, extruded mountain geometry.
Unlike [`DelaunayCoverLayer`](./delaunay-cover-layer.md), its mesh follows the original elevation
image rather than the sparse weather-station triangles.

<LayerLiveExample highlight="elevation-layer" size="tall" />

## Import

```ts
import {ElevationLayer} from '@deck.gl-community/geo-layers';
```

## Example

const layer = new ElevationLayer({
id: 'wind-elevation',
```ts
const terrain = new ElevationLayer({
id: 'wind-mountain-terrain',
elevationData:
'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/wind/elevation.png',
bounds: [-125, 24.4, -66.7, 49.6],
elevationRange: [-100, 4126],
elevationScale: 80,
meshMaxError: 480,
color: [42, 60, 77, 255]
elevationScale: 24,
meshMaxError: 12,
color: [35, 49, 64, 255]
});
```

The layer decodes the original height map into terrain geometry using the in-process loaders.gl
terrain loader. It does not require an externally hosted terrain worker.
For smoother relief, filter the grayscale image once before passing it as `elevationData`. Do not
recreate or decode the terrain mesh during particle animation.

## Properties

- `elevationData`: URL of the red-channel grayscale terrain height map.
- `bounds`: Geographic `[west, south, east, north]` extent.
- `elevationRange`: Minimum and maximum image elevations, in meters.
- `elevationScale`: Vertical exaggeration applied to the decoded mesh.
- `meshMaxError`: Simplification error tolerance for the generated terrain mesh.
- `color`: RGBA color applied to the lit terrain surface.
- `texture`: Optional image draped over the three-dimensional mesh.
- `elevationData` (`string`, required): URL or data URL of a red-channel grayscale height map.
- `bounds` (`[number, number, number, number]`, required): geographic west, south, east, and north.
- `elevationRange` (`[number, number]`, default `[-100, 4126]`): source elevation range in meters.
- `elevationScale` (`number`, default `1`): vertical exaggeration of the decoded mesh.
- `meshMaxError` (`number`, default `80`): terrain simplification error; use approximately `12`
for the smoothed wind showcase.
- `color` (`Color`, default `[42, 58, 72, 255]`): shaded mountain-surface color.
- `texture` (`string`, optional): image draped over the decoded terrain.

## Sub-layers

- `terrain-mesh`: A `TerrainLayer` containing the decoded elevation mesh.
- `terrain-mesh`: a loaders.gl-backed `TerrainLayer`.

See the [Wind Map example](/examples/geo-layers/wind).
Terrain decoding runs in-process, so the example does not require a separately hosted terrain
worker. See the [wind showcase guide](../developer-guide/wind-showcase.md) and the
[Wind Map example](/examples/geo-layers/wind).
Loading
Loading