Giter VIP home page Giter VIP logo

h3-js's Introduction

H3 Logo

h3-js

Build Status Coverage Status License npm version H3 Version

The h3-js library provides a pure-JavaScript version of the H3 Core Library, a hexagon-based geographic grid system. It can be used either in Node >= 6 or in the browser. The core library is transpiled from C using emscripten, offering full parity with the C API and highly efficient operations.

For more information on H3 and for the full API documentation, please see the H3 Documentation.

Install

npm install h3-js

Usage

๐ŸŽ‰ Note: The following usage docs apply to H3 v4, which was released on August 23, 2022.

The library uses ES6 modules. Bundles for Node and the browser are built to the dist folder.

Import

ES6 usage:

import {latLngToCell} from "h3-js";

CommonJS usage:

const h3 = require("h3-js");

Pre-bundled script (library is available as an h3 global):

<script src="https://unpkg.com/h3-js"></script>

Core functions

// Convert a lat/lng point to a hexagon index at resolution 7
const h3Index = h3.latLngToCell(37.3615593, -122.0553238, 7);
// -> '87283472bffffff'

// Get the center of the hexagon
const hexCenterCoordinates = h3.cellToLatLng(h3Index);
// -> [37.35171820183272, -122.05032565263946]

// Get the vertices of the hexagon
const hexBoundary = h3.cellToBoundary(h3Index);
// -> [ [37.341099093235684, -122.04156135164334 ], ...]

Useful algorithms

// Get all neighbors within 1 step of the hexagon
const disk = h3.gridDisk(h3Index, 1);
// -> ['87283472bffffff', '87283472affffff', ...]

// Get the set of hexagons within a polygon
const polygon = [
    [37.813318999983238, -122.4089866999972145],
    [37.7198061999978478, -122.3544736999993603],
    [37.8151571999998453, -122.4798767000009008]
];
const hexagons = h3.polygonToCells(polygon, 7);
// -> ['872830828ffffff', '87283082effffff', ...]

// Get the outline of a set of hexagons, as a GeoJSON-style MultiPolygon
const coordinates = h3.cellsToMultiPolygon(hexagons, true);
// -> [[[
//      [-122.37681938644465, 37.76546768434345],
//      [-122.3856345540363,37.776004200673846],
//      ...
//    ]]]

API Reference

h3


h3.UNITS

Length/Area units

Properties

Name Type
m string
m2 string
km string
km2 string
rads string
rads2 string

h3.h3IndexToSplitLong(h3Index) โ‡’ SplitLong

Convert an H3 index (64-bit hexidecimal string) into a "split long" - a pair of 32-bit ints

Returns: SplitLong - A two-element array with 32 lower bits and 32 upper bits

Param Type Description
h3Index H3IndexInput H3 index to check

h3.splitLongToH3Index(lower, upper) โ‡’ H3Index

Get a H3 index string from a split long (pair of 32-bit ints)

Returns: H3Index - H3 index

Param Type Description
lower number Lower 32 bits
upper number Upper 32 bits

h3.isValidCell(h3Index) โ‡’ boolean

Whether a given string represents a valid H3 index

Returns: boolean - Whether the index is valid

Param Type Description
h3Index H3IndexInput H3 index to check

h3.isPentagon(h3Index) โ‡’ boolean

Whether the given H3 index is a pentagon

Returns: boolean - isPentagon

Param Type Description
h3Index H3IndexInput H3 index to check

h3.isResClassIII(h3Index) โ‡’ boolean

Whether the given H3 index is in a Class III resolution (rotated versus the icosahedron and subject to shape distortion adding extra points on icosahedron edges, making them not true hexagons).

Returns: boolean - isResClassIII

Param Type Description
h3Index H3IndexInput H3 index to check

h3.getBaseCellNumber(h3Index) โ‡’ number

Get the number of the base cell for a given H3 index

Returns: number - Index of the base cell (0-121)

Param Type Description
h3Index H3IndexInput H3 index to get the base cell for

h3.getIcosahedronFaces(h3Index) โ‡’ Array.<number>

Get the indices of all icosahedron faces intersected by a given H3 index

Returns: Array.<number> - Indices (0-19) of all intersected faces
Throws:

  • H3Error If input is invalid
Param Type Description
h3Index H3IndexInput H3 index to get faces for

h3.getResolution(h3Index) โ‡’ number

Returns the resolution of an H3 index

Returns: number - The number (0-15) resolution, or -1 if invalid

Param Type Description
h3Index H3IndexInput H3 index to get resolution

h3.latLngToCell(lat, lng, res) โ‡’ H3Index

Get the hexagon containing a lat,lon point

Returns: H3Index - H3 index
Throws:

  • H3Error If input is invalid
Param Type Description
lat number Latitude of point
lng number Longtitude of point
res number Resolution of hexagons to return

h3.cellToLatLng(h3Index) โ‡’ CoordPair

Get the lat,lon center of a given hexagon

Returns: CoordPair - Point as a [lat, lng] pair
Throws:

  • H3Error If input is invalid
Param Type Description
h3Index H3IndexInput H3 index

h3.cellToBoundary(h3Index, [formatAsGeoJson]) โ‡’ Array.<CoordPair>

Get the vertices of a given hexagon (or pentagon), as an array of [lat, lng] points. For pentagons and hexagons on the edge of an icosahedron face, this function may return up to 10 vertices.

Returns: Array.<CoordPair> - Array of [lat, lng] pairs
Throws:

  • H3Error If input is invalid
Param Type Description
h3Index H3IndexInput H3 index
[formatAsGeoJson] boolean Whether to provide GeoJSON output: [lng, lat], closed loops

h3.cellToParent(h3Index, res) โ‡’ H3Index

Get the parent of the given hexagon at a particular resolution

Returns: H3Index - H3 index of parent, or null for invalid input
Throws:

  • H3Error If input is invalid
Param Type Description
h3Index H3IndexInput H3 index to get parent for
res number Resolution of hexagon to return

h3.cellToChildren(h3Index, res) โ‡’ Array.<H3Index>

Get the children/descendents of the given hexagon at a particular resolution

Returns: Array.<H3Index> - H3 indexes of children, or empty array for invalid input
Throws:

  • H3Error If resolution is invalid or output is too large for JS
Param Type Description
h3Index H3IndexInput H3 index to get children for
res number Resolution of hexagons to return

h3.cellToChildrenSize(h3Index, res) โ‡’ number

Get the number of children for a cell at a given resolution

Returns: number - Number of children at res for the given cell
Throws:

  • H3Error If cell or parentRes are invalid
Param Type Description
h3Index H3IndexInput H3 index to get child count for
res number Child resolution

h3.cellToCenterChild(h3Index, res) โ‡’ H3Index

Get the center child of the given hexagon at a particular resolution

Returns: H3Index - H3 index of child, or null for invalid input
Throws:

  • H3Error If resolution is invalid
Param Type Description
h3Index H3IndexInput H3 index to get center child for
res number Resolution of cell to return

h3.cellToChildPos(h3Index, parentRes) โ‡’ number

Get the position of the cell within an ordered list of all children of the cell's parent at the specified resolution.

Returns: number - Position of child within parent at parentRes
Throws:

  • H3Error If cell or parentRes are invalid
Param Type Description
h3Index H3IndexInput H3 index to get child pos for
parentRes number Resolution of reference parent

h3.childPosToCell(childPos, h3Index, childRes) โ‡’ H3Index

Get the child cell at a given position within an ordered list of all children at the specified resolution

Returns: H3Index - H3 index of child
Throws:

  • H3Error If input is invalid
Param Type Description
childPos number Position of the child cell to get
h3Index H3IndexInput H3 index of the parent cell
childRes number Resolution of child cell to return

h3.gridDisk(h3Index, ringSize) โ‡’ Array.<H3Index>

Get all hexagons in a k-ring around a given center. The order of the hexagons is undefined.

Returns: Array.<H3Index> - H3 indexes for all hexagons in ring
Throws:

  • H3Error If input is invalid or output is too large for JS
Param Type Description
h3Index H3IndexInput H3 index of center hexagon
ringSize number Radius of k-ring

h3.gridDiskDistances(h3Index, ringSize) โ‡’ Array.<Array.<H3Index>>

Get all hexagons in a k-ring around a given center, in an array of arrays ordered by distance from the origin. The order of the hexagons within each ring is undefined.

Returns: Array.<Array.<H3Index>> - Array of arrays with H3 indexes for all hexagons each ring
Throws:

  • H3Error If input is invalid or output is too large for JS
Param Type Description
h3Index H3IndexInput H3 index of center hexagon
ringSize number Radius of k-ring

h3.gridRingUnsafe(h3Index, ringSize) โ‡’ Array.<H3Index>

Get all hexagons in a hollow hexagonal ring centered at origin with sides of a given length. Unlike kRing, this function will throw an error if there is a pentagon anywhere in the ring.

Returns: Array.<H3Index> - H3 indexes for all hexagons in ring
Throws:

  • Error If the algorithm could not calculate the ring
  • H3Error If input is invalid
Param Type Description
h3Index H3IndexInput H3 index of center hexagon
ringSize number Radius of ring

h3.polygonToCells(coordinates, res, [isGeoJson]) โ‡’ Array.<H3Index>

Get all hexagons with centers contained in a given polygon. The polygon is specified with GeoJson semantics as an array of loops. Each loop is an array of [lat, lng] pairs (or [lng, lat] if isGeoJson is specified). The first loop is the perimeter of the polygon, and subsequent loops are expected to be holes.

Returns: Array.<H3Index> - H3 indexes for all hexagons in polygon
Throws:

  • H3Error If input is invalid or output is too large for JS
Param Type Description
coordinates Array.<Array.<number>> | Array.<Array.<Array.<number>>> Array of loops, or a single loop
res number Resolution of hexagons to return
[isGeoJson] boolean Whether to expect GeoJson-style [lng, lat] pairs instead of [lat, lng]

h3.cellsToMultiPolygon(h3Indexes, [formatAsGeoJson]) โ‡’ Array.<Array.<Array.<CoordPair>>>

Get the outlines of a set of H3 hexagons, returned in GeoJSON MultiPolygon format (an array of polygons, each with an array of loops, each an array of coordinates). Coordinates are returned as [lat, lng] pairs unless GeoJSON is requested.

It is the responsibility of the caller to ensure that all hexagons in the set have the same resolution and that the set contains no duplicates. Behavior is undefined if duplicates or multiple resolutions are present, and the algorithm may produce unexpected or invalid polygons.

Returns: Array.<Array.<Array.<CoordPair>>> - MultiPolygon-style output.
Throws:

  • H3Error If input is invalid
Param Type Description
h3Indexes Array.<H3IndexInput> H3 indexes to get outlines for
[formatAsGeoJson] boolean Whether to provide GeoJSON output: [lng, lat], closed loops

h3.compactCells(h3Set) โ‡’ Array.<H3Index>

Compact a set of hexagons of the same resolution into a set of hexagons across multiple levels that represents the same area.

Returns: Array.<H3Index> - Compacted H3 indexes
Throws:

  • H3Error If the input is invalid (e.g. duplicate hexagons)
Param Type Description
h3Set Array.<H3IndexInput> H3 indexes to compact

h3.uncompactCells(compactedSet, res) โ‡’ Array.<H3Index>

Uncompact a compacted set of hexagons to hexagons of the same resolution

Returns: Array.<H3Index> - The uncompacted H3 indexes
Throws:

  • H3Error If the input is invalid (e.g. invalid resolution)
Param Type Description
compactedSet Array.<H3IndexInput> H3 indexes to uncompact
res number The resolution to uncompact to

h3.areNeighborCells(origin, destination) โ‡’ boolean

Whether two H3 indexes are neighbors (share an edge)

Returns: boolean - Whether the hexagons share an edge
Throws:

  • H3Error If the input is invalid
Param Type Description
origin H3IndexInput Origin hexagon index
destination H3IndexInput Destination hexagon index

h3.cellsToDirectedEdge(origin, destination) โ‡’ H3Index

Get an H3 index representing a unidirectional edge for a given origin and destination

Returns: H3Index - H3 index of the edge, or null if no edge is shared
Throws:

  • H3Error If the input is invalid
Param Type Description
origin H3IndexInput Origin hexagon index
destination H3IndexInput Destination hexagon index

h3.getDirectedEdgeOrigin(edgeIndex) โ‡’ H3Index

Get the origin hexagon from an H3 index representing a unidirectional edge

Returns: H3Index - H3 index of the edge origin
Throws:

  • H3Error If the input is invalid
Param Type Description
edgeIndex H3IndexInput H3 index of the edge

h3.getDirectedEdgeDestination(edgeIndex) โ‡’ H3Index

Get the destination hexagon from an H3 index representing a unidirectional edge

Returns: H3Index - H3 index of the edge destination
Throws:

  • H3Error If the input is invalid
Param Type Description
edgeIndex H3IndexInput H3 index of the edge

h3.isValidDirectedEdge(edgeIndex) โ‡’ boolean

Whether the input is a valid unidirectional edge

Returns: boolean - Whether the index is valid

Param Type Description
edgeIndex H3IndexInput H3 index of the edge

h3.directedEdgeToCells(edgeIndex) โ‡’ Array.<H3Index>

Get the [origin, destination] pair represented by a unidirectional edge

Returns: Array.<H3Index> - [origin, destination] pair as H3 indexes
Throws:

  • H3Error If the input is invalid
Param Type Description
edgeIndex H3IndexInput H3 index of the edge

h3.originToDirectedEdges(h3Index) โ‡’ Array.<H3Index>

Get all of the unidirectional edges with the given H3 index as the origin (i.e. an edge to every neighbor)

Returns: Array.<H3Index> - List of unidirectional edges
Throws:

  • H3Error If the input is invalid
Param Type Description
h3Index H3IndexInput H3 index of the origin hexagon

h3.directedEdgeToBoundary(edgeIndex, [formatAsGeoJson]) โ‡’ Array.<CoordPair>

Get the vertices of a given edge as an array of [lat, lng] points. Note that for edges that cross the edge of an icosahedron face, this may return 3 coordinates.

Returns: Array.<CoordPair> - Array of geo coordinate pairs
Throws:

  • H3Error If the input is invalid
Param Type Description
edgeIndex H3IndexInput H3 index of the edge
[formatAsGeoJson] boolean Whether to provide GeoJSON output: [lng, lat]

h3.gridDistance(origin, destination) โ‡’ number

Get the grid distance between two hex indexes. This function may fail to find the distance between two indexes if they are very far apart or on opposite sides of a pentagon.

Returns: number - Distance between hexagons
Throws:

  • H3Error If input is invalid or the distance could not be calculated
Param Type Description
origin H3IndexInput Origin hexagon index
destination H3IndexInput Destination hexagon index

h3.gridPathCells(origin, destination) โ‡’ Array.<H3Index>

Given two H3 indexes, return the line of indexes between them (inclusive).

This function may fail to find the line between two indexes, for example if they are very far apart. It may also fail when finding distances for indexes on opposite sides of a pentagon.

Notes:

  • The specific output of this function should not be considered stable across library versions. The only guarantees the library provides are that the line length will be h3Distance(start, end) + 1 and that every index in the line will be a neighbor of the preceding index.
  • Lines are drawn in grid space, and may not correspond exactly to either Cartesian lines or great arcs.

Returns: Array.<H3Index> - H3 indexes connecting origin and destination
Throws:

  • H3Error If input is invalid or the line cannot be calculated
Param Type Description
origin H3IndexInput Origin hexagon index
destination H3IndexInput Destination hexagon index

h3.cellToLocalIj(origin, destination) โ‡’ CoordIJ

Produces IJ coordinates for an H3 index anchored by an origin.

  • The coordinate space used by this function may have deleted regions or warping due to pentagonal distortion.
  • Coordinates are only comparable if they come from the same origin index.
  • Failure may occur if the index is too far away from the origin or if the index is on the other side of a pentagon.
  • This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.

Returns: CoordIJ - Coordinates as an {i, j} pair
Throws:

  • H3Error If the IJ coordinates cannot be calculated
Param Type Description
origin H3IndexInput Origin H3 index
destination H3IndexInput H3 index for which to find relative coordinates

h3.localIjToCell(origin, coords) โ‡’ H3Index

Produces an H3 index for IJ coordinates anchored by an origin.

  • The coordinate space used by this function may have deleted regions or warping due to pentagonal distortion.
  • Coordinates are only comparable if they come from the same origin index.
  • Failure may occur if the index is too far away from the origin or if the index is on the other side of a pentagon.
  • This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.

Returns: H3Index - H3 index at the relative coordinates
Throws:

  • H3Error If the H3 index cannot be calculated
Param Type Description
origin H3IndexInput Origin H3 index
coords CoordIJ Coordinates as an {i, j} pair

h3.greatCircleDistance(latLng1, latLng2, unit) โ‡’ number

Great circle distance between two geo points. This is not specific to H3, but is implemented in the library and provided here as a convenience.

Returns: number - Great circle distance
Throws:

  • H3Error If the unit is invalid
Param Type Description
latLng1 Array.<number> Origin coordinate as [lat, lng]
latLng2 Array.<number> Destination coordinate as [lat, lng]
unit string Distance unit (either UNITS.m, UNITS.km, or UNITS.rads)

h3.cellArea(h3Index, unit) โ‡’ number

Exact area of a given cell

Returns: number - Cell area
Throws:

  • H3Error If the input is invalid
Param Type Description
h3Index H3IndexInput H3 index of the hexagon to measure
unit string Distance unit (either UNITS.m2, UNITS.km2, or UNITS.rads2)

h3.edgeLength(edge, unit) โ‡’ number

Calculate length of a given unidirectional edge

Returns: number - Cell area
Throws:

  • H3Error If the input is invalid
Param Type Description
edge H3IndexInput H3 index of the edge to measure
unit string Distance unit (either UNITS.m, UNITS.km, or UNITS.rads)

h3.getHexagonAreaAvg(res, unit) โ‡’ number

Average hexagon area at a given resolution

Returns: number - Average area
Throws:

  • H3Error If the input is invalid
Param Type Description
res number Hexagon resolution
unit string Area unit (either UNITS.m2, UNITS.km2, or UNITS.rads2)

h3.getHexagonEdgeLengthAvg(res, unit) โ‡’ number

Average hexagon edge length at a given resolution

Returns: number - Average edge length
Throws:

  • H3Error If the input is invalid
Param Type Description
res number Hexagon resolution
unit string Distance unit (either UNITS.m, UNITS.km, or UNITS.rads)

h3.cellToVertex(h3Index, vertexNum) โ‡’ H3Index

Find the index for a vertex of a cell.

Returns: H3Index - Vertex index
Throws:

  • H3Error If the input is invalid
Param Type Description
h3Index H3IndexInput Cell to find the vertex for
vertexNum number Number (index) of the vertex to calculate

h3.cellToVertexes(h3Index) โ‡’ Array.<H3Index>

Find the indexes for all vertexes of a cell.

Returns: Array.<H3Index> - All vertex indexes of this cell
Throws:

  • H3Error If the input is invalid
Param Type Description
h3Index H3IndexInput Cell to find all vertexes for

h3.vertexToLatLng(h3Index) โ‡’ CoordPair

Get the lat, lng of a given vertex

Returns: CoordPair - Latitude, longitude coordinates of the vertex
Throws:

  • H3Error If the input is invalid
Param Type Description
h3Index H3IndexInput A vertex index

h3.isValidVertex(h3Index) โ‡’ boolean

Returns true if the input is a valid vertex index.

Returns: boolean - True if the index represents a vertex

Param Type Description
h3Index H3IndexInput An index to test for being a vertex index

h3.getNumCells(res) โ‡’ number

The total count of hexagons in the world at a given resolution. Note that above resolution 8 the exact count cannot be represented in a JavaScript 32-bit number, so consumers should use caution when applying further operations to the output.

Returns: number - Count
Throws:

  • H3Error If the resolution is invalid
Param Type Description
res number Hexagon resolution

h3.getRes0Cells() โ‡’ Array.<H3Index>

Get all H3 indexes at resolution 0. As every index at every resolution > 0 is the descendant of a res 0 index, this can be used with h3ToChildren to iterate over H3 indexes at any resolution.

Returns: Array.<H3Index> - All H3 indexes at res 0


h3.getPentagons(res) โ‡’ Array.<H3Index>

Get the twelve pentagon indexes at a given resolution.

Returns: Array.<H3Index> - All H3 pentagon indexes at res
Throws:

  • H3Error If the resolution is invalid
Param Type Description
res number Hexagon resolution

h3.degsToRads(deg) โ‡’ number

Convert degrees to radians

Returns: number - Value in radians

Param Type Description
deg number Value in degrees

h3.radsToDegs(rad) โ‡’ number

Convert radians to degrees

Returns: number - Value in degrees

Param Type Description
rad number Value in radians

h3.H3Index : string

64-bit hexidecimal string representation of an H3 index


h3.H3IndexInput : string | Array.<number>

64-bit hexidecimal string representation of an H3 index, or two 32-bit integers in little endian order in an array.


h3.CoordIJ

Coordinates as an {i, j} pair

Properties

Name Type
i number
j number

h3.H3Error

Custom JS Error instance with an attached error code. Error codes come from the core H3 library and can be found in the H3 docs.

Properties

Name Type
message string
code number

h3.CoordPair : Array.<number>

Pair of lat,lng coordinates (or lng,lat if GeoJSON output is specified)


h3.SplitLong : Array.<number>

Pair of lower,upper 32-bit ints representing a 64-bit value


Legacy API

H3 v4 renamed the majority of the functions in the library. To help ease migration from H3 v3 to H3 v4, we offer a legacy API wrapper at h3-js/legacy, which exports the v4 functions with the v3 names. Users are welcome to use the legacy API wrapper as a transitional support, but are encouraged to upgrade to the H3 v4 API as soon as possible.

Note that the legacy API is not 100% backwards compatible - it's a thin wrapper on top of the v4 functions, so in cases where behavior has changed, the v4 behavior will be used. In particular, many of the v4 functions will throw errors for invalid input, where v3 functions would return null.

Installation:

npm install h3-js

Usage:

import {geoToH3} from 'h3-js/legacy';

const h3Index = geoToH3(37.3615593, -122.0553238, 7);

Development

The h3-js library uses yarn as the preferred package manager. To install the dev dependencies, just run:

yarn

To lint the code:

yarn lint

To run the tests:

yarn test

Code must be formatted with prettier; unformatted code will fail the build. To format all files:

yarn prettier

Benchmarks

The h3-js library includes a basic benchmark suite using Benchmark.js. Because many of the functions may be called over thousands of hexagons in a "hot loop", performance is an important concern. Benchmarks are run against the transpiled ES5 code by default.

To run the benchmarks in Node:

yarn benchmark-node

To run the benchmarks in a browser:

yarn benchmark-browser

Sample Node output (Macbook Pro running Node 12):

isValidCell x 3,650,995 ops/sec ยฑ1.67% (87 runs sampled)
latLngToCell x 429,982 ops/sec ยฑ1.39% (86 runs sampled)
cellToLatLng x 1,161,867 ops/sec ยฑ1.11% (84 runs sampled)
cellToLatLng - integers x 1,555,791 ops/sec ยฑ1.29% (86 runs sampled)
cellToBoundary x 375,938 ops/sec ยฑ1.25% (87 runs sampled)
cellToBoundary - integers x 377,181 ops/sec ยฑ1.18% (85 runs sampled)
getIcosahedronFaces x 992,946 ops/sec ยฑ1.13% (85 runs sampled)
gridDisk x 194,400 ops/sec ยฑ1.16% (85 runs sampled)
polygonToCells_9 x 4,919 ops/sec ยฑ0.79% (87 runs sampled)
polygonToCells_11 x 368 ops/sec ยฑ0.76% (86 runs sampled)
polygonToCells_10ring x 76.88 ops/sec ยฑ0.57% (68 runs sampled)
cellsToMultiPolygon x 760 ops/sec ยฑ1.06% (86 runs sampled)
compactCells x 2,466 ops/sec ยฑ0.75% (86 runs sampled)
uncompactCells x 715 ops/sec ยฑ1.15% (85 runs sampled)
areNeighborCells x 1,073,086 ops/sec ยฑ1.56% (89 runs sampled)
cellsToDirectedEdge x 692,172 ops/sec ยฑ1.06% (86 runs sampled)
getDirectedEdgeOrigin x 995,390 ops/sec ยฑ1.60% (85 runs sampled)
getDirectedEdgeDestination x 930,473 ops/sec ยฑ1.11% (86 runs sampled)
isValidDirectedEdge x 3,505,407 ops/sec ยฑ1.05% (87 runs sampled)

When making code changes that may affect performance, please run benchmarks against master and then against your branch to identify any regressions.

Transpiling the C Source

The core library is transpiled using emscripten. The easiest way to build from source locally is by using Docker. Make sure Docker is installed, then:

yarn docker-boot
yarn build-emscripten

The build script uses the H3_VERSION file to determine the version of the core library to build. To use a different version of the library (e.g. to test local changes), clone the desired H3 repo to ./h3c and then run yarn docker-emscripten.

Contributing

Pull requests and Github issues are welcome. Please include tests for new work, and keep the library test coverage at 100%. Please note that the purpose of this module is to expose the API of the H3 Core library, so we will rarely accept new features that are not part of that API. New proposed feature work is more appropriate in the core C library or in a new JS library that depends on h3-js.

Before we can merge your changes, you must agree to the Uber Contributor License Agreement.

Versioning

The H3 core library adheres to Semantic Versioning. The h3-js library has a major.minor.patch version scheme. The major and minor version numbers of h3-js are the major and minor version of the bound core library, respectively. The patch version is incremented independently of the core library.

Legal and Licensing

The h3-js library is licensed under the Apache 2.0 License.

DGGRID Copyright (c) 2015 Southern Oregon University

h3-js's People

Contributors

4nthonylin avatar bhenhsi avatar dependabot[bot] avatar dfellis avatar felix-kaestner avatar isaacbrodsky avatar nrabinowitz avatar zachasme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h3-js's Issues

`polyfill` missing hexagons near pentagons

Demo: https://uber-common-public.s3-us-west-2.amazonaws.com/svc-vis-prototype/h3-grid/index.html

The app calls h3.polyfill to get hexagons that fill each OSM tile. The offending tiles here are

{
  "x": 87,
  "y": 153,
  "z": 8,
  "east": -56.25,
  "north": -33.13755119234615,
  "south": -34.30714385628804,
  "west": -57.65625,
}
{
  "x": 86,
  "y": 154,
  "z": 8,
  "east": -57.65625,
  "north": -34.30714385628804,
  "south": -35.4606699514953,
  "west": -59.0625,
}

Though the issue is observed at multiple zoom levels.

Bad indexation using h3Line

Hi,

I encounter an indexing problem when I want to index a polyline with the h3Line function.

You can see on the picture (below) that the polyline is not indexed correctly.
Some hexagon has the index of the line while it is not there and vice versa.

Is this a known problem of the h3Line function or an implementation problem?

Thank you for your help.
Below is the image and the code used.

indexation_line

function indexLinePetiteEchelle(req){  
    const layer = {};
    // This first piece of code creates the indexing for each node of the polyline.
    jsonDataLPE.features.forEach(feature => {
        const ind = [];
        for (let i = 0; i < feature.geometry.coordinates.length; i++) {
            const [lng, lat] = [feature.geometry.coordinates[i][0],feature.geometry.coordinates[i][1]];
            const stationIndex = h3.geoToH3(lat, lng, parseInt(req.body.resolution));
            const ring = h3.kRing(stationIndex, 1);
                ind.push(h3Index);
            );
        }
        // The second allows to create an indexation between point n and point n+1 of the polyline. (h3line)
        for(let i=0;i<ind.length-1;i++){
            const layerB = h3.h3Line(ind[i], ind[i+1]);
            layerB.forEach(h3Index => {
                layer[h3Index] = (layer[h3Index] || 0) + 1;
            });
        }
    });
    const geojsonLPE = geojson2h3.h3SetToFeatureCollection(
        Object.keys(layer),
        hex => ({value: layer[hex]})
    );
    return {indexGeoJson: geojsonLPE, hexes: layer};
}

Shape distortion while using compact

While using the compact feature to optimize a cluster of hexes at high resolution, I noticed the introduction of gaps into the cluster like so:
Screen Shot 2020-10-16 at 2 26 08 PM

I understand that these gaps are an expected distortion as a result of choosing hexagons as the preferred tessellation shape (as outlined in the H3 eng blog announcement). I was looking to understand more details about this tessellation algorithm and if its possible to close these gaps.

Perhaps, we could create a tangential compact function that slightly increases the area covered by these hexagons in order to fill these gaps? I understand this would cause more extensive overlaps, but in our use case that would be preferable to having gaps in the area.

Could you provide more details regarding this algorithm? Thanks! @nrabinowitz

Add Flow type definitions

Need to research best practices here - could export from the lib, or add directly to the flow-typed repo.

[issue] discrepency between h3-js and h3-transitional

I am trying to add h3 layer to kepler.gl by replaceing h3-transitional with h3-js
I am seeing different result calling h3ToGeo function

When using h3-transitional, the result is correct

id: 50042a8003a81, centroid: [37.60685873255048,-122.37792703211281]
id: 50042a5803a7f, centroid: [37.635939950070636,-122.39939748488374]
id: 5004295803a87, centroid: [37.79488052776275,-122.39819707999791]
id: 50042a6003a7f, centroid: [37.63064491937859,-122.39776868902631]
id: 5004296803a85, centroid: [37.78689467417056,-122.40828440667723]
id: 5004296003a85, centroid: [37.79218213227278,-122.40991607411941]
id: 5004296003a86, centroid: [37.79088770571817,-122.4032410194023]
id: 5004296803a84, centroid: [37.788188921714365,-122.41495905002361]
id: 5004296803a86, centroid: [37.78559998121372,-122.40160964134064]
id: 5004296803a83, centroid: [37.78948272367625,-122.42163357153376]

While using h3-js, it isn't and all of the centroid are the same

id: 50042a8003a81, centroid: [20.143053033363785,-130.35704768662526]
id: 50042a5803a7f, centroid: [20.143053033363785,-130.35704768662526]
id: 5004295803a87, centroid: [20.143053033363785,-130.35704768662526]
id: 50042a6003a7f, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296803a85, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296003a85, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296003a86, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296803a84, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296803a86, centroid: [20.143053033363785,-130.35704768662526]
id: 5004296803a83, centroid: [20.143053033363785,-130.35704768662526]

Is there something wrong with the address i am passing in?

Why is the node version limited to < 10?

The docs say it "can be used either in Node >= 4 or in the browser", but the package.json specifies node < 10.

"engines": {
    "node": ">=4 <10",

Just wondering if there's anything in the current version that breaks this library? or if the package.json is just being overly restrictive?

h3Distance

Any reason why h3Distance is not in the JS API?

npm audit vulnerabilities

Hi,

Just an FYI of vulnerabilities reported by npm. Seems like, as always its lodash, and extend.

found 3 vulnerabilities (1 moderate, 2 high) in 2278 scanned packages

Moderate Prototype Pollution
Package extend
Dependency of request
Path request > extend
More info https://npmjs.com/advisories/996

High Prototype Pollution
Package lodash
Dependency of cheerio
Path cheerio > lodash
More info https://npmjs.com/advisories/1065

High Prototype Pollution
Package lodash
Dependency of request-promise
Path request-promise > request-promise-core > lodash
More info https://npmjs.com/advisories/1065

Distortion of generated lat/lon polygon vertices

Hi,

Using the latest version, if I generate a cell around latitude 50ยบ North, I get the following coordinates:

-1.3219318484448281,50.768516534439534
-1.2914715984357399,50.77757400890455
-1.2658101799357302,50.75620946752976
-1.270599641666343,50.72577692057219
-1.301064224845246,50.71670684748162
-1.3267350166044807,50.738081918893414

which results in this plot:

Distorted_cell

The cell is not even drawn in the right location, this is a screenshot of a H3 viewer which plots the cells correctly and in the correct locations:

Correct_cells

I'm using OpenLayers, with the following code to generate the polygon vertices:

let h3Index = h3.geoToH3(lng, lat, 6);
let hexBoundary = h3.h3ToGeoBoundary(h3Index);
let polygon = new Polygon([hexBoundary]);
polygon.transform("EPSG:4326", "EPSG:3857"); // Transform to web mercator projection
hex = new Feature(polygon);

I have been digging through some code, have found a couple of other references online to this issue, which only provide "your polygons will get distorted at high latitudes". I get that, but not that distorted at 50ยบ North.

Integer value of h3Index

Hi,
I know that since Js does not support BigInteger this library is returning hex results as index, but is there any safe way to use BigInt object in js to handle these numbers? since in my case I need to manipulate the indexes.

[Question] How to efficiently query using H3

Hi!

I'm creating an app which shows nearby posts in a customizeable radius (with accuracy of ~100m). I've found h3 to be a very efficient library, but I couldn't quite figure out how to efficiently query my firestore NoSQL database using H3, since firestore is very limited in querying capabilities.

I've currently come up with this solution:

export async function loadNearbyPosts(coordinates: Coordinates, radius: number): Promise<Post[]> {
  const h3 = geoToH3(coordinates.latitude, coordinates.longitude, H3_RESOLUTION);
  console.log(`${JSON.stringify(coordinates)} -> ${h3}`);
  const neighbours = kRing(h3, 10); // <-- how do I convert my 'radius' in metres to the k-ring range ('10')?
  console.log(`Neighbours of ${h3} include: ${JSON.stringify(neighbours)}`);

  const batchedNeighbours: string[][] = [];
  for (let i = 0; i < neighbours.length; i += 10) batchedNeighbours.push(neighbours.splice(i, 10));

  console.log(`Batched to size of 10s: ${JSON.stringify(batchedNeighbours)}`);
  console.log(`Running ${batchedNeighbours.length} queries...`);

  const start = global.nativePerformanceNow();
  // how do I remove this batching and instead use range checks? something like `greater than this h3 and smaller than this h3`
  const queries = batchedNeighbours.map((n) => firestore().collection('posts').where('location.h3', 'in', n).get());
  const results = await Promise.all(queries);
  const end = global.nativePerformanceNow();

  const docs: Post[] = [];
  results.forEach((r) => docs.push(...r.docs.map((d) => build<Post>(d))));

  console.log(`Executed ${batchedNeighbours.length} queries and received ${docs.length} results, all within ${end - start}ms.`);
  return docs;
}

While this does indeed return results for me, it is very inefficient. For this simple query, it actually executes 17 queries (!!) because firestore has a limit of maximum 10 items in an array in the in query (that's why I'm batching the neighbours into arrays of 10 elements), and I'm comparing for exact matches, so I'm forced to using the same precision for all my h3 hexagons.

Using geohashes, I can find by range since they're alphabetically sorted. E.g. I can filter for bc -> bc~ which gives me all squares that start with bc.

Now let's get to my actual questions:

  1. Is it possible to "find by range" using h3, similar to geohashes? That way I can remove the batching code and don't have to run 17 queries for a simple "nearby" lookup. I couldn't really find a good explanation of the h3 algorithm on how the tiles are sorted, but if I could reduce it to some smaller amount of queries (e.g. everything in range 871e064d5ffffff -> 871e06498ffffff, plus everything in range of 871e0649bffffff -> 871e06509ffffff... or in other words "larger than this h3 but smaller than this h3")
  2. How can I actually convert a range in metres to k-ring/hex-ring ranges?

Thanks for your help!

h3ToGeoBoundary : documentation details

It seems h3ToGeoBoundary returns an array of vertices, that close the hexagon/pentagon/etc , i.e first and last vertices are same. When it is a hexagon it returns 7 vertices, where first and last are the same. It will be helpful to clarify this in the documentation.

h3IsValid returns true on invalid H3 indexes

Hi, I have noticed that h3IsValid will return true for many indexes that are not actually valid. For example:
h3IsValid("8a28308hello_world_ppppppppppppppppppqadjsadjasldajaskldlkjdklasjlk5505ffff")
Returns true even though the string is clearly invalid. I think this is due to the calls to parseInt() in the h3IndexToSplitLong method:

    if (typeof h3Index !== 'string') {
        return [0, 0];
    }
    const upper = parseInt(h3Index.substring(0, h3Index.length - 8), BASE_16);
    const lower = parseInt(h3Index.substring(h3Index.length - 8), BASE_16);
    return [lower, upper];
}

The first parseInt call will just ignore all of the extraneous characters in the middle of the string, only parsing "8a28308". This results in the above index being evaluated as equivalent to "8a283085505ffff".

Should check for error code from h3Line call

Hey @nrabinowitz

So h3-node currently (ab)uses h3-js for unit testing by just confirming that the outputs of both are identical given semi-random inputs.

I've noticed intermittent failures in the h3Line test, and after digging through the code, I think the issue might be on the h3-js side.

We can see in the declaration of the h3Line function that it returns an integer value.

/** @brief Line of h3 indexes connecting two indexes */
int H3_EXPORT(h3Line)(H3Index start, H3Index end, H3Index *out);

And in the documentation on the implementation that the return value is an error/success status code

 * @return 0 on success, or another value on failure.

So the h3-node implementation of binding h3Line includes a check for that status

  int errorCode = h3Line(origin, destination, line);
  if (errorCode != 0) {
    napi_throw_error(env, "EINVAL", "Line cannot be calculated");
    free(line);
    return NULL;
  }

But the h3-js implementation of binding h3Line ignores that status

function h3Line(origin, destination) {
    const [oLower, oUpper] = h3IndexToSplitLong(origin);
    const [dLower, dUpper] = h3IndexToSplitLong(destination);
    const count = H3.h3LineSize(oLower, oUpper, dLower, dUpper);
    if (count < 0) {
        // We can't get the specific error code here - may be any of
        // the errors possible in experimentalH3ToLocalIj
        throw new Error('Line cannot be calculated');
    }
    const hexagons = C._calloc(count, SZ_H3INDEX);
    H3.h3Line(oLower, oUpper, dLower, dUpper, hexagons); // << Not reading the return value
    const out = readArrayOfHexagons(hexagons, count);
    C._free(hexagons);
    return out;
}

I'd normally just make a PR to fix this, but since you implemented the C version of the code and the JS bindings, I wanted to bring this up before, in case this was actually intentional?

ES6 const as part of exported code

When installing this package vis npm, this line is imported containing the ES6 token const, which is breaking our build process in production, as uglifiers expect only ES5 code in node_modules.

const h3 = libh3();

Please replace const with var, to make this safely importable via npm.

Inconsistent results from polyfill after calling polyfill with complex polygon crossing antimeridian

It seems that calling polyfill with a complex polygon (that crosses the antimeridian) messes with the h3 internals somehow, causing subsequent calls to return incorrect results.

This is best demonstrated by this jsfiddle: https://jsfiddle.net/tamaxerra/kxz865m7/1/

The console output from the fiddle is the number of h3 indexes returned:

36
56
27

The first (36) and last (27) count are the result of the same polygon being passed.

UnhandledRejection

The package is listening all 'UnhandledRejection' errors and throwing it's own (h3-js) error from 'dist/hs-js.js', line: 10979 even if the source of the error is not h3-js package itself.

Is there a way to overwrite this 'UnhandledRejection' errors, what do you suggest?

Questions & Clarification on Coordinate Systems

A few questions & clarifications:

Unfortunately I do not have a background in mathematics, please be patient with me.


The gist of my use case is a geo-location based mobile game that uses a hexagonal grid to represent the world, something H3 appears to exactly solve for. Though, this use case necessitates the need to have a coordinate system that can uniquely identify each cell in the global grid for a variety of reasons. I am having a hard time figuring out how to obtain coordinates from the cells of an H3 grid.

H3 Coordinate Systems: https://h3geo.org/docs/core-library/coordsystems
Hexagonal Coordinate Systems: https://www.redblobgames.com/grids/hexagons/#coordinates

I marginally familiar three coordinate systems for hexagonal grids:

  • Offset Coordinates
  • Cube Coordinates (3 axes 120 degrees apart)
  • Axial Coordinates (Essentially cube coordinates sans an axis) [What I am aiming for here]

In the H3 docs, it mentions:

  • IJK Coordinates
    • This is noted as being the 3 coordinate axes spaced 120ยฐ apart which seems like a cube coordinate system. However the example picture's coordinates don't seem to line up with the expectation of i+j+k == 0.
    • What is this if not cube coordinates?
    • Are these globally unique?
    • How can this coordinate be obtained for a given H3Index?
  • FaceIJK Coordinates
    • Simply the IJK coordinates, but centered on each face. And I assume constrained to each face. Definitely not what I'm after.
  • Hex2d Coordinates.
    • [x,y] coordinates for the IJK coordinates with the +x axis aligned on i axis. This appears to be what I am looking for.
    • Are these essentially Axial Coordinates?
    • Is there a specific conversion expectation to go from IJK to Hex2d?
    • How can this coordinate be obtained for a given H3Index?
  • Local IJ Coordinates.
    • At first this looked promising, until I read local coordinates are only valid near the origin.. Which points out that these coordinates are really only valid within the same base cell.

TL;DR: How can I obtain cartesian coordinates for each cell that are globally unique?

3.6.2 polyfill breaking change from 3.5.0

We previously used the following to generate all hexes at zoom 0:

h3
  .polyfill([[-90, -180], [90, -180], [90, 0], [-90, 0]], 0)
  .concat(h3.polyfill([[-90, 180], [90, 180], [90, 0], [-90, 0]], 0))

When upgrading to 3.6.2 from 3.5.0, the above code returns an empty array.

Fusion build process fails to import h3-js correctly

"module": "dist/h3-js.es.js",

The fusionJS build process is misled by this line and will try to import dist/h3-js.es.js instead of dist/h3-js.js.

After that happens, webpack/babel transpile the module in a way that other modules will try to find the functions under h3Js.default.geoToH3, instead of the correct h3Js.geoToH3.

Changing this line locally to "module": "dist/h3-js.js" fixes my issue, but I'm wondering if that will break other projects instead.

If you need to know, I'm using the package @uber/h3-overlays, which imports @uber/h3-transitional, which in turn imports h3-js.

I would appreciate if you could take a look and shed some light whether we can change the module file or not.

h3.h3SetToMultiPolygon - Confusing return values

Hi

I am using h3 as means of generating a heatmap across a large map. Currently the drawing aspect is a little slow (many thousands of hexagons). So instead of drawing each hexagon separately I want to combine them using h3.h3SetToMultiPolygon.

I found it quite confusing to understand what the actual return is from this method. But I attempted to draw using the return value as if it were a list of polygons. When I try to draw these polygons it fills in large areas. Am I doing something wrong? Here is my code (typescript + google maps)

var megaPolygon = h3.h3SetToMultiPolygon(h3StringArray, false);

this.displayPolygons = [];

megaPolygon.forEach(polygon => {
    polygon.forEach(polygonLoop => {
        var newPath: ILatLngLiteral[] = [];

        polygonLoop.forEach(point => {
            newPath.push({
                latitude: point[0] as any,
                longitude: point[1] as any
            });
        });

        this.displayPolygons.push({
            id: this.displayPolygons.length,
            path: newPath,
            fill: {
                color: this.getHeatmapColor(0.7),
                opacity: 1
            },
            stroke: {
                weight: 0
            },
        });
    });
});

In these screenshots the top one is all individual hexagons, the bottom one is using h3.h3SetToMultiPolygon

Individual Hexes
image

MultiPolygon
image

If it helps, here is the raw data (as polylines)
image

Growing memory usage

Hi,

I'm using h3-js to compile isochrones (a few hundred millions), and I notices that the memory usage keep growing. After some quick investigations on my code to make sure the issue is not on my side, I think this comes from either h3SetToMultiPolygon or multiPolyfill (I investigate a while ago, and I can't remember). Anyway, after it does what it is supposed to do, a small amont of memory keep being used, and thus, after running it a couple of thousand times, node runs out of memory.
For now, as a quick dirty fix, I run it on child processes that I can restart once in a while.

Sorry for not providing more intels, I investigate this a while ago and found a quick workaround, but it still worth sharing the issue.

Note: i'm using 3.7.1

EDIT: version 3.7.1 was apparently supposed to fix this issue. I guess it's still there...

Misaligned polygons, not perfect hexagons. Some pentagons. Catering for projection

Hi,

Im trying to incorprate your library on a number of solutions which require realtime translations between hex ids and geojson multi/polygons.

h3.h3SetToMultiPolygon(["85291a6ffffffff"],true)

returns

[[[[-121.87310260648961,36.48355301296484],[-121.82059177712684,36.56646154014561],[-121.88144909358076,36.64149027277887],[-121.99481876336013,36.63355254199253],[-122.0471691328904,36.550641568925464],[-121.98631059624982,36.4756707384872],[-121.87310260648961,36.48355301296484]]]]

No problem with that. The issue however is displaying this now results in an askew/misrepresented polygon on a map.

image

The map is in EPSG:4326.
Geojson.io

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "color": "blue"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                -121.87310260648961,
                36.48355301296484
              ],
              [
                -121.82059177712684,
                36.56646154014561
              ],
              [
                -121.88144909358076,
                36.64149027277887
              ],
              [
                -121.99481876336013,
                36.63355254199253
              ],
              [
                -122.0471691328904,
                36.550641568925464
              ],
              [
                -121.98631059624982,
                36.4756707384872
              ],
              [
                -121.87310260648961,
                36.48355301296484
              ]
            ]
          ]
        ]
      }
    }
  ]
}

Is this correct?

TypeScript regression

#55 added auto-generated TypeScript types, but it seems like some of the functions (e.g. h3ToGeoBoundary) that return an array of arrays (i.e. Array[]) don't type-check properly in TypeScript, since the compiler expects the outer Array to have a type parameter:

* @return {Array[]} Array of [lat, lng] pairs

The fix is likely to specify the inner-most type explicitly (e.g. Number[][]) in the JSDoc.

Incorrect/weird results from h3SetToMultiPolygon

I'm getting some weird results from h3SetToMultiPolygon when passing large numbers of h3 indexes (in these examples the h3 cells are all adjacent). There are two issues:

  1. When the polygon array is returned there are a number of single point arrays. e.g.

h3Ids:
["8132fffffffffff","812e7ffffffffff","81303ffffffffff","815a3ffffffffff","814f7ffffffffff","81733ffffffffff","81687ffffffffff","814afffffffffff","8133bffffffffff","812f3ffffffffff","814e7ffffffffff","8130fffffffffff","815afffffffffff","8132bffffffffff","814bbffffffffff","812e3ffffffffff","81777ffffffffff","814f3ffffffffff","814abffffffffff","81337ffffffffff","812efffffffffff","814e3ffffffffff","815abffffffffff","81327ffffffffff","814b7ffffffffff","812fbffffffffff","81773ffffffffff","814efffffffffff","81317ffffffffff","815b7ffffffffff","814a7ffffffffff","81333ffffffffff","815a7ffffffffff","81737ffffffffff","81323ffffffffff","814fbffffffffff","814b3ffffffffff","812f7ffffffffff","814ebffffffffff","81313ffffffffff","815b3ffffffffff","814a3ffffffffff","8123bffffffffff","81237ffffffffff","81233ffffffffff","8147bffffffffff","8146fffffffffff","8146bffffffffff","81223ffffffffff","81463ffffffffff","81473ffffffffff","81477ffffffffff","81467ffffffffff","815dbffffffffff","815d3ffffffffff","815cbffffffffff","815c3ffffffffff","8137bffffffffff","815bbffffffffff","81373ffffffffff","8136bffffffffff","81363ffffffffff","8171bffffffffff","81717ffffffffff","81713ffffffffff"]

Gives this result:
[ [ [ [ 43.816094965537175, 142.3058437365082 ], [ 47.94353494620575, 140.81932027711576 ], [ 48.30438780776227, 137.965723000237 ], [ 48.41801789173907, 134.76393627595755 ], [ 45.253613490980094, 131.7744009814935 ], [ 45.09643436908035, 125.98114176677377 ], [ 47.997962809385406, 122.1525950681968 ], [ 47.30945130281312, 116.21289563713783 ], [ 43.25414167974314, 115.50113901102061 ], [ 41.14827082786993, 119.13690952882241 ], [ 38.614966776615006, 118.5828850895855 ], [ 37.42985448428109, 118.86929883406582 ], [ 36.20528264541884, 121.690153924224 ], [ 36.005614448071924, 123.16276457697893 ], [ 32.66144519495384, 124.02055612683286 ], [ 29.89298533869355, 120.503393859958 ], [ 26.20027606045547, 121.34751445935747 ], [ 24.728661050965936, 119.64146543031175 ], [ 23.50895195973631, 117.99047716641068 ], [ 19.252194904738655, 118.80300158646772 ], [ 18.127070267319834, 123.02355515221002 ], [ 13.797500809062361, 123.85482415801255 ], [ 10.736966167684393, 120.449366342475 ], [ 6.2891846753414375, 121.26764633911117 ], [ 4.76343118357537, 125.5023153387887 ], [ 7.805398745803346, 129.0449200915637 ], [ 6.19767652780886, 133.49441060685513 ], [ 9.23145267029969, 137.1970727246292 ], [ 7.537486471095007, 141.69432910913807 ], [ 10.472716898667054, 145.410940917621 ], [ 8.701739974658008, 149.7748737561887 ], [ 4.084015752678338, 150.44123001544202 ], [ 2.3920322085174597, 154.598935323174 ], [ 5.189055516512115, 158.0067643262748 ], [ 3.50810422466813, 161.8156148096885 ], [ 6.119591258608643, 164.93539603741024 ], [ 4.4670316097845255, 168.3352524578736 ], [ 4.467031609784517, 168.3352524578736 ], [ 6.172978893164634, 172.0341823693935 ], [ 4.248592317017831, 175.46041201203371 ], [ 5.8899217543139155, 179.21716082489448 ], [ 5.889921754313889, 179.21716082489448 ], [ 2.9040374505798128, -178.0251966524985 ], [ 3.821024494330419, -174.31673738369324 ], [ 7.972793830841406, -173.38014762578527 ], [ 9.060308038526605, -169.29312998396932 ], [ 5.767146686378422, -166.16940101623453 ], [ 6.766536253596447, -161.77338167921764 ], [ 3.3357348575173495, -158.59967491814012 ], [ 4.260374459536216, -154.0294052002189 ], [ 8.71898308656318, -152.5335322367957 ], [ 9.628747217956542, -147.80006555587835 ], [ 14.110797540904425, -146.16007687374923 ], [ 17.737530353545214, -149.3676428224656 ], [ 22.166939007405805, -147.69594788211106 ], [ 25.669243623986258, -151.04796662686522 ], [ 29.891830084602514, -149.34707529879068 ], [ 30.56995088296885, -144.17342232410294 ], [ 34.454167617014946, -142.3232078622538 ], [ 37.68759229063255, -145.7463690434673 ], [ 41.20828589932378, -143.84631120128412 ], [ 44.09362423911827, -147.45009391663316 ], [ 43.44325276436555, -153.03739182353246 ], [ 43.44325276436556, -153.03739182353243 ], [ 46.9088746957617, -156.03631344405528 ], [ 46.51349897531834, -161.56979335131368 ], [ 49.895974148750696, -165.61336675442524 ], [ 49.05085282910133, -171.87311046039585 ], [ 44.74985555511408, -173.25136162888563 ], [ 43.33462463706693, -179.170112546831 ], [ 46.18001465709014, 175.62099681678237 ], [ 44.17622039141846, 169.66101739290986 ], [ 46.48282657751592, 163.91021485526238 ], [ 43.912304017571394, 158.38289640953528 ], [ 45.62266462732751, 152.54480605394903 ], [ 42.63340688235615, 147.81728377284588 ] ] ], [ [ [ 27.949605976503907, 142.4332217566576 ] ] ], [ [ [ 34.33115860097916, 132.30837745804206 ] ] ], [ [ [ 12.194726726167971, 160.7733897026288 ] ] ] ]

The first polygon is accurate but the others are single points and seem unnecessary. Not a big deal as I can easily filter these out. This doesn't seem to happen at lower H3 resolutions.


  1. Occasionally I am only getting single point returns (i.e. no actual polygon).

For example with these h3 ids:
[ "816efffffffffff", "8126bffffffffff", "8148fffffffffff", "8113bffffffffff", "8122fffffffffff", "810c3ffffffffff", "8150bffffffffff", "815c3ffffffffff", "8126fffffffffff", "81493ffffffffff", "81363ffffffffff", "81457ffffffffff", "81233ffffffffff", "810c7ffffffffff", "8150fffffffffff", "815c7ffffffffff", "81273ffffffffff", "81497ffffffffff", "81367ffffffffff", "81237ffffffffff", "810cbffffffffff", "81513ffffffffff", "815cbffffffffff", "8149bffffffffff", "8136bffffffffff", "8123bffffffffff", "810cfffffffffff", "81517ffffffffff", "811c3ffffffffff", "815cfffffffffff", "816c3ffffffffff", "8127bffffffffff", "8136fffffffffff", "81463ffffffffff", "8151bffffffffff", "81703ffffffffff", "815d3ffffffffff", "81373ffffffffff", "81467ffffffffff", "811cbffffffffff", "81707ffffffffff", "815d7ffffffffff", "816cbffffffffff", "81283ffffffffff", "81377ffffffffff", "8146bffffffffff", "811cfffffffffff", "815dbffffffffff", "81287ffffffffff", "8137bffffffffff", "8146fffffffffff", "811d3ffffffffff", "816d3ffffffffff", "8128bffffffffff", "81473ffffffffff", "811d7ffffffffff", "81713ffffffffff", "8128fffffffffff", "81477ffffffffff", "81123ffffffffff", "811dbffffffffff", "81717ffffffffff", "816dbffffffffff", "81293ffffffffff", "8147bffffffffff", "81127ffffffffff", "81793ffffffffff", "810ebffffffffff", "8171bffffffffff", "81297ffffffffff", "81797ffffffffff", "8112bffffffffff", "816e3ffffffffff", "8129bffffffffff", "81483ffffffffff", "8179bffffffffff", "8112fffffffffff", "81447ffffffffff", "81223ffffffffff", "816e7ffffffffff", "81263ffffffffff", "81487ffffffffff", "81227ffffffffff", "81503ffffffffff", "816ebffffffffff", "81267ffffffffff", "8148bffffffffff", "81137ffffffffff", "8122bffffffffff", "81507ffffffffff", "815fbffffffffff", "814cbffffffffff", "812a7ffffffffff", "8139bffffffffff", "81453ffffffffff", "81677ffffffffff", "81547ffffffffff", "811b7ffffffffff", "812abffffffffff", "814cfffffffffff", "8167bffffffffff", "8154bffffffffff", "811bbffffffffff", "812afffffffffff", "814d3ffffffffff", "813a3ffffffffff", "8145bffffffffff", "8154fffffffffff", "812b3ffffffffff", "814d7ffffffffff", "81183ffffffffff", "813a7ffffffffff", "81277ffffffffff", "81553ffffffffff", "814dbffffffffff", "812b7ffffffffff", "81187ffffffffff", "813abffffffffff", "81557ffffffffff", "812bbffffffffff", "8118bffffffffff", "813afffffffffff", "816c7ffffffffff", "8155bffffffffff", "81743ffffffffff", "8118fffffffffff", "813b3ffffffffff", "8159bffffffffff", "81193ffffffffff", "813b7ffffffffff", "81563ffffffffff", "81197ffffffffff", "813bbffffffffff", "81067ffffffffff", "817c7ffffffffff", "81567ffffffffff", "81343ffffffffff", "810e3ffffffffff", "8119bffffffffff", "815e3ffffffffff", "816d7ffffffffff", "81383ffffffffff", "817cbffffffffff", "8156bffffffffff", "81347ffffffffff", "81753ffffffffff", "810e7ffffffffff", "815e7ffffffffff", "817cfffffffffff", "8156fffffffffff", "8134bffffffffff", "81663ffffffffff", "81757ffffffffff", "8180fffffffffff", "811a3ffffffffff", "815ebffffffffff", "8138bffffffffff", "8134fffffffffff", "81573ffffffffff", "81667ffffffffff", "81443ffffffffff", "8175bffffffffff", "810efffffffffff", "811a7ffffffffff", "815efffffffffff", "81077ffffffffff", "81353ffffffffff", "81577ffffffffff", "8166bffffffffff", "815f3ffffffffff", "811abffffffffff", "814c3ffffffffff", "81393ffffffffff", "81357ffffffffff", "8157bffffffffff", "8144bffffffffff", "810f7ffffffffff", "815f7ffffffffff", "811afffffffffff", "812a3ffffffffff", "8135bffffffffff", "8144fffffffffff", "81673ffffffffff", "81543ffffffffff", "811b3ffffffffff" ]

I get:
[ [ [ [ 43.44325276436555, -153.03739182353246 ] ] ], [ [ [ 14.48240061773311, -65.76882190787967 ] ] ], [ [ [ 19.358823435394214, -75.99854824376126 ] ] ], [ [ [ 8.931891500446854, -127.11406580207421 ] ] ], [ [ [ 59.16948256665965, -139.68359348160976 ] ] ], [ [ [ 40.975558199255886, -54.879012779249344 ] ] ], [ [ [ 31.285608665560563, -134.10648897177788 ] ] ], [ [ [ 29.30037465923499, 0.2609468260311339 ] ] ], [ [ [ 41.45713981733575, -138.450291223663 ] ] ], [ [ [ 29.82877615972559, -1.240802016513824 ] ] ], [ [ [ 31.877885956365837, -62.02252554784451 ] ] ], [ [ [ 11.545295975414758, -4.01399844347046 ] ] ] ]

i.e. no actual polygon, just a series of points โ€”ย seems like a bug?

Cannot use 'in' operator to search for 'toJSON'

I try to use polyfill on a country like CAN or RUS, but I get errros like:

Cannot use 'in' operator to search for 'toJSON' in abort(Assertion failed: adjacentFaceDir[tmpFijk.face][fijk.face] == KI, at: faceijk.c,581,_faceIjkPentToGeoBoundary). Build with -s ASSERTIONS=1 for more info.
Cannot use 'in' operator to search for 'toJSON' in abort(OOM). Build with -s ASSERTIONS=1 for more info.

Any idea on how to fix this?

2D Projection?

This lib is working fine but there's a (to be expected) distortion, is there a simple way to represent the hexagons in a flat 2D way?

Optimization question

Hi!

I'm just confused in how I can implement on a Uber-like system.

Let's say that I have my user geolocated and also I have his h3 index, if I want to find the nearest delivery man, I can do one of the following approaches:

First approach

  • Get the current h3 index where is located the user (resolution 8)
  • Search the database (that has h3 index set as the table index)
  • If no delivery mens are at that h3 index, search in its neighbors, and so on until I find one

can cost a lot

Second approach

  • Get the current h3 index of the user
  • Do an h3 radius lookup at resolution 8. The center is set on the user
  • Sort the results by nearest to farthest
  • If no delivery mens are found, the search radius in km is increased, until there's a delivery men that is near and has no jobs

i think this is the best approach

Third approach
???

Thank you so much for your time in advance!

h3js index find all children using index values

Hello,
Suppose we are storing h3 indexes in a database column. To perform a parent/child query I was thinking of using h3 indexes. Lets say we have this index 832834fffffffff. This cell's children are[ '8428341ffffffff', '8428343ffffffff', '8428345ffffffff', '8428347ffffffff', '8428349ffffffff', '842834bffffffff', '842834dffffffff']. What is the logic to tell if an h3index id is a child of another id. Is there any way that we can find a range of indexies that are child of the specific id.
I already found uber/h3#320 and https://stackoverflow.com/questions/53911322/is-the-h3index-ordered but could not find my answer.
Thanks

React-native won't compile because of the use of h3-js

importing h3-js this way import * as h3 from "h3-js";

would trigger the error below:

[Sat May 08 2021 16:50:27.116]  ERROR    Error: Requiring module "node_modules/h3-js/dist/browser/h3-js.js", which threw an exception: ReferenceError: Can't find variable: document
[Sat May 08 2021 16:50:27.132]  ERROR    ReferenceError: Can't find variable: document

I am wondering if this could be easily fixed? I am reading that there is a node version of h3-js, how can I import it instead of the browser version?

I tried to only import the function I was using at the time but I am still getting the same error

import {geoToH3} from 'h3-js';

I think the error is pointing to this code here in h3-js

  var readAsync;

  {
    if (document.currentScript) {
      scriptDirectory = document.currentScript.src;
    }

    if (scriptDirectory.indexOf("blob:") !== 0) {
      scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf("/") + 1);
    } else {
      scriptDirectory = "";
    }

Demo

I have already read the H3(written by c). From your work, I knew that there are a variety of different ways to render H3 hexagons on a map. But I don't know how to write an JavaScript program(html?) , can you give me a Demo?
Thank you very much! my email address:[email protected]

Polyfill glitching out over large areas bug?

Hi all,

I am attempting to use h3 to generate a GeoJSON polygon that I will then overlay on a mapbox map. When I try and polyfill(blue) a large square polygon(red) the resulting output gets really glitchy (see screenshots)

screen shot 2018-10-22 at 17 27 32

However when I halve the size of the red box, the polyfill works as intended?

screen shot 2018-10-22 at 17 28 13

const polygon = [
        [minLon, maxLat],
        [maxLon, maxLat],
        [maxLon, minLat],
        [minLon, minLat]
    ];
    const hexagons = h3.polyfill(polygon, 1, true);
    
    let hexFeatures = []
    for(let h of hexagons){
        let hexFeature = {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates': [h3.h3ToGeoBoundary(h, true)]
            }
        }
        hexFeatures.push(hexFeature)
    }

let hexGroup = {
        "id": "hex",
        "type": "fill",
        "source": {
            "type": "geojson",
            "data": {
                "type": "FeatureCollection",
                "features": hexFeatures
            }
        },
        'layout': {},
        'paint': {
            'fill-color': '#0000ff',
            'fill-opacity': 0.50
        }
    }


    map.addLayer(worldGroup)

Is this a possible bug?

Thanks

Hexagons with > 6 sides

h3ToGeoboundary can rarely create hexagons with > 6 sides.

Two examples of this behavior from different base cells: 85a60003fffffff, 859c7003fffffff.
See examples examples

can't find variable: document

I'm trying to us the h3-js library in a react-native app. I npm installed the library, and then when I just import h3 into one of my files, it gives me an error that say's can't find variable document. I'm assuming it is coming from the libh3.js file in "./dist/out" where it has the function....

var libh3 = (function() {
var _scriptDir = typeof document !== 'undefined' && dtocument.currentScript ? document.currentScript.src : undefined;
return (
........

I don't know where the problem is coming from but it's not in my code because I'm just trying to import h3-js

Typescript thinks UNITS is a type-only export

When I try to use h3.UNITS in a Typescript project, I see

'UNITS' only refers to a type, but is being used as a value here.

Probably need to change the way the types are formatted to export a constant.

Export the JS tutorials as plain Javascript

Extracting the h3 code from the Observables workbooks has been brutal. All my existing code uses jQuery so having just plain HTML, Javascript examples would save a lot of time

Visually mismatching parent hex

I encountered a situation where the h3ToParent function returns a hexagon that does not visually seem to be the parent of the original hexagon.

import { h3ToGeoBoundary, h3ToParent } from "h3-js";

const hexAtRes12 = "8c393362a49d5ff";
const parentHexAtRes6 = h3ToParent("8c393362a49d5ff", 6); // "86393362fffffff"

const polygonRes12 = h3ToGeoBoundary(hexAtRes12, true);
const polygonRes6 = h3ToGeoBoundary(parentHexAtRes6, true);

When rendering these polygons with mapbox gl we get:

image

I expected the neighbor hex to the bottom left of the yellow hex to be the parent hex of the green hex at resolution 12.

There are also examples the other way around. The res 12 hex "8c39336212687ff" is visually a child of the above res 6 hex "86393362fffffff" but in reality, the h3ToParent function returns "863933627ffffff" as parent at res 6.

Is this behaviour to be expected? If so, how can it be explained?

Allow integer input for H3 indexes

All current functions accept H3 indexes as strings, but we could potentially accept [int, int] as well - two 32-bit integers representing the 64-bit index, probably in [lower, upper] order to match the h3IndexToSplitLong output. This should offer slightly better performance by skipping the string-parsing step.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.