From 4f64723766ce1d895c6d58c64a22246fbeca18fd Mon Sep 17 00:00:00 2001 From: "Dr. Sergey Pogodin" Date: Fri, 20 Sep 2024 11:04:36 +0200 Subject: [PATCH] [#9165] H3HexagonLayer / Elevation of hexagons above the ground --- .../geo-layers/h3-hexagon-layer.md | 4 +-- .../src/h3-layers/h3-hexagon-layer.ts | 23 ++++++++----- modules/geo-layers/src/h3-layers/h3-utils.ts | 34 ++++++++++++++++--- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/docs/api-reference/geo-layers/h3-hexagon-layer.md b/docs/api-reference/geo-layers/h3-hexagon-layer.md index e3ac9a768a5..2ba71ed9cc7 100644 --- a/docs/api-reference/geo-layers/h3-hexagon-layer.md +++ b/docs/api-reference/geo-layers/h3-hexagon-layer.md @@ -191,11 +191,11 @@ Hexagon radius multiplier, between 0 - 1. When `coverage` = 1, hexagon is render ### Data Accessors -#### `getHexagon` ([Accessor<string>](../../developer-guide/using-layers.md#accessors), optional) {#gethexagon} +#### `getHexagon` ([Accessor<string | [string, number]>](../../developer-guide/using-layers.md#accessors), optional) {#gethexagon} * Default: `object => object.hexagon` -Method called to retrieve the [H3](https://h3geo.org/) hexagon index of each object. Note that all hexagons within one `H3HexagonLayer` must use the same [resolution](https://h3geo.org/docs/core-library/restable). +Method called to retrieve the [H3](https://h3geo.org/) hexagon index of each object. Optionally, it may return `[string, number]` tuple, where the first element is the hexagon index, and the second one is the hexagon base elevation over the ground. Note that all hexagons within one `H3HexagonLayer` must use the same [resolution](https://h3geo.org/docs/core-library/restable). ## Sub Layers diff --git a/modules/geo-layers/src/h3-layers/h3-hexagon-layer.ts b/modules/geo-layers/src/h3-layers/h3-hexagon-layer.ts index ce1cc50e423..a6a92ae881a 100644 --- a/modules/geo-layers/src/h3-layers/h3-hexagon-layer.ts +++ b/modules/geo-layers/src/h3-layers/h3-hexagon-layer.ts @@ -7,8 +7,8 @@ import { getHexagonEdgeLengthAvg, H3Index } from 'h3-js'; + import { - AccessorFunction, CompositeLayer, createIterable, Layer, @@ -17,8 +17,16 @@ import { WebMercatorViewport, DefaultProps } from '@deck.gl/core'; + import {ColumnLayer, PolygonLayer, PolygonLayerProps} from '@deck.gl/layers'; -import {flattenPolygon, getHexagonCentroid, h3ToPolygon} from './h3-utils'; + +import { + type HexagonAccessor, + flattenPolygon, + getHexagonCentroid, + getIndexAndBaseElevation, + h3ToPolygon +} from './h3-utils'; // There is a cost to updating the instanced geometries when using highPrecision: false // This constant defines the distance between two hexagons that leads to "significant @@ -71,7 +79,7 @@ type _H3HexagonLayerProps = { * * By default, it reads `hexagon` property of data object. */ - getHexagon?: AccessorFunction; + getHexagon?: HexagonAccessor; /** * Whether to extrude polygons. * @default true @@ -136,7 +144,7 @@ export default class H3HexagonLayer< const {iterable, objectInfo} = createIterable(this.props.data); for (const object of iterable) { objectInfo.index++; - const hexId = this.props.getHexagon(object, objectInfo); + const [hexId] = getIndexAndBaseElevation(this.props.getHexagon, object, objectInfo); // Take the resolution of the first hex const hexResolution = getResolution(hexId); if (resolution < 0) { @@ -292,10 +300,9 @@ export default class H3HexagonLayer< data, _normalize: false, _windingOrder: 'CCW', - positionFormat: 'XY', getPolygon: (object, objectInfo) => { - const hexagonId = getHexagon(object, objectInfo); - return flattenPolygon(h3ToPolygon(hexagonId, coverage)); + const hexagon = getHexagon(object, objectInfo); + return flattenPolygon(h3ToPolygon(hexagon, coverage)); } } ); @@ -320,7 +327,7 @@ export default class H3HexagonLayer< diskResolution: 6, // generate an extruded hexagon as the base geometry radius: 1, vertices: this.state.vertices, - getPosition: getHexagonCentroid.bind(null, getHexagon) + getPosition: getHexagonCentroid.bind(null, getHexagon as any) } ); } diff --git a/modules/geo-layers/src/h3-layers/h3-utils.ts b/modules/geo-layers/src/h3-layers/h3-utils.ts index c3ab930d35a..93f1a33ffad 100644 --- a/modules/geo-layers/src/h3-layers/h3-utils.ts +++ b/modules/geo-layers/src/h3-layers/h3-utils.ts @@ -1,5 +1,8 @@ import {CoordPair, H3IndexInput, cellToBoundary, cellToLatLng} from 'h3-js'; import {lerp} from '@math.gl/core'; +import type {AccessorFunction} from '@deck.gl/core'; + +export type HexagonAccessor = AccessorFunction; // normalize longitudes w.r.t center (refLng), when not provided first vertex export function normalizeLongitudes(vertices: CoordPair[], refLng?: number): void { @@ -31,14 +34,32 @@ export function scalePolygon(hexId: H3IndexInput, vertices: CoordPair[], factor: } } +// gets hexagon id +export function getIndexAndBaseElevation( + getHexagon: HexagonAccessor, + object, + objectInfo +): [string, number] { + const hexagon = getHexagon(object, objectInfo); + return typeof hexagon === 'string' ? [hexagon, 0] : hexagon; +} + // gets hexagon centroid -export function getHexagonCentroid(getHexagon, object, objectInfo) { - const hexagonId = getHexagon(object, objectInfo); +export function getHexagonCentroid(getHexagon: HexagonAccessor, object, objectInfo) { + const [hexagonId, baseElevation] = getIndexAndBaseElevation(getHexagon, object, objectInfo); const [lat, lng] = cellToLatLng(hexagonId); - return [lng, lat]; + return [lng, lat, baseElevation]; } -export function h3ToPolygon(hexId: H3IndexInput, coverage: number = 1): number[][] { +export function h3ToPolygon(hex: string | [string, number], coverage: number = 1): number[][] { + let baseElevation: number; + let hexId: string; + + if (typeof hex === 'string') { + baseElevation = 0; + hexId = hex; + } else [hexId, baseElevation] = hex; + const vertices = cellToBoundary(hexId, true); if (coverage !== 1) { @@ -49,15 +70,18 @@ export function h3ToPolygon(hexId: H3IndexInput, coverage: number = 1): number[] normalizeLongitudes(vertices); } + for (const vtx of vertices) vtx.push(baseElevation); + return vertices; } export function flattenPolygon(vertices: number[][]): Float64Array { - const positions = new Float64Array(vertices.length * 2); + const positions = new Float64Array(vertices.length * 3); let i = 0; for (const pt of vertices) { positions[i++] = pt[0]; positions[i++] = pt[1]; + positions[i++] = pt[2]; } return positions; }