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

add vertex mode functions #138

Merged
merged 5 commits into from
Jul 22, 2022
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
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
All notable changes to this project will be documented in this file. This library adheres to a versioning policy described in [the README](./README.md#versioning). The public API of this library consists of the functions exported in [h3core.js](./lib/h3core.js).

## [Unreleased]
### Added
- Added vertex mode functions (#138)
### Breaking Changes
- Updated the core library to `v4.0.0-rc2`. This update renames the majority of the H3 functions. You can see a [list of changed function names](https://h3geo.org/docs/next/library/migration-3.x/functions) in the core library documentation. For the most part, upgrading to v4 for Javascript consumers should be a straightforward search & replace between the old names and the new.
- Added more cases in which JS errors may be thrown. In H3 v3, many functions would fail silently with invalid input, returning `null` or similar signal values. In H3 v4, we will throw descriptive errors for most instances of bad input.
- Updated the core library to `v4.0.0-rc2`. This update renames the majority of the H3 functions. You can see a [list of changed function names](https://h3geo.org/docs/next/library/migration-3.x/functions) in the core library documentation. For the most part, upgrading to v4 for Javascript consumers should be a straightforward search & replace between the old names and the new. (#139)
- Added more cases in which JS errors may be thrown. In H3 v3, many functions would fail silently with invalid input, returning `null` or similar signal values. In H3 v4, we will throw descriptive errors for most instances of bad input. (#139)
Copy link
Collaborator

Choose a reason for hiding this comment

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

🙏


## [3.7.2] - 2021-04-29
### Fixed
Expand Down
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Coverage Status](https://coveralls.io/repos/github/uber/h3-js/badge.svg?branch=master)](https://coveralls.io/github/uber/h3-js?branch=master)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![npm version](https://badge.fury.io/js/h3-js.svg)](https://badge.fury.io/js/h3-js)
[![H3 Version](https://img.shields.io/badge/h3_api-v4.0.0-rc2-blue.svg)](https://github.com/uber/h3/releases/tag/v4.0.0-rc2)
[![H3 Version](https://img.shields.io/static/v1?label=h3%20api&message=v4.0.0-rc2&color=blue)](https://github.com/uber/h3/releases/tag/v4.0.0-rc2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good catch, thanks


The `h3-js` library provides a pure-JavaScript version of the [H3 Core Library](https://github.com/uber/h3), 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](http://kripken.github.io/emscripten-site), offering full parity with the C API and highly efficient operations.

Expand Down Expand Up @@ -135,6 +135,10 @@ const coordinates = h3.cellsToMultiPolygon(hexagons, true);
* [.exactEdgeLength(edge, unit)](#module_h3.exactEdgeLength) ⇒ <code>number</code>
* [.getHexagonAreaAvg(res, unit)](#module_h3.getHexagonAreaAvg) ⇒ <code>number</code>
* [.getHexagonEdgeLengthAvg(res, unit)](#module_h3.getHexagonEdgeLengthAvg) ⇒ <code>number</code>
* [.cellToVertex(h3Index, vertexNum)](#module_h3.cellToVertex) ⇒ <code>H3Index</code>
* [.cellToVertexes(h3Index)](#module_h3.cellToVertexes) ⇒ <code>Array.&lt;H3Index&gt;</code>
* [.vertexToLatLng(h3Index)](#module_h3.vertexToLatLng) ⇒ <code>Array.&lt;number&gt;</code>
* [.isValidVertex(h3Index)](#module_h3.isValidVertex) ⇒ <code>boolean</code>
* [.getNumCells(res)](#module_h3.getNumCells) ⇒ <code>number</code>
* [.getRes0Cells()](#module_h3.getRes0Cells) ⇒ <code>Array.&lt;H3Index&gt;</code>
* [.getPentagons(res)](#module_h3.getPentagons) ⇒ <code>Array.&lt;H3Index&gt;</code>
Expand Down Expand Up @@ -794,6 +798,63 @@ Average hexagon edge length at a given resolution
| unit | <code>string</code> | Distance unit (either UNITS.m, UNITS.km, or UNITS.rads) |


* * *

<a name="module_h3.cellToVertex"></a>

### h3.cellToVertex(h3Index, vertexNum) ⇒ <code>H3Index</code>
Find the index for a vertex of a cell.

**Returns**: <code>H3Index</code> - Vertex index

| Param | Type | Description |
| --- | --- | --- |
| h3Index | <code>H3IndexInput</code> | Cell to find the vertex for |
| vertexNum | <code>number</code> | Number (index) of the vertex to calculate |


* * *

<a name="module_h3.cellToVertexes"></a>

### h3.cellToVertexes(h3Index) ⇒ <code>Array.&lt;H3Index&gt;</code>
Find the indexes for all vertexes of a cell.

**Returns**: <code>Array.&lt;H3Index&gt;</code> - All vertex indexes of this cell

| Param | Type | Description |
| --- | --- | --- |
| h3Index | <code>H3IndexInput</code> | Cell to find all vertexes for |


* * *

<a name="module_h3.vertexToLatLng"></a>

### h3.vertexToLatLng(h3Index) ⇒ <code>Array.&lt;number&gt;</code>
Get the lat, lng of a given vertex

**Returns**: <code>Array.&lt;number&gt;</code> - Latitude, longitude coordinates of the vertex

| Param | Type | Description |
| --- | --- | --- |
| h3Index | <code>H3IndexInput</code> | A vertex index |


* * *

<a name="module_h3.isValidVertex"></a>

### h3.isValidVertex(h3Index) ⇒ <code>boolean</code>
Returns true if the input is a valid vertex index.

**Returns**: <code>boolean</code> - True if the index represents a vertex

| Param | Type | Description |
| --- | --- | --- |
| h3Index | <code>H3IndexInput</code> | An index to test for being a vertex index |


* * *

<a name="module_h3.getNumCells"></a>
Expand Down
2 changes: 1 addition & 1 deletion doc-files/README.tmpl.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Coverage Status](https://coveralls.io/repos/github/uber/h3-js/badge.svg?branch=master)](https://coveralls.io/github/uber/h3-js?branch=master)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![npm version](https://badge.fury.io/js/h3-js.svg)](https://badge.fury.io/js/h3-js)
[![H3 Version](https://img.shields.io/badge/h3_api-v4.0.0-rc2-blue.svg)](https://github.com/uber/h3/releases/tag/v4.0.0-rc2)
[![H3 Version](https://img.shields.io/static/v1?label=h3%20api&message=v4.0.0-rc2&color=blue)](https://github.com/uber/h3/releases/tag/v4.0.0-rc2)

The `h3-js` library provides a pure-JavaScript version of the [H3 Core Library](https://github.com/uber/h3), 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](http://kripken.github.io/emscripten-site), offering full parity with the C API and highly efficient operations.

Expand Down
6 changes: 5 additions & 1 deletion lib/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,9 @@ export default [
['getRes0Cells', H3_ERROR, [POINTER]],
['res0CellCount', NUMBER],
['getPentagons', H3_ERROR, [NUMBER, POINTER]],
['pentagonCount', NUMBER]
['pentagonCount', NUMBER],
['cellToVertex', H3_ERROR, [H3_LOWER, H3_UPPER, NUMBER, POINTER]],
['cellToVertexes', H3_ERROR, [H3_LOWER, H3_UPPER, POINTER]],
['vertexToLatLng', H3_ERROR, [H3_LOWER, H3_UPPER, POINTER]],
['isValidVertex', BOOLEAN, [H3_LOWER, H3_UPPER]]
];
69 changes: 68 additions & 1 deletion lib/h3core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ export function uncompactCells(compactedSet, res) {
}

// ----------------------------------------------------------------------------
// Public API functions: Unidirectional edges
// Public API functions: Directed edges

/**
* Whether two H3 indexes are neighbors (share an edge)
Expand Down Expand Up @@ -1443,6 +1443,73 @@ export function getHexagonEdgeLengthAvg(res, unit) {
}
}

// ----------------------------------------------------------------------------
// Public API functions: Vertex mode

/**
* Find the index for a vertex of a cell.
* @static
* @param {H3IndexInput} h3Index Cell to find the vertex for
* @param {number} vertexNum Number (index) of the vertex to calculate
* @return {H3Index} Vertex index
*/
export function cellToVertex(h3Index, vertexNum) {
const [lower, upper] = h3IndexToSplitLong(h3Index);
const vertexIndex = C._malloc(SZ_H3INDEX);
try {
throwIfError(H3.cellToVertex(lower, upper, vertexNum, vertexIndex));
return readH3IndexFromPointer(vertexIndex);
} finally {
C._free(vertexIndex);
}
}

/**
* Find the indexes for all vertexes of a cell.
* @static
* @param {H3IndexInput} h3Index Cell to find all vertexes for
* @return {H3Index[]} All vertex indexes of this cell
*/
export function cellToVertexes(h3Index) {
const [lower, upper] = h3IndexToSplitLong(h3Index);
const maxNumVertexes = 6;
const vertexIndexes = C._calloc(maxNumVertexes, SZ_H3INDEX);
try {
throwIfError(H3.cellToVertexes(lower, upper, vertexIndexes));
return readArrayOfH3Indexes(vertexIndexes, maxNumVertexes);
} finally {
C._free(vertexIndexes);
}
}

/**
* Get the lat, lng of a given vertex
* @static
* @param {H3IndexInput} h3Index A vertex index
* @returns {number[]} Latitude, longitude coordinates of the vertex
*/
export function vertexToLatLng(h3Index) {
const latlng = C._malloc(SZ_LATLNG);
const [lower, upper] = h3IndexToSplitLong(h3Index);
try {
throwIfError(H3.vertexToLatLng(lower, upper, latlng));
return readLatLng(latlng);
} finally {
C._free(latlng);
}
}

/**
* Returns true if the input is a valid vertex index.
* @static
* @param {H3IndexInput} h3Index An index to test for being a vertex index
* @returns {boolean} True if the index represents a vertex
*/
export function isValidVertex(h3Index) {
const [lower, upper] = h3IndexToSplitLong(h3Index);
return Boolean(H3.isValidVertex(lower, upper));
}

// ----------------------------------------------------------------------------
// Public informational utilities

Expand Down
10 changes: 5 additions & 5 deletions out/libh3.js

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions test/h3core.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1977,3 +1977,98 @@ test('getPentagons - invalid', assert => {
assert.throws(() => h3.getPentagons(42), {code: E_RES_DOMAIN}, 'throws on invalid resolution');
assert.end();
});

test('cellToVertex - invalid', assert => {
assert.throws(
() => h3.cellToVertex('823d6ffffffffff', -1),
{code: E_DOMAIN},
'negative vertex number throws'
);
assert.throws(
() => h3.cellToVertex('823d6ffffffffff', 6),
{code: E_DOMAIN},
'out of range vertex number throws'
);
assert.throws(
() => h3.cellToVertex('823007fffffffff', 5),
{code: E_DOMAIN},
'out of range vertex number for pentagon throws'
);
assert.throws(
() => h3.cellToVertex('ffffffffffffffff', 5),
{code: E_FAILED},
'invalid cell throws'
);
assert.end();
});

test('isValidVertex', assert => {
assert.equal(h3.isValidVertex('FFFFFFFFFFFFFFFF'), false, 'all 1 is not a vertex');
assert.equal(h3.isValidVertex('0'), false, 'all 0 is not a vertex');
assert.equal(h3.isValidVertex('823d6ffffffffff'), false, 'cell is not a vertex');
assert.equal(h3.isValidVertex('2222597fffffffff'), true, 'vertex index is a vertex');
assert.end();
});

test('cellToVertexes', assert => {
const origin = '823d6ffffffffff';
const verts = h3.cellToVertexes(origin);
assert.equal(verts.length, 6, 'vertexes have expected length');
for (let i = 0; i < 6; i++) {
const vert = h3.cellToVertex(origin, i);
assert.ok(verts.includes(vert), 'cellToVertexes is exhaustive');
assert.ok(h3.isValidVertex(vert), 'cellToVertexes returns valid vertexes');
}
assert.end();
});

test('cellToVertexes pentagon', assert => {
const origin = '823007fffffffff';
const verts = h3.cellToVertexes(origin);
assert.equal(verts.length, 5, 'vertexes have expected length');
for (let i = 0; i < 5; i++) {
const vert = h3.cellToVertex(origin, i);
assert.ok(verts.includes(vert), 'cellToVertexes is exhaustive');
assert.ok(h3.isValidVertex(vert), 'cellToVertexes returns valid vertexes');
}
assert.end();
});

test('cellToVertex', assert => {
const origin = '823d6ffffffffff';
const verts = new Set();
for (let i = 0; i < 6; i++) {
const vert = h3.cellToVertex(origin, i);
assert.ok(h3.isValidVertex(vert));
verts.add(vert);
}
assert.equal(verts.size, 6, 'vertexes are unique');
assert.end();
});

test('vertexToLatLng', assert => {
const origin = '823d6ffffffffff';
const bounds = h3.cellToBoundary(origin);
for (let i = 0; i < 6; i++) {
const vert = h3.cellToVertex(origin, i);
const latlng = h3.vertexToLatLng(vert);
let found = false;
for (let j = 0; j < bounds.length; j++) {
if (almostEqual(latlng[0], bounds[j][0]) && almostEqual(latlng[1], bounds[j][1])) {
found = true;
break;
}
}
assert.ok(found, 'vertex latlng is present in cell bounds');
}
assert.end();
});

test('vertexToLatLng - invalid', assert => {
assert.throws(
() => h3.vertexToLatLng('ffffffffffffffff'),
{code: E_CELL_INVALID},
'invalid vertex throws'
);
assert.end();
});
5 changes: 0 additions & 5 deletions test/test-parity.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ const BINDING_FUNCTIONS = fs
const EXCLUDE_METHODS = [
'h3ToString',
'stringToH3',
// TODO: Vertex functions are not yet supported in JS
'isValidVertex',
'vertexToLatLng',
'cellToVertexes',
'cellToVertex',
// TODO: Unnecessary when https://github.com/uber/h3/pull/622 is released
'distance'
];
Expand Down