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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 1.0.5

- Upgrade vendored H3 C library from 4.4.1 → 4.5.0 ([upstream notes](https://github.com/uber/h3/releases/tag/v4.5.0))
- Add `reverseDirectedEdge` — returns a directed edge with origin and destination swapped (FFI + stub; throws `UnsupportedError` on web pending h3-js 4.5)
- `gridPathCells` is now bidirectional: `gridPathCells(a, b)` reversed equals `gridPathCells(b, a)` (H3 v4.5.0 behavior change)
- `cellsToLinkedMultiPolygon` / `cellsToMultiPolygon` now surface `E_CELL_INVALID`, `E_RES_MISMATCH`, and `E_DOMAIN` for invalid input, mixed resolutions, and duplicate cells (previously undefined output)
- Internal: refactored indexing (now uses `Vec3d`) and CoordIJK (now inlineable) from upstream — transparent to callers
- Regenerate FFI bindings against H3 v4.5.0 headers
- Refresh README badges and version references
- Expand pub.dev metadata: add `homepage`, `issue_tracker`, `documentation`, refined topics for better discoverability

## 1.0.4

- Switch h3-js CDN from jsDelivr to unpkg
Expand Down
2 changes: 1 addition & 1 deletion H3_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.4.1
4.5.0
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
[![pub package](https://img.shields.io/pub/v/h3_core.svg)](https://pub.dev/packages/h3_core)
[![CI](https://github.com/agnath18K/h3_core/actions/workflows/ci.yml/badge.svg)](https://github.com/agnath18K/h3_core/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![H3 Version](https://img.shields.io/badge/H3-v4.4.1-green.svg)](https://github.com/uber/h3/releases/tag/v4.4.1)
[![H3 Version](https://img.shields.io/badge/H3-v4.5.0-green.svg)](https://github.com/uber/h3/releases/tag/v4.5.0)

Dart/Flutter bindings for the [H3](https://h3geo.org) geospatial indexing library, originally developed at [Uber](https://github.com/uber/h3).

Wraps **H3 v4.4.1** via `dart:ffi` on native platforms and **h3-js** via `dart:js_interop` on web. Same API on all platforms.
Hexagonal geospatial indexing for Dart and Flutter — Uber's H3 via FFI on native and h3-js on web. Useful for mapping, GIS, spatial analytics, ride-sharing geofencing, and a geohash alternative.

Wraps **H3 v4.5.0** via `dart:ffi` on native platforms and **h3-js** via `dart:js_interop` on web. Same API on all platforms.

## Features

- Full H3 v4.4.1 API (~80 functions)
- Full H3 v4.5.0 API (~80 functions, including `reverseDirectedEdge`)
- Native: zero-overhead FFI calls via Build Hooks (compiles C natively — no pre-built binaries)
- Web: h3-js interop via `dart:js_interop`
- Single package, identical API on all platforms
Expand Down Expand Up @@ -116,7 +118,7 @@ Add the h3-js script tag to your `web/index.html` before the Flutter bootstrap:

## Versioning

Package version uses its own semver. Wraps H3 C library v4.4.1.
Package version uses its own semver. Wraps H3 C library v4.5.0.

## License

Expand Down
5 changes: 3 additions & 2 deletions ffigen.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
output: 'lib/src/generated/h3_bindings.g.dart'
name: 'H3C'
description: 'Auto-generated FFI bindings for H3 v4.4.1'
description: 'Auto-generated FFI bindings for H3 v4.5.0'

headers:
entry-points:
Expand Down Expand Up @@ -82,6 +82,7 @@ functions:
- 'directedEdgeToCells'
- 'originToDirectedEdges'
- 'directedEdgeToBoundary'
- 'reverseDirectedEdge'
- 'cellToVertex'
- 'cellToVertexes'
- 'vertexToLatLng'
Expand Down Expand Up @@ -141,5 +142,5 @@ sort: true

preamble: |
// AUTO-GENERATED by ffigen. Do not edit.
// H3 v4.4.1 — https://h3geo.org
// H3 v4.5.0 — https://h3geo.org
// ignore_for_file: type=lint
4 changes: 2 additions & 2 deletions hook/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import 'package:logging/logging.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';

const _h3VersionMajor = '4';
const _h3VersionMinor = '4';
const _h3VersionPatch = '1';
const _h3VersionMinor = '5';
const _h3VersionPatch = '0';

void main(List<String> args) async {
await build(args, (input, output) async {
Expand Down
21 changes: 10 additions & 11 deletions lib/src/generated/h3_bindings.g.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// AUTO-GENERATED by ffigen. Do not edit.
// H3 v4.4.1 — https://h3geo.org
// H3 v4.5.0 — https://h3geo.org
// ignore_for_file: type=lint

// AUTO GENERATED FILE, DO NOT EDIT.
Expand Down Expand Up @@ -150,7 +150,7 @@ external int cellsToDirectedEdge(
/// Functions for cellsToMultiPolygon (currently a binding-only concept)
/// @{
/// /
/// /** @brief Create a LinkedGeoPolygon from a set of contiguous hexagons
/// /** @brief Create a LinkedGeoPolygon from a set of cells
@ffi.Native<
H3Error Function(ffi.Pointer<H3Index>, ffi.Int, ffi.Pointer<LinkedGeoPolygon>)
>()
Expand Down Expand Up @@ -723,6 +723,14 @@ external double radsToDegs(double radians);
@ffi.Native<ffi.Int Function()>(isLeaf: true)
external int res0CellCount();

/// @defgroup reverseDirectedEdge reverseDirectedEdge
/// Functions for reverseDirectedEdge
/// @{
/// /
/// /** @brief Returns the directed edge with origin and destination cells reversed
@ffi.Native<H3Error Function(H3Index, ffi.Pointer<H3Index>)>()
external int reverseDirectedEdge(int edge, ffi.Pointer<H3Index> out);

/// @defgroup stringToH3 stringToH3
/// Functions for stringToH3
/// @{
Expand Down Expand Up @@ -832,15 +840,6 @@ final class GeoLoop extends ffi.Struct {
external ffi.Pointer<LatLng> verts;
}

/// @struct GeoMultiPolygon
/// @brief Simplified core of GeoJSON MultiPolygon coordinates definition
final class GeoMultiPolygon extends ffi.Struct {
@ffi.Int()
external int numPolygons;

external ffi.Pointer<GeoPolygon> polygons;
}

/// @struct GeoPolygon
/// @brief Simplified core of GeoJSON Polygon coordinates definition
final class GeoPolygon extends ffi.Struct {
Expand Down
19 changes: 15 additions & 4 deletions lib/src/h3_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,17 @@ List<H3Index> originToDirectedEdges(H3Index origin) {
});
}

/// Returns the directed edge with origin and destination swapped.
///
/// Since H3 v4.5.0.
H3Index reverseDirectedEdge(H3Index edge) {
return using((Arena arena) {
final out = arena<Uint64>();
checkH3Error(c.reverseDirectedEdge(edge.toInt(), out));
return H3Index.fromInt(out.value);
});
}

/// Returns the boundary vertices of the directed [edge].
CellBoundary directedEdgeToBoundary(H3Index edge) {
return using((Arena arena) {
Expand Down Expand Up @@ -750,19 +761,19 @@ List<H3Index> getPentagons(int resolution) {
/// Version constants for the h3_core package and the underlying H3 C library.
abstract final class H3Version {
/// The h3_core Dart package version.
static const String package = '1.0.1';
static const String package = '1.0.5';

/// The H3 C library version string.
static const String native = '4.4.1';
static const String native = '4.5.0';

/// The H3 C library major version.
static const int major = 4;

/// The H3 C library minor version.
static const int minor = 4;
static const int minor = 5;

/// The H3 C library patch version.
static const int patch = 1;
static const int patch = 0;
}

// Async — runs on isolate to keep the UI thread free.
Expand Down
13 changes: 9 additions & 4 deletions lib/src/h3_stub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ List<H3Index> originToDirectedEdges(H3Index origin) => _unsupported();
/// Returns the boundary vertices of the directed [edge].
CellBoundary directedEdgeToBoundary(H3Index edge) => _unsupported();

/// Returns the directed edge with origin and destination swapped.
///
/// Since H3 v4.5.0.
H3Index reverseDirectedEdge(H3Index edge) => _unsupported();

// Vertices

/// Returns the vertex at index [vertexNum] (0–5) of the [cell].
Expand Down Expand Up @@ -227,19 +232,19 @@ List<H3Index> getPentagons(int resolution) => _unsupported();
/// Version constants for the h3_core package and the underlying H3 C library.
abstract final class H3Version {
/// The h3_core Dart package version.
static const String package = '1.0.1';
static const String package = '1.0.5';

/// The H3 C library version string.
static const String native = '4.4.1';
static const String native = '4.5.0';

/// The H3 C library major version.
static const int major = 4;

/// The H3 C library minor version.
static const int minor = 4;
static const int minor = 5;

/// The H3 C library patch version.
static const int patch = 1;
static const int patch = 0;
}

// Async wrappers
Expand Down
20 changes: 16 additions & 4 deletions lib/src/h3_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,18 @@ CellBoundary directedEdgeToBoundary(H3Index edge) {
});
}

/// Returns the directed edge with origin and destination swapped.
///
/// Since H3 v4.5.0. h3-js does not yet expose this function (latest h3-js
/// is 4.4.0 at time of writing); calling this throws [UnsupportedError]
/// on web until h3-js 4.5 is published on npm.
H3Index reverseDirectedEdge(H3Index edge) {
throw UnsupportedError(
'reverseDirectedEdge requires h3-js >= 4.5.0, which is not yet '
'published on npm. Available on native via dart:ffi.',
);
}

// Vertices

/// Returns the vertex at index [vertexNum] (0–5) of the [cell].
Expand Down Expand Up @@ -582,19 +594,19 @@ List<H3Index> getPentagons(int resolution) {
/// Version constants for the h3_core package and the underlying H3 C library.
abstract final class H3Version {
/// The h3_core Dart package version.
static const String package = '1.0.1';
static const String package = '1.0.5';

/// The H3 C library version string.
static const String native = '4.4.1';
static const String native = '4.5.0';

/// The H3 C library major version.
static const int major = 4;

/// The H3 C library minor version.
static const int minor = 4;
static const int minor = 5;

/// The H3 C library patch version.
static const int patch = 1;
static const int patch = 0;
}

// Async — on web h3-js is sync, so these just wrap in a future.
Expand Down
11 changes: 7 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: h3_core
version: 1.0.4
version: 1.0.5
description: >-
Dart/Flutter bindings for the H3 geospatial indexing library.
Uses dart:ffi on native platforms, h3-js on web.
Dart/Flutter bindings for Uber's H3 hexagonal geospatial indexing library.
Uses dart:ffi on native platforms and h3-js on web — same API everywhere.
repository: https://github.com/agnath18K/h3_core
topics: [h3, geospatial, hexagonal, indexing, geo]
homepage: https://github.com/agnath18K/h3_core
issue_tracker: https://github.com/agnath18K/h3_core/issues
documentation: https://pub.dev/documentation/h3_core/latest/
topics: [h3, geospatial, ffi, mapping, hexagonal]

environment:
sdk: '>=3.10.0 <4.0.0'
Expand Down
67 changes: 67 additions & 0 deletions src/h3lib/include/adder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2025 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef ADDER_H
#define ADDER_H

/*
Header-only implementation of a "compensated summation" algorithm (Kahan
summation), which allows us to add up sequences of floating-point numbers
with better precision than naive summation, especially when the terms in
the sum vary significantly in magnitude.
See: https://en.wikipedia.org/wiki/Kahan_summation_algorithm

This is useful when computing the area of (multi)polygons, which
often involves adding many small terms to a large aggregate. For example,
D3 uses an improved accuracy summation when computing polygonal areas via its
`Adder` class:
https://github.com/d3/d3-geo/blob/main/src/area.js

There are a few potential algorithms we might consider for summation:

1. Naive sum
2. Kahan summation
3. Neumaier summation
4. Other approaches like pairwise summation, or Python's `fsum`

We considered the first three for simplicity, and settled on Kahan summation:
it achieves noticeably better accuracy than naive summation and almost as
good accuracy as Neumaier, while being only slightly slower than naive and
slightly faster and simpler than Neumaier.

See also: https://github.com/python/cpython/issues/100425 for discussion of
tradeoffs between Kahan, Neumaier, and `fsum`.

## Usage

Adder adder = {}; // initialize
kadd(&adder, x); // add x to summation
out = adder.sum; // extract final sum
*/

typedef struct {
double sum; // running total. public
double _c; // compensation term. private
} Adder;

static inline void kadd(Adder *adder, double x) {
double y = x - adder->_c;
double t = adder->sum + y;
adder->_c = (t - adder->sum) - y;
adder->sum = t;
}

#endif
9 changes: 0 additions & 9 deletions src/h3lib/include/algos.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#include "coordijk.h"
#include "h3api.h"
#include "linkedGeo.h"
#include "vertexGraph.h"

// neighbor along the ijk coordinate system of the current face, rotated
H3Error h3NeighborRotations(H3Index origin, Direction dir, int *rotations,
H3Index *out);
Expand All @@ -37,13 +35,6 @@ Direction directionForNeighbor(H3Index origin, H3Index destination);
void _kRingInternal(H3Index origin, int k, H3Index *out, int *distances,
int maxIdx, int curK);

// Create a vertex graph from a set of hexagons
H3Error h3SetToVertexGraph(const H3Index *h3Set, const int numHexes,
VertexGraph *out);

// Create a LinkedGeoPolygon from a vertex graph
void _vertexGraphToLinkedGeo(VertexGraph *graph, LinkedGeoPolygon *out);

// Internal function for polygonToCells that traces a geoloop with hexagons of
// a specific size
H3Error _getEdgeHexagons(const GeoLoop *geoloop, int64_t numHexagons, int res,
Expand Down
29 changes: 29 additions & 0 deletions src/h3lib/include/area.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2025 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file area.h
* @brief Area computation functions
*/

#ifndef AREA_H
#define AREA_H

#include "h3api.h"

H3Error geoLoopAreaRads2(GeoLoop loop, double *out);
H3Error geoPolygonAreaRads2(GeoPolygon poly, double *out);
H3Error geoMultiPolygonAreaRads2(GeoMultiPolygon mpoly, double *out);

#endif
Loading
Loading