Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
fef1bd3
Geodesic coverage
holoskii Oct 3, 2025
ebda843
AUDIT_SOURCE_FILE_LIST
holoskii Oct 6, 2025
356c6d0
Remove H3_EXPORT where not needed
holoskii Oct 6, 2025
fdae2ee
Move internal header to include dir
holoskii Oct 22, 2025
a0c04b3
GeodesicCellBoundary to separate header
holoskii Oct 22, 2025
66cd77a
Attempt to fix MSVC compilation
holoskii Oct 22, 2025
0854cd5
GeodesicPolygon * instead of void *
holoskii Oct 22, 2025
d5b6a4a
Introduce epsilon for SphereCap check
holoskii Oct 22, 2025
502b7ac
sphereCapTables.h to include dir
holoskii Oct 24, 2025
f5eed3e
Add new benchmark
holoskii Oct 24, 2025
264171f
Audit src file list
holoskii Oct 24, 2025
a60688f
Fix compilation: move helper function outside benchmark
holoskii Oct 29, 2025
43609f5
Keep h3api.h free of non-standart includes
holoskii Oct 31, 2025
9938d9a
Slim down geodesic fuzzer
holoskii Oct 31, 2025
411e9e1
Separate geodesic fuzzer
holoskii Nov 3, 2025
2afdb4f
clang-format
holoskii Feb 13, 2026
a751efd
Address comments:
holoskii Feb 13, 2026
a372c6c
Fix errors:
holoskii Feb 13, 2026
c0d1afb
Fix website documentation
holoskii Feb 13, 2026
cbd9f7c
Make sure maxCells will not underflow
holoskii Feb 13, 2026
1a72e65
Fix and document edge cases of polygons and centroids
holoskii Feb 13, 2026
89b8331
Rebase fixes
holoskii Feb 13, 2026
17a6155
Address comments:
holoskii Feb 13, 2026
ba6c5d3
numVerts -> numEdges
holoskii Feb 13, 2026
21715e3
vec3dToCell -> vec3ToCell
holoskii Feb 13, 2026
9ad5817
latLngToVec3 - modify struct by pointer, do not return
holoskii Feb 13, 2026
ca00cf4
Properly format with clang-format-14
holoskii Feb 13, 2026
5cb4d30
Check inputs before creating geodesic polygons. Don't acceps NaN
holoskii Feb 14, 2026
807ff77
Fix geodesic polyfill missing cells whose boundary coincides with pol…
holoskii Mar 12, 2026
a08529f
Reject polygons that does not fit within hemisphere upfront
holoskii Mar 12, 2026
8d30abc
Add support for CENTER containment mode in geodesic path
holoskii Mar 12, 2026
9e387ee
More efficient geodesic processing
holoskii Mar 12, 2026
0165b4a
Add tests to increase test coverage
holoskii Mar 13, 2026
b4bec09
Only accept polygons with >= 3 vertex
holoskii Mar 13, 2026
0739208
Fix CCW vs CW issues
holoskii Mar 13, 2026
9a5d8cf
Fix hole logic in geodesic polyfill
holoskii Mar 13, 2026
38293ec
Add more tests for geodesic cells
holoskii Mar 13, 2026
f842e84
Fix rebase error
holoskii Mar 13, 2026
fb857a1
Fix Coverage build failure in CI
holoskii Mar 14, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The public API of this library consists of the functions declared in file
### Added
- `reverseDirectedEdge` function (#1098)
- (internal) `geoLoopArea` function (#1101)
- Geodesic coverage flag for `polygonToCellsExperimental` that follows great-circle edges when covering very large polygons. This mode is significantly slower than the planar algorithm, so prefer lower resolutions when using it.

### Changed
- `cellAreaRads2` uses `geoLoopArea` (#1101)
Expand Down
21 changes: 20 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ set(LIB_SOURCE_FILES
src/h3lib/include/adder.h
src/h3lib/include/area.h
src/h3lib/include/cellsToMultiPoly.h
src/h3lib/include/polyfillIterator.h
src/h3lib/include/geodesicIterator.h
src/h3lib/include/geodesicPolygonInternal.h
src/h3lib/include/geodesicCellBoundary.h
src/h3lib/include/sphereCapTables.h
src/h3lib/lib/h3Assert.c
src/h3lib/lib/algos.c
src/h3lib/lib/coordijk.c
Expand All @@ -193,7 +198,9 @@ set(LIB_SOURCE_FILES
src/h3lib/lib/faceijk.c
src/h3lib/lib/baseCells.c
src/h3lib/lib/area.c
src/h3lib/lib/cellsToMultiPoly.c)
src/h3lib/lib/cellsToMultiPoly.c
src/h3lib/lib/geodesicIterator.c
src/h3lib/lib/geodesicPolygon.c)
set(APP_SOURCE_FILES
src/apps/applib/include/kml.h
src/apps/applib/include/benchmark.h
Expand Down Expand Up @@ -226,6 +233,10 @@ set(OTHER_SOURCE_FILES
src/apps/testapps/testPolygonToCellsExperimental.c
src/apps/testapps/testPolygonToCellsReported.c
src/apps/testapps/testPolygonToCellsReportedExperimental.c
src/apps/testapps/testGeodesicPolygonInternal.c
src/apps/testapps/testGeodesicPolygonToCellsExperimental.c
src/apps/testapps/testGeodesicCoverage.c
src/apps/testapps/testGeodesicGridDiskRoundtrip.c
src/apps/testapps/testPentagonIndexes.c
src/apps/testapps/testGridDisk.c
src/apps/testapps/testGridDiskInternal.c
Expand All @@ -247,6 +258,7 @@ set(OTHER_SOURCE_FILES
src/apps/testapps/testGetIcosahedronFaces.c
src/apps/testapps/testLatLng.c
src/apps/testapps/testLatLngInternal.c
src/apps/testapps/testVec3d.c
src/apps/testapps/testGridRing.c
src/apps/testapps/testGridRingInternal.c
src/apps/testapps/testGridRingUnsafe.c
Expand Down Expand Up @@ -287,6 +299,7 @@ set(OTHER_SOURCE_FILES
src/apps/testapps/testMathExtensionsInternal.c
src/apps/testapps/testDescribeH3Error.c
src/apps/testapps/testGeoLoopArea.c
src/apps/testapps/testSphereCap.c
src/apps/miscapps/cellToBoundaryHier.c
src/apps/miscapps/cellToLatLngHier.c
src/apps/miscapps/generateBaseCellNeighbors.c
Expand All @@ -312,13 +325,15 @@ set(OTHER_SOURCE_FILES
src/apps/fuzzers/fuzzerLocalIj.c
src/apps/fuzzers/fuzzerPolygonToCells.c
src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalGeodesic.c
src/apps/fuzzers/fuzzerPolygonToCellsNoHoles.c
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalNoHoles.c
src/apps/fuzzers/fuzzerCellToChildPos.c
src/apps/fuzzers/fuzzerInternalAlgos.c
src/apps/fuzzers/fuzzerInternalCoordIjk.c
src/apps/benchmarks/benchmarkPolygonToCells.c
src/apps/benchmarks/benchmarkPolygonToCellsExperimental.c
src/apps/benchmarks/benchmarkPolygonToCellsExperimentalGeodesic.c
src/apps/benchmarks/benchmarkPolygon.c
src/apps/benchmarks/benchmarkCellsToPolyAlgos.c
src/apps/benchmarks/benchmarkCellToChildren.c
Expand Down Expand Up @@ -643,6 +658,8 @@ if(BUILD_FUZZERS)
add_h3_fuzzer(fuzzerPolygonToCells src/apps/fuzzers/fuzzerPolygonToCells.c)
add_h3_fuzzer(fuzzerPolygonToCellsExperimental
src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c)
add_h3_fuzzer(fuzzerPolygonToCellsExperimentalGeodesic
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalGeodesic.c)
add_h3_fuzzer(fuzzerPolygonToCellsNoHoles
src/apps/fuzzers/fuzzerPolygonToCellsNoHoles.c)
add_h3_fuzzer(fuzzerPolygonToCellsExperimentalNoHoles
Expand Down Expand Up @@ -687,6 +704,8 @@ if(BUILD_BENCHMARKS)
src/apps/benchmarks/benchmarkPolygonToCellsExperimental.c)
add_h3_benchmark(benchmarkArea
src/apps/benchmarks/benchmarkArea.c)
add_h3_benchmark(benchmarkPolygonToCellsExperimentalGeodesic
src/apps/benchmarks/benchmarkPolygonToCellsExperimentalGeodesic.c)
if(ENABLE_REQUIRES_ALL_SYMBOLS)
add_h3_benchmark(benchmarkPolygon
src/apps/benchmarks/benchmarkPolygon.c)
Expand Down
7 changes: 7 additions & 0 deletions CMakeTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ add_h3_test(testPolygonInternal src/apps/testapps/testPolygonInternal.c)
add_h3_test(testPolyfillInternal src/apps/testapps/testPolyfillInternal.c)
add_h3_test(testVec2dInternal src/apps/testapps/testVec2dInternal.c)
add_h3_test(testVec3dInternal src/apps/testapps/testVec3dInternal.c)
add_h3_test(testVec3d src/apps/testapps/testVec3d.c)
add_h3_test(testCellToLocalIj src/apps/testapps/testCellToLocalIj.c)
add_h3_test(testCellToLocalIjInternal
src/apps/testapps/testCellToLocalIjInternal.c)
Expand All @@ -271,6 +272,12 @@ add_h3_test_with_arg(testH3NeighborRotations
add_h3_test_with_arg(testH3NeighborRotations
src/apps/testapps/testH3NeighborRotations.c 2)

add_h3_test(testGeodesicPolygonToCellsExperimental src/apps/testapps/testGeodesicPolygonToCellsExperimental.c)
add_h3_test(testGeodesicPolygonInternal src/apps/testapps/testGeodesicPolygonInternal.c)
add_h3_test(testGeodesicCoverage src/apps/testapps/testGeodesicCoverage.c)
add_h3_test(testGeodesicGridDiskRoundtrip src/apps/testapps/testGeodesicGridDiskRoundtrip.c)
add_h3_test(testSphereCap src/apps/testapps/testSphereCap.c)

# The "Exhaustive" part of the test name is used by the test-fast to exclude
# these files. test-fast exists so that Travis CI can run Valgrind on tests
# without taking a very long time.
Expand Down
3 changes: 3 additions & 0 deletions src/apps/benchmarks/benchmarkPolygonToCellsExperimental.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file benchmarkPolygonToCellsExperimental.c
* @brief Benchmarks the experimental polygon-to-cells traversal.
*/
#include "algos.h"
#include "benchmark.h"
#include "h3api.h"
Expand Down
208 changes: 208 additions & 0 deletions src/apps/benchmarks/benchmarkPolygonToCellsExperimentalGeodesic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* Copyright 2017, 2020-2021 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 benchmarkPolygonToCellsExperimentalGeodesic.c
* @brief Benchmarks the experimental polygon-to-cells traversal (geodesic).
*/
#include <stdbool.h>
#include <stdlib.h>

#include "algos.h"
#include "benchmark.h"
#include "h3api.h"
#include "polyfill.h"
#include "polygon.h"

// Colorado state
LatLng stateVerts[] = {{0.645778804554910, -1.903190792178713},
{0.645682811446050, -1.780975856637062},
{0.715595465293187, -1.781167842854781},
{0.715578012000667, -1.903262350678044},
{0.645778804554910, -1.903190792178713}};
Comment thread
holoskii marked this conversation as resolved.
GeoLoop stateGeoLoop;
GeoPolygon stateGeoPolygon;

// Large ellipse approx 1800x1100km
LatLng largeEllipseVerts[] = {{0.698131700797732, -1.658062789394613},
{0.697959500367918, -1.647103776346370},
{0.697443578674904, -1.636188013515931},
{0.696585971825909, -1.625358580432251},
{0.695390064403362, -1.614658215920214},
{0.693860576107503, -1.604129149430017},
{0.692003543129878, -1.593812934376823},
{0.689826294331253, -1.583750284148419},
{0.687337422317945, -1.573980911428067},
{0.684546749530733, -1.564543371466692},
{0.681465289480172, -1.555474909922921},
{0.678105203281295, -1.546811315871481},
{0.674479751659253, -1.538586780560073},
{0.670603242615285, -1.530833762472139},
{0.666490974959581, -1.523582859228054},
{0.662159177933861, -1.516862686830300},
{0.657624947161976, -1.510699766729177},
{0.652906177181289, -1.505118421154754},
{0.648021490821112, -1.500140677128138},
{0.642990165706910, -1.495786179530887},
{0.637832058180313, -1.492072113575638},
{0.632567524935215, -1.489013136983919},
{0.627217342679196, -1.486621322138826},
{0.621802626137356, -1.484906108440836},
{0.616344744722137, -1.483874265054807},
{0.610865238198015, -1.483529864195180},
{0.605385731673894, -1.483874265054807},
{0.599927850258674, -1.484906108440836},
{0.594513133716834, -1.486621322138826},
{0.589162951460816, -1.489013136983919},
{0.583898418215717, -1.492072113575638},
{0.578740310689120, -1.495786179530887},
{0.573708985574918, -1.500140677128138},
{0.568824299214742, -1.505118421154754},
{0.564105529234055, -1.510699766729177},
{0.559571298462169, -1.516862686830300},
{0.555239501436449, -1.523582859228054},
{0.551127233780745, -1.530833762472139},
{0.547250724736778, -1.538586780560073},
{0.543625273114736, -1.546811315871481},
{0.540265186915859, -1.555474909922921},
{0.537183726865297, -1.564543371466692},
{0.534393054078086, -1.573980911428067},
{0.531904182064778, -1.583750284148419},
{0.529726933266152, -1.593812934376823},
{0.527869900288528, -1.604129149430017},
{0.526340411992668, -1.614658215920214},
{0.525144504570122, -1.625358580432251},
{0.524286897721127, -1.636188013515931},
{0.523770976028112, -1.647103776346370},
{0.523598775598299, -1.658062789394613},
{0.523770976028112, -1.669021802442856},
{0.524286897721127, -1.679937565273295},
{0.525144504570122, -1.690766998356975},
{0.526340411992668, -1.701467362869012},
{0.527869900288528, -1.711996429359209},
{0.529726933266152, -1.722312644412403},
{0.531904182064778, -1.732375294640808},
{0.534393054078086, -1.742144667361160},
{0.537183726865297, -1.751582207322534},
{0.540265186915859, -1.760650668866305},
{0.543625273114736, -1.769314262917745},
{0.547250724736778, -1.777538798229153},
{0.551127233780745, -1.785291816317088},
{0.555239501436449, -1.792542719561173},
{0.559571298462169, -1.799262891958926},
{0.564105529234055, -1.805425812060049},
{0.568824299214742, -1.811007157634472},
{0.573708985574918, -1.815984901661088},
{0.578740310689120, -1.820339399258339},
{0.583898418215717, -1.824053465213588},
{0.589162951460816, -1.827112441805307},
{0.594513133716834, -1.829504256650400},
{0.599927850258674, -1.831219470348391},
{0.605385731673894, -1.832251313734419},
{0.610865238198015, -1.832595714594046},
{0.616344744722137, -1.832251313734419},
{0.621802626137356, -1.831219470348391},
{0.627217342679196, -1.829504256650400},
{0.632567524935215, -1.827112441805307},
{0.637832058180313, -1.824053465213588},
{0.642990165706910, -1.820339399258339},
{0.648021490821112, -1.815984901661088},
{0.652906177181289, -1.811007157634472},
{0.657624947161976, -1.805425812060049},
{0.662159177933861, -1.799262891958926},
{0.666490974959581, -1.792542719561173},
{0.670603242615285, -1.785291816317088},
{0.674479751659253, -1.777538798229153},
{0.678105203281295, -1.769314262917745},
{0.681465289480172, -1.760650668866305},
{0.684546749530733, -1.751582207322534},
{0.687337422317945, -1.742144667361160},
{0.689826294331253, -1.732375294640808},
{0.692003543129878, -1.722312644412403},
{0.693860576107503, -1.711996429359210},
{0.695390064403362, -1.701467362869012},
{0.696585971825909, -1.690766998356975},
{0.697443578674904, -1.679937565273295},
{0.697959500367918, -1.669021802442856}};
GeoLoop largeEllipseGeoLoop;
GeoPolygon largeEllipseGeoPolygon;

// London to NY flight
LatLng londonNyVerts[] = {{0.8989737191417, -0.0022305307840},
{0.7105724077059, -1.2916483662309},
{0.8989737191417, -0.0022305307840}};
GeoLoop londonNyGeoLoop;
GeoPolygon londonNyGeoPolygon;

void polygonToCellsBenchmark(const GeoPolygon *polygon, int resolution,
bool geodesic) {
uint32_t flags = CONTAINMENT_OVERLAPPING;
if (geodesic) {
FLAG_SET_GEODESIC(flags);
}

int64_t numHexagons = 0;
H3_EXPORT(maxPolygonToCellsSizeExperimental)
(polygon, resolution, flags, &numHexagons);
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));
H3_EXPORT(polygonToCellsExperimental)
(polygon, resolution, flags, numHexagons, hexagons);
free(hexagons);
}

BEGIN_BENCHMARKS();

stateGeoLoop.numVerts = 5;
stateGeoLoop.verts = stateVerts;
stateGeoPolygon.geoloop = stateGeoLoop;

largeEllipseGeoLoop.numVerts = 100;
largeEllipseGeoLoop.verts = largeEllipseVerts;
largeEllipseGeoPolygon.geoloop = largeEllipseGeoLoop;

londonNyGeoLoop.numVerts = 3;
londonNyGeoLoop.verts = londonNyVerts;
londonNyGeoPolygon.geoloop = londonNyGeoLoop;

const int stateResolution = 5;
const int largeEllipseResolution = 4;
const int londonNyResolution = 3;

BENCHMARK(polygonToCellsState_PlanarOverlapping, 30, {
polygonToCellsBenchmark(&stateGeoPolygon, stateResolution, false);
});

BENCHMARK(polygonToCellsState_GeodesicOverlapping, 30, {
polygonToCellsBenchmark(&stateGeoPolygon, stateResolution, true);
});

BENCHMARK(polygonToCellsLargeEllipse_PlanarOverlapping, 50, {
polygonToCellsBenchmark(&largeEllipseGeoPolygon, largeEllipseResolution,
false);
});

BENCHMARK(polygonToCellsLargeEllipse_GeodesicOverlapping, 50, {
polygonToCellsBenchmark(&largeEllipseGeoPolygon, largeEllipseResolution,
true);
});

BENCHMARK(polygonToCellsLondonNY_PlanarOverlapping, 100, {
polygonToCellsBenchmark(&londonNyGeoPolygon, londonNyResolution, false);
});

BENCHMARK(polygonToCellsLondonNY_GeodesicOverlapping, 100, {
polygonToCellsBenchmark(&londonNyGeoPolygon, londonNyResolution, true);
});

END_BENCHMARKS();
2 changes: 1 addition & 1 deletion src/apps/fuzzers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ The public API of H3 is covered in the following fuzzers:
| localIjToCell | [fuzzerLocalIj](./fuzzerLocalIj.c)
| originToDirectedEdges | [fuzzerDirectedEdge](./fuzzerDirectedEdge.c)
| polygonToCells | [fuzzerPoylgonToCells](./fuzzerPolygonToCells.c)
| polygonToCellsExperimental | [fuzzerPoylgonToCellsExperimental](./fuzzerPolygonToCellsExperimental.c) [fuzzerPoylgonToCellsExperimentalNoHoles](./fuzzerPolygonToCellsExperimentalNoHoles.c)
| polygonToCellsExperimental | [fuzzerPoylgonToCellsExperimental](./fuzzerPolygonToCellsExperimental.c) [fuzzerPoylgonToCellsExperimentalGeodesic](./fuzzerPolygonToCellsExperimentalGeodesic.c) [fuzzerPoylgonToCellsExperimentalNoHoles](./fuzzerPolygonToCellsExperimentalNoHoles.c)
| radsToDegs | Trivial
| stringToH3 | [fuzzerIndexIO](./fuzzerIndexIO.c)
| uncompactCells | [fuzzerCompact](./fuzzerCompact.c)
Expand Down
9 changes: 7 additions & 2 deletions src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file
* @brief Fuzzer program for polygonToCells2 and related functions
/** @file fuzzerPolygonToCellsExperimental.c
* @brief Fuzzes the experimental polygon-to-cells implementation.
*/

#include "aflHarness.h"
Expand Down Expand Up @@ -95,6 +95,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
geoPolygon.numHoles = originalNumHoles;
run(&geoPolygon, flags, res);

// Don't run polygon without holes twice
if (originalNumHoles == 0) {
continue;
}
geoPolygon.numHoles = 0;
run(&geoPolygon, flags, res);
}
Expand Down
Loading
Loading