Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#9165] H3HexagonLayer / Elevation of hexagons above the ground #9166

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions docs/api-reference/geo-layers/h3-hexagon-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't normally support tuples. A possible option might be to have a getHexagonElevation accessor. They are likely to come from different columns in the source data anyway?



## Sub Layers
Expand Down
23 changes: 15 additions & 8 deletions modules/geo-layers/src/h3-layers/h3-hexagon-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
getHexagonEdgeLengthAvg,
H3Index
} from 'h3-js';

import {
AccessorFunction,
CompositeLayer,
createIterable,
Layer,
Expand All @@ -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
Expand Down Expand Up @@ -71,7 +79,7 @@ type _H3HexagonLayerProps<DataT> = {
*
* By default, it reads `hexagon` property of data object.
*/
getHexagon?: AccessorFunction<DataT, string>;
getHexagon?: HexagonAccessor<DataT>;
/**
* Whether to extrude polygons.
* @default true
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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));
}
}
);
Expand All @@ -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)
}
);
}
Expand Down
34 changes: 29 additions & 5 deletions modules/geo-layers/src/h3-layers/h3-utils.ts
Original file line number Diff line number Diff line change
@@ -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<DataT> = AccessorFunction<DataT, string | [string, number]>;

// normalize longitudes w.r.t center (refLng), when not provided first vertex
export function normalizeLongitudes(vertices: CoordPair[], refLng?: number): void {
Expand Down Expand Up @@ -31,14 +34,32 @@ export function scalePolygon(hexId: H3IndexInput, vertices: CoordPair[], factor:
}
}

// gets hexagon id
export function getIndexAndBaseElevation<DataT>(
getHexagon: HexagonAccessor<DataT>,
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<DataT>(getHexagon: HexagonAccessor<DataT>, 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) {
Expand All @@ -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;
}