h3 3.6.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/ext/h3/src/CHANGELOG.md +7 -0
- data/ext/h3/src/CMakeLists.txt +4 -2
- data/ext/h3/src/README.md +1 -1
- data/ext/h3/src/VERSION +1 -1
- data/ext/h3/src/docs/community/bindings.md +4 -0
- data/ext/h3/src/src/apps/testapps/testCompact.c +34 -2
- data/ext/h3/src/src/apps/testapps/testGeoCoord.c +13 -1
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +4 -2
- data/ext/h3/src/src/apps/testapps/testPolyfill.c +3 -3
- data/ext/h3/src/src/apps/testapps/testPolyfill_GH136.c +58 -0
- data/ext/h3/src/src/apps/testapps/testPolygon.c +26 -1
- data/ext/h3/src/src/h3lib/include/algos.h +8 -0
- data/ext/h3/src/src/h3lib/include/bbox.h +3 -1
- data/ext/h3/src/src/h3lib/lib/algos.c +240 -38
- data/ext/h3/src/src/h3lib/lib/bbox.c +50 -25
- data/ext/h3/src/src/h3lib/lib/h3Index.c +3 -0
- data/lib/h3/version.rb +1 -1
- data/spec/region_spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 32f9595b2e8746f59aaef1c082fc3527a7eb3d7594d7eac1a59cb5875df6af3d
|
|
4
|
+
data.tar.gz: 8fd9c4ed2317a0211b4d3fa6360aede580bff5db691605b7fdd33b299720ba3f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4e0a51a2bdcf92096406af99d3823359768b99291f96be9ac6d113363c09efb71513cf09944eca1155549b63bbab4c628e2a6f89f8d77817df4029155375072e
|
|
7
|
+
data.tar.gz: 1c672e3d6d2262dee4bae5bf65587a870c9053b1815ec7ee34798fae228aed5bd338d57883ebb594f81b6c959006af86c460ddca473e4db401631e2400a11dcd
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
h3 (3.6.
|
|
4
|
+
h3 (3.6.1)
|
|
5
5
|
ffi (~> 1.9)
|
|
6
6
|
rgeo-geojson (~> 2.1)
|
|
7
7
|
zeitwerk (~> 2.1)
|
|
@@ -17,10 +17,10 @@ GEM
|
|
|
17
17
|
tins (~> 1.6)
|
|
18
18
|
diff-lcs (1.3)
|
|
19
19
|
docile (1.3.1)
|
|
20
|
-
ffi (1.11.
|
|
20
|
+
ffi (1.11.2)
|
|
21
21
|
json (2.1.0)
|
|
22
22
|
rake (12.3.2)
|
|
23
|
-
rgeo (2.1.
|
|
23
|
+
rgeo (2.1.1)
|
|
24
24
|
rgeo-geojson (2.1.1)
|
|
25
25
|
rgeo (>= 1.0.0)
|
|
26
26
|
rspec (3.8.0)
|
|
@@ -46,7 +46,7 @@ GEM
|
|
|
46
46
|
thor (0.19.4)
|
|
47
47
|
tins (1.20.2)
|
|
48
48
|
yard (0.9.20)
|
|
49
|
-
zeitwerk (2.1
|
|
49
|
+
zeitwerk (2.2.1)
|
|
50
50
|
|
|
51
51
|
PLATFORMS
|
|
52
52
|
ruby
|
data/ext/h3/src/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ The public API of this library consists of the functions declared in file
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.1] - 2019-11-11
|
|
11
|
+
### Fixed
|
|
12
|
+
- `compact` handles zero length input correctly. (#278)
|
|
13
|
+
- `bboxHexRadius` scaling factor adjusted to guarantee containment for `polyfill`. (#279)
|
|
14
|
+
- `polyfill` new algorithm for up to 3x perf boost. (#282)
|
|
15
|
+
- Fix CMake targets for KML generation. (#285)
|
|
16
|
+
|
|
10
17
|
## [3.6.0] - 2019-08-12
|
|
11
18
|
### Added
|
|
12
19
|
- `h3ToCenterChild` function to find center child at given resolution (#267)
|
data/ext/h3/src/CMakeLists.txt
CHANGED
|
@@ -143,6 +143,7 @@ set(OTHER_SOURCE_FILES
|
|
|
143
143
|
src/apps/testapps/testVertexGraph.c
|
|
144
144
|
src/apps/testapps/testCompact.c
|
|
145
145
|
src/apps/testapps/testPolyfill.c
|
|
146
|
+
src/apps/testapps/testPolyfill_GH136.c
|
|
146
147
|
src/apps/testapps/testPentagonIndexes.c
|
|
147
148
|
src/apps/testapps/testKRing.c
|
|
148
149
|
src/apps/testapps/testH3ToGeoBoundary.c
|
|
@@ -349,11 +350,11 @@ if(BUILD_FILTERS)
|
|
|
349
350
|
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "KML/res${resolution}cells.kml")
|
|
350
351
|
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "KML/res${resolution}centers.kml")
|
|
351
352
|
add_custom_target(kml_cells_${resolution}
|
|
352
|
-
COMMAND ${SHELL} "$<TARGET_FILE:h3ToHier> ${resolution} | $<TARGET_FILE:h3ToGeoBoundary>
|
|
353
|
+
COMMAND ${SHELL} "$<TARGET_FILE:h3ToHier> -r ${resolution} | $<TARGET_FILE:h3ToGeoBoundary> --kml --kml-name res${resolution}cells.kml --kml-description \"Res ${resolution} Cells\" > KML/res${resolution}cells.kml"
|
|
353
354
|
VERBATIM
|
|
354
355
|
DEPENDS create-kml-dir)
|
|
355
356
|
add_custom_target(kml_centers_${resolution}
|
|
356
|
-
COMMAND ${SHELL} "$<TARGET_FILE:h3ToHier> ${resolution} | $<TARGET_FILE:h3ToGeo>
|
|
357
|
+
COMMAND ${SHELL} "$<TARGET_FILE:h3ToHier> -r ${resolution} | $<TARGET_FILE:h3ToGeo> --kml --kml-name res${resolution}centers.kml --kml-description \"Res ${resolution} Centers\" > KML/res${resolution}centers.kml"
|
|
357
358
|
VERBATIM
|
|
358
359
|
DEPENDS create-kml-dir)
|
|
359
360
|
add_dependencies(kml
|
|
@@ -506,6 +507,7 @@ if(BUILD_TESTING)
|
|
|
506
507
|
add_h3_test(testH3SetToVertexGraph src/apps/testapps/testH3SetToVertexGraph.c)
|
|
507
508
|
add_h3_test(testLinkedGeo src/apps/testapps/testLinkedGeo.c)
|
|
508
509
|
add_h3_test(testPolyfill src/apps/testapps/testPolyfill.c)
|
|
510
|
+
add_h3_test(testPolyfill_GH136 src/apps/testapps/testPolyfill_GH136.c)
|
|
509
511
|
add_h3_test(testVertexGraph src/apps/testapps/testVertexGraph.c)
|
|
510
512
|
add_h3_test(testH3UniEdge src/apps/testapps/testH3UniEdge.c)
|
|
511
513
|
add_h3_test(testGeoCoord src/apps/testapps/testGeoCoord.c)
|
data/ext/h3/src/README.md
CHANGED
data/ext/h3/src/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.6.
|
|
1
|
+
3.6.1
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
As a C library, bindings can be made to call H3 functions from different programming languages. This page lists different bindings currently available. Contributions to this list are welcome, please feel free to open a [pull request](https://github.com/uber/h3/tree/master/docs/community/bindings.md).
|
|
4
4
|
|
|
5
|
+
## BigQuery
|
|
6
|
+
|
|
7
|
+
- [cartodb/bigquery-jslibs](https://github.com/CartoDB/bigquery-jslibs)
|
|
8
|
+
|
|
5
9
|
## C#
|
|
6
10
|
|
|
7
11
|
- [entrepreneur-interet-general/h3.standard](https://github.com/entrepreneur-interet-general/H3.Standard)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2019 Uber Technologies, Inc.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -152,6 +152,31 @@ SUITE(compact) {
|
|
|
152
152
|
"compact fails on duplicate input");
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
TEST(compact_empty) {
|
|
156
|
+
t_assert(H3_EXPORT(compact)(NULL, NULL, 0) == 0,
|
|
157
|
+
"compact succeeds on empty input");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
TEST(compact_disparate) {
|
|
161
|
+
// Exercises a case where compaction needs to be tested but none is
|
|
162
|
+
// possible
|
|
163
|
+
const int numHex = 7;
|
|
164
|
+
H3Index disparate[] = {0, 0, 0, 0, 0, 0, 0};
|
|
165
|
+
for (int i = 0; i < numHex; i++) {
|
|
166
|
+
setH3Index(&disparate[i], 1, i, CENTER_DIGIT);
|
|
167
|
+
}
|
|
168
|
+
H3Index output[] = {0, 0, 0, 0, 0, 0, 0};
|
|
169
|
+
|
|
170
|
+
t_assert(H3_EXPORT(compact)(disparate, output, numHex) == 0,
|
|
171
|
+
"compact succeeds on disparate input");
|
|
172
|
+
|
|
173
|
+
// Assumes that `output` is an exact copy of `disparate`, including
|
|
174
|
+
// the ordering (which may not necessarily be the case)
|
|
175
|
+
for (int i = 0; i < numHex; i++) {
|
|
176
|
+
t_assert(disparate[i] == output[i], "output set equals input set");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
155
180
|
TEST(uncompact_wrongRes) {
|
|
156
181
|
int numHex = 3;
|
|
157
182
|
H3Index someHexagons[] = {0, 0, 0};
|
|
@@ -221,6 +246,13 @@ SUITE(compact) {
|
|
|
221
246
|
free(result);
|
|
222
247
|
}
|
|
223
248
|
|
|
249
|
+
TEST(uncompact_empty) {
|
|
250
|
+
int uncompactSz = H3_EXPORT(maxUncompactSize)(NULL, 0, 0);
|
|
251
|
+
t_assert(uncompactSz == 0, "maxUncompactSize accepts empty input");
|
|
252
|
+
t_assert(H3_EXPORT(uncompact)(NULL, 0, NULL, 0, 0) == 0,
|
|
253
|
+
"uncompact accepts empty input");
|
|
254
|
+
}
|
|
255
|
+
|
|
224
256
|
TEST(uncompact_onlyZero) {
|
|
225
257
|
// maxUncompactSize and uncompact both permit 0 indexes
|
|
226
258
|
// in the input array, and skip them. When only a zero is
|
|
@@ -237,7 +269,7 @@ SUITE(compact) {
|
|
|
237
269
|
free(children);
|
|
238
270
|
}
|
|
239
271
|
|
|
240
|
-
TEST(
|
|
272
|
+
TEST(uncompact_withZero) {
|
|
241
273
|
// maxUncompactSize and uncompact both permit 0 indexes
|
|
242
274
|
// in the input array, and skip them.
|
|
243
275
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2019 Uber Technologies, Inc.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -168,6 +168,18 @@ SUITE(geoCoord) {
|
|
|
168
168
|
t_assert(_geoDistRads(&start, &out) < 0.01, "moved back to origin");
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
TEST(_geoDistRads_wrappedLongitude) {
|
|
172
|
+
const GeoCoord negativeLongitude = {.lat = 0, .lon = -(M_PI + M_PI_2)};
|
|
173
|
+
const GeoCoord zero = {.lat = 0, .lon = 0};
|
|
174
|
+
|
|
175
|
+
t_assert(fabs(M_PI_2 - _geoDistRads(&negativeLongitude, &zero)) <
|
|
176
|
+
EPSILON_RAD,
|
|
177
|
+
"Distance with wrapped longitude");
|
|
178
|
+
t_assert(fabs(M_PI_2 - _geoDistRads(&zero, &negativeLongitude)) <
|
|
179
|
+
EPSILON_RAD,
|
|
180
|
+
"Distance with wrapped longitude and swapped arguments");
|
|
181
|
+
}
|
|
182
|
+
|
|
171
183
|
TEST(doubleConstants) {
|
|
172
184
|
// Simple checks for ordering of values
|
|
173
185
|
testDecreasingFunction(H3_EXPORT(hexAreaKm2), "hexAreaKm2 ordering");
|
|
@@ -86,10 +86,12 @@ SUITE(h3ToLocalIj) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
TEST(ijOutOfRange) {
|
|
89
|
-
const int numCoords =
|
|
90
|
-
const CoordIJ coords[] = {{0, 0}, {1, 0},
|
|
89
|
+
const int numCoords = 7;
|
|
90
|
+
const CoordIJ coords[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0},
|
|
91
|
+
{4, 0}, {-4, 0}, {0, 4}};
|
|
91
92
|
const H3Index expected[] = {0x81283ffffffffff, 0x81293ffffffffff,
|
|
92
93
|
0x8150bffffffffff, 0x8151bffffffffff,
|
|
94
|
+
H3_INVALID_INDEX, H3_INVALID_INDEX,
|
|
93
95
|
H3_INVALID_INDEX};
|
|
94
96
|
|
|
95
97
|
for (int i = 0; i < numCoords; i++) {
|
|
@@ -64,13 +64,13 @@ SUITE(polyfill) {
|
|
|
64
64
|
|
|
65
65
|
TEST(maxPolyfillSize) {
|
|
66
66
|
int numHexagons = H3_EXPORT(maxPolyfillSize)(&sfGeoPolygon, 9);
|
|
67
|
-
t_assert(numHexagons ==
|
|
67
|
+
t_assert(numHexagons == 3457, "got expected max polyfill size");
|
|
68
68
|
|
|
69
69
|
numHexagons = H3_EXPORT(maxPolyfillSize)(&holeGeoPolygon, 9);
|
|
70
|
-
t_assert(numHexagons ==
|
|
70
|
+
t_assert(numHexagons == 3457, "got expected max polyfill size (hole)");
|
|
71
71
|
|
|
72
72
|
numHexagons = H3_EXPORT(maxPolyfillSize)(&emptyGeoPolygon, 9);
|
|
73
|
-
t_assert(numHexagons ==
|
|
73
|
+
t_assert(numHexagons == 3, "got expected max polyfill size (empty)");
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
TEST(polyfill) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2017-2019 Uber Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include <stdlib.h>
|
|
18
|
+
#include "algos.h"
|
|
19
|
+
#include "constants.h"
|
|
20
|
+
#include "geoCoord.h"
|
|
21
|
+
#include "h3Index.h"
|
|
22
|
+
#include "test.h"
|
|
23
|
+
|
|
24
|
+
// https://github.com/uber/h3/issues/136
|
|
25
|
+
|
|
26
|
+
static GeoCoord testVerts[] = {{0.10068990369902957, 0.8920772174196191},
|
|
27
|
+
{0.10032914690616246, 0.8915914753447348},
|
|
28
|
+
{0.10033349237998787, 0.8915860128746426},
|
|
29
|
+
{0.10069496685903621, 0.8920742194546231}};
|
|
30
|
+
static Geofence testGeofence = {.numVerts = 4, .verts = testVerts};
|
|
31
|
+
static GeoPolygon testPolygon;
|
|
32
|
+
|
|
33
|
+
static int countActualHexagons(H3Index* hexagons, int numHexagons) {
|
|
34
|
+
int actualNumHexagons = 0;
|
|
35
|
+
for (int i = 0; i < numHexagons; i++) {
|
|
36
|
+
if (hexagons[i] != 0) {
|
|
37
|
+
actualNumHexagons++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return actualNumHexagons;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
SUITE(polyfill_gh136) {
|
|
44
|
+
testPolygon.geofence = testGeofence;
|
|
45
|
+
testPolygon.numHoles = 0;
|
|
46
|
+
|
|
47
|
+
TEST(gh136) {
|
|
48
|
+
int res = 13;
|
|
49
|
+
int numHexagons = H3_EXPORT(maxPolyfillSize)(&testPolygon, res);
|
|
50
|
+
H3Index* hexagons = calloc(numHexagons, sizeof(H3Index));
|
|
51
|
+
|
|
52
|
+
H3_EXPORT(polyfill)(&testPolygon, res, hexagons);
|
|
53
|
+
int actualNumHexagons = countActualHexagons(hexagons, numHexagons);
|
|
54
|
+
|
|
55
|
+
t_assert(actualNumHexagons == 4353, "got expected polyfill size");
|
|
56
|
+
free(hexagons);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2019 Uber Technologies, Inc.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -553,4 +553,29 @@ SUITE(polygon) {
|
|
|
553
553
|
|
|
554
554
|
H3_EXPORT(destroyLinkedPolygon)(&polygon);
|
|
555
555
|
}
|
|
556
|
+
|
|
557
|
+
TEST(normalizeMultiPolygon_unassignedHole) {
|
|
558
|
+
GeoCoord verts[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
|
|
559
|
+
|
|
560
|
+
LinkedGeoLoop* outer = malloc(sizeof(*outer));
|
|
561
|
+
assert(outer != NULL);
|
|
562
|
+
createLinkedLoop(outer, &verts[0], 4);
|
|
563
|
+
|
|
564
|
+
GeoCoord verts2[] = {{2, 2}, {3, 3}, {2, 3}};
|
|
565
|
+
|
|
566
|
+
LinkedGeoLoop* inner = malloc(sizeof(*inner));
|
|
567
|
+
assert(inner != NULL);
|
|
568
|
+
createLinkedLoop(inner, &verts2[0], 3);
|
|
569
|
+
|
|
570
|
+
LinkedGeoPolygon polygon = {0};
|
|
571
|
+
addLinkedLoop(&polygon, inner);
|
|
572
|
+
addLinkedLoop(&polygon, outer);
|
|
573
|
+
|
|
574
|
+
int result = normalizeMultiPolygon(&polygon);
|
|
575
|
+
|
|
576
|
+
t_assert(result == NORMALIZATION_ERR_UNASSIGNED_HOLES,
|
|
577
|
+
"Expected error code returned");
|
|
578
|
+
|
|
579
|
+
H3_EXPORT(destroyLinkedPolygon)(&polygon);
|
|
580
|
+
}
|
|
556
581
|
}
|
|
@@ -40,4 +40,12 @@ void h3SetToVertexGraph(const H3Index* h3Set, const int numHexes,
|
|
|
40
40
|
// Create a LinkedGeoPolygon from a vertex graph
|
|
41
41
|
void _vertexGraphToLinkedGeo(VertexGraph* graph, LinkedGeoPolygon* out);
|
|
42
42
|
|
|
43
|
+
// Internal function for polyfill that traces a geofence with hexagons of a
|
|
44
|
+
// specific size
|
|
45
|
+
int _getEdgeHexagons(const Geofence* geofence, int numHexagons, int res,
|
|
46
|
+
int* numSearchHexes, H3Index* search, H3Index* found);
|
|
47
|
+
|
|
48
|
+
// The new polyfill algorithm. Separated out because it can theoretically fail
|
|
49
|
+
int _polyfillInternal(const GeoPolygon* geoPolygon, int res, H3Index* out);
|
|
50
|
+
|
|
43
51
|
#endif
|
|
@@ -37,6 +37,8 @@ bool bboxIsTransmeridian(const BBox* bbox);
|
|
|
37
37
|
void bboxCenter(const BBox* bbox, GeoCoord* center);
|
|
38
38
|
bool bboxContains(const BBox* bbox, const GeoCoord* point);
|
|
39
39
|
bool bboxEquals(const BBox* b1, const BBox* b2);
|
|
40
|
-
int
|
|
40
|
+
int bboxHexEstimate(const BBox* bbox, int res);
|
|
41
|
+
int lineHexEstimate(const GeoCoord* origin, const GeoCoord* destination,
|
|
42
|
+
int res);
|
|
41
43
|
|
|
42
44
|
#endif
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
#define HEX_RANGE_SUCCESS 0
|
|
42
42
|
#define HEX_RANGE_PENTAGON 1
|
|
43
43
|
#define HEX_RANGE_K_SUBSEQUENCE 2
|
|
44
|
+
#define MAX_ONE_RING_SIZE 7
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Directions used for traversing a hexagonal ring counterclockwise around
|
|
@@ -623,9 +624,8 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
|
623
624
|
* maxPolyfillSize returns the number of hexagons to allocate space for when
|
|
624
625
|
* performing a polyfill on the given GeoJSON-like data structure.
|
|
625
626
|
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* a Python application? ;)
|
|
627
|
+
* The size is the maximum of either the number of points in the geofence or the
|
|
628
|
+
* number of hexagons in the bounding box of the geofence.
|
|
629
629
|
*
|
|
630
630
|
* @param geoPolygon A GeoJSON-like data structure indicating the poly to fill
|
|
631
631
|
* @param res Hexagon resolution (0-15)
|
|
@@ -634,12 +634,18 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
|
634
634
|
int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
|
|
635
635
|
// Get the bounding box for the GeoJSON-like struct
|
|
636
636
|
BBox bbox;
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
//
|
|
641
|
-
// the
|
|
642
|
-
|
|
637
|
+
const Geofence geofence = geoPolygon->geofence;
|
|
638
|
+
bboxFromGeofence(&geofence, &bbox);
|
|
639
|
+
int numHexagons = bboxHexEstimate(&bbox, res);
|
|
640
|
+
// This algorithm assumes that the number of vertices is usually less than
|
|
641
|
+
// the number of hexagons, but when it's wrong, this will keep it from
|
|
642
|
+
// failing
|
|
643
|
+
int totalVerts = geofence.numVerts;
|
|
644
|
+
for (int i = 0; i < geoPolygon->numHoles; i++) {
|
|
645
|
+
totalVerts += geoPolygon->holes[i].numVerts;
|
|
646
|
+
}
|
|
647
|
+
if (numHexagons < totalVerts) numHexagons = totalVerts;
|
|
648
|
+
return numHexagons;
|
|
643
649
|
}
|
|
644
650
|
|
|
645
651
|
/**
|
|
@@ -647,15 +653,108 @@ int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
|
|
|
647
653
|
* zeroed memory, and fills it with the hexagons that are contained by
|
|
648
654
|
* the GeoJSON-like data structure.
|
|
649
655
|
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
656
|
+
* This implementation traces the GeoJSON geofence(s) in cartesian space with
|
|
657
|
+
* hexagons, tests them and their neighbors to be contained by the geofence(s),
|
|
658
|
+
* and then any newly found hexagons are used to test again until no new
|
|
659
|
+
* hexagons are found.
|
|
653
660
|
*
|
|
654
661
|
* @param geoPolygon The geofence and holes defining the relevant area
|
|
655
662
|
* @param res The Hexagon resolution (0-15)
|
|
656
663
|
* @param out The slab of zeroed memory to write to. Assumed to be big enough.
|
|
657
664
|
*/
|
|
658
665
|
void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
666
|
+
// TODO: Eliminate this wrapper with the H3 4.0.0 release
|
|
667
|
+
int failure = _polyfillInternal(geoPolygon, res, out);
|
|
668
|
+
// The polyfill algorithm can theoretically fail if the allocated memory is
|
|
669
|
+
// not large enough for the polygon, but this should be impossible given the
|
|
670
|
+
// conservative overestimation of the number of hexagons possible.
|
|
671
|
+
// LCOV_EXCL_START
|
|
672
|
+
if (failure) {
|
|
673
|
+
int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
|
|
674
|
+
for (int i = 0; i < numHexagons; i++) out[i] = H3_INVALID_INDEX;
|
|
675
|
+
}
|
|
676
|
+
// LCOV_EXCL_STOP
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* _getEdgeHexagons takes a given geofence ring (either the main geofence or
|
|
681
|
+
* one of the holes) and traces it with hexagons and updates the search and
|
|
682
|
+
* found memory blocks. This is used for determining the initial hexagon set
|
|
683
|
+
* for the polyfill algorithm to execute on.
|
|
684
|
+
*
|
|
685
|
+
* @param geofence The geofence (or hole) to be traced
|
|
686
|
+
* @param numHexagons The maximum number of hexagons possible for the geofence
|
|
687
|
+
* (also the bounds of the search and found arrays)
|
|
688
|
+
* @param res The hexagon resolution (0-15)
|
|
689
|
+
* @param numSearchHexes The number of hexagons found so far to be searched
|
|
690
|
+
* @param search The block of memory containing the hexagons to search from
|
|
691
|
+
* @param found The block of memory containing the hexagons found from the
|
|
692
|
+
* search
|
|
693
|
+
*
|
|
694
|
+
* @return An error code if the hash function cannot insert a found hexagon
|
|
695
|
+
* into the found array.
|
|
696
|
+
*/
|
|
697
|
+
int _getEdgeHexagons(const Geofence* geofence, int numHexagons, int res,
|
|
698
|
+
int* numSearchHexes, H3Index* search, H3Index* found) {
|
|
699
|
+
for (int i = 0; i < geofence->numVerts; i++) {
|
|
700
|
+
GeoCoord origin = geofence->verts[i];
|
|
701
|
+
GeoCoord destination = i == geofence->numVerts - 1
|
|
702
|
+
? geofence->verts[0]
|
|
703
|
+
: geofence->verts[i + 1];
|
|
704
|
+
const int numHexesEstimate =
|
|
705
|
+
lineHexEstimate(&origin, &destination, res);
|
|
706
|
+
for (int j = 0; j < numHexesEstimate; j++) {
|
|
707
|
+
GeoCoord interpolate;
|
|
708
|
+
interpolate.lat =
|
|
709
|
+
(origin.lat * (numHexesEstimate - j) / numHexesEstimate) +
|
|
710
|
+
(destination.lat * j / numHexesEstimate);
|
|
711
|
+
interpolate.lon =
|
|
712
|
+
(origin.lon * (numHexesEstimate - j) / numHexesEstimate) +
|
|
713
|
+
(destination.lon * j / numHexesEstimate);
|
|
714
|
+
H3Index pointHex = H3_EXPORT(geoToH3)(&interpolate, res);
|
|
715
|
+
// A simple hash to store the hexagon, or move to another place if
|
|
716
|
+
// needed
|
|
717
|
+
int loc = (int)(pointHex % numHexagons);
|
|
718
|
+
int loopCount = 0;
|
|
719
|
+
while (found[loc] != 0) {
|
|
720
|
+
// If this conditional is reached, the `found` memory block is
|
|
721
|
+
// too small for the given polygon. This should not happen.
|
|
722
|
+
if (loopCount > numHexagons) return -1; // LCOV_EXCL_LINE
|
|
723
|
+
if (found[loc] == pointHex)
|
|
724
|
+
break; // At least two points of the geofence index to the
|
|
725
|
+
// same cell
|
|
726
|
+
loc = (loc + 1) % numHexagons;
|
|
727
|
+
loopCount++;
|
|
728
|
+
}
|
|
729
|
+
if (found[loc] == pointHex)
|
|
730
|
+
continue; // Skip this hex, already exists in the found hash
|
|
731
|
+
// Otherwise, set it in the found hash for now
|
|
732
|
+
found[loc] = pointHex;
|
|
733
|
+
|
|
734
|
+
search[*numSearchHexes] = pointHex;
|
|
735
|
+
(*numSearchHexes)++;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return 0;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* _polyfillInternal traces the provided geoPolygon data structure with hexagons
|
|
743
|
+
* and then iteratively searches through these hexagons and their immediate
|
|
744
|
+
* neighbors to see if they are contained within the polygon or not. Those that
|
|
745
|
+
* are found are added to the out array as well as the found array. Once all
|
|
746
|
+
* hexagons to search are checked, the found hexagons become the new search
|
|
747
|
+
* array and the found array is wiped and the process repeats until no new
|
|
748
|
+
* hexagons can be found.
|
|
749
|
+
*
|
|
750
|
+
* @param geoPolygon The geofence and holes defining the relevant area
|
|
751
|
+
* @param res The Hexagon resolution (0-15)
|
|
752
|
+
* @param out The slab of zeroed memory to write to. Assumed to be big enough.
|
|
753
|
+
*
|
|
754
|
+
* @return An error code if any of the hash operations fails to insert a hexagon
|
|
755
|
+
* into an array of memory.
|
|
756
|
+
*/
|
|
757
|
+
int _polyfillInternal(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
659
758
|
// One of the goals of the polyfill algorithm is that two adjacent polygons
|
|
660
759
|
// with zero overlap have zero overlapping hexagons. That the hexagons are
|
|
661
760
|
// uniquely assigned. There are a few approaches to take here, such as
|
|
@@ -677,36 +776,139 @@ void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
|
677
776
|
BBox* bboxes = malloc((geoPolygon->numHoles + 1) * sizeof(BBox));
|
|
678
777
|
assert(bboxes != NULL);
|
|
679
778
|
bboxesFromGeoPolygon(geoPolygon, bboxes);
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
//
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
//
|
|
693
|
-
//
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
779
|
+
|
|
780
|
+
// Get the estimated number of hexagons and allocate some temporary memory
|
|
781
|
+
// for the hexagons
|
|
782
|
+
int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
|
|
783
|
+
H3Index* search = calloc(numHexagons, sizeof(H3Index));
|
|
784
|
+
H3Index* found = calloc(numHexagons, sizeof(H3Index));
|
|
785
|
+
|
|
786
|
+
// Some metadata for tracking the state of the search and found memory
|
|
787
|
+
// blocks
|
|
788
|
+
int numSearchHexes = 0;
|
|
789
|
+
int numFoundHexes = 0;
|
|
790
|
+
|
|
791
|
+
// 1. Trace the hexagons along the polygon defining the outer geofence and
|
|
792
|
+
// add them to the search hash. The hexagon containing the geofence point
|
|
793
|
+
// may or may not be contained by the geofence (as the hexagon's center
|
|
794
|
+
// point may be outside of the boundary.)
|
|
795
|
+
const Geofence geofence = geoPolygon->geofence;
|
|
796
|
+
int failure = _getEdgeHexagons(&geofence, numHexagons, res, &numSearchHexes,
|
|
797
|
+
search, found);
|
|
798
|
+
// If this branch is reached, we have exceeded the maximum number of
|
|
799
|
+
// hexagons possible and need to clean up the allocated memory.
|
|
800
|
+
// LCOV_EXCL_START
|
|
801
|
+
if (failure) {
|
|
802
|
+
free(search);
|
|
803
|
+
free(found);
|
|
804
|
+
free(bboxes);
|
|
805
|
+
return failure;
|
|
806
|
+
}
|
|
807
|
+
// LCOV_EXCL_STOP
|
|
808
|
+
|
|
809
|
+
// 2. Iterate over all holes, trace the polygons defining the holes with
|
|
810
|
+
// hexagons and add to only the search hash. We're going to temporarily use
|
|
811
|
+
// the `found` hash to use for dedupe purposes and then re-zero it once
|
|
812
|
+
// we're done here, otherwise we'd have to scan the whole set on each insert
|
|
813
|
+
// to make sure there's no duplicates, which is very inefficient.
|
|
814
|
+
for (int i = 0; i < geoPolygon->numHoles; i++) {
|
|
815
|
+
Geofence* hole = &(geoPolygon->holes[i]);
|
|
816
|
+
failure = _getEdgeHexagons(hole, numHexagons, res, &numSearchHexes,
|
|
817
|
+
search, found);
|
|
818
|
+
// If this branch is reached, we have exceeded the maximum number of
|
|
819
|
+
// hexagons possible and need to clean up the allocated memory.
|
|
820
|
+
// LCOV_EXCL_START
|
|
821
|
+
if (failure) {
|
|
822
|
+
free(search);
|
|
823
|
+
free(found);
|
|
824
|
+
free(bboxes);
|
|
825
|
+
return failure;
|
|
698
826
|
}
|
|
699
|
-
//
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
827
|
+
// LCOV_EXCL_STOP
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// 3. Re-zero the found hash so it can be used in the main loop below
|
|
831
|
+
for (int i = 0; i < numHexagons; i++) found[i] = 0;
|
|
832
|
+
|
|
833
|
+
// 4. Begin main loop. While the search hash is not empty do the following
|
|
834
|
+
while (numSearchHexes > 0) {
|
|
835
|
+
// Iterate through all hexagons in the current search hash, then loop
|
|
836
|
+
// through all neighbors and test Point-in-Poly, if point-in-poly
|
|
837
|
+
// succeeds, add to out and found hashes if not already there.
|
|
838
|
+
int currentSearchNum = 0;
|
|
839
|
+
int i = 0;
|
|
840
|
+
while (currentSearchNum < numSearchHexes) {
|
|
841
|
+
H3Index ring[MAX_ONE_RING_SIZE] = {0};
|
|
842
|
+
H3Index searchHex = search[i];
|
|
843
|
+
H3_EXPORT(kRing)(searchHex, 1, ring);
|
|
844
|
+
for (int j = 0; j < MAX_ONE_RING_SIZE; j++) {
|
|
845
|
+
if (ring[j] == H3_INVALID_INDEX) {
|
|
846
|
+
continue; // Skip if this was a pentagon and only had 5
|
|
847
|
+
// neighbors
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
H3Index hex = ring[j];
|
|
851
|
+
|
|
852
|
+
// A simple hash to store the hexagon, or move to another place
|
|
853
|
+
// if needed. This MUST be done before the point-in-poly check
|
|
854
|
+
// since that's far more expensive
|
|
855
|
+
int loc = (int)(hex % numHexagons);
|
|
856
|
+
int loopCount = 0;
|
|
857
|
+
while (out[loc] != 0) {
|
|
858
|
+
// If this branch is reached, we have exceeded the maximum
|
|
859
|
+
// number of hexagons possible and need to clean up the
|
|
860
|
+
// allocated memory.
|
|
861
|
+
// LCOV_EXCL_START
|
|
862
|
+
if (loopCount > numHexagons) {
|
|
863
|
+
free(search);
|
|
864
|
+
free(found);
|
|
865
|
+
free(bboxes);
|
|
866
|
+
return -1;
|
|
867
|
+
}
|
|
868
|
+
// LCOV_EXCL_STOP
|
|
869
|
+
if (out[loc] == hex) break; // Skip duplicates found
|
|
870
|
+
loc = (loc + 1) % numHexagons;
|
|
871
|
+
loopCount++;
|
|
872
|
+
}
|
|
873
|
+
if (out[loc] == hex) {
|
|
874
|
+
continue; // Skip this hex, already exists in the out hash
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Check if the hexagon is in the polygon or not
|
|
878
|
+
GeoCoord hexCenter;
|
|
879
|
+
H3_EXPORT(h3ToGeo)(hex, &hexCenter);
|
|
880
|
+
|
|
881
|
+
// If not, skip
|
|
882
|
+
if (!pointInsidePolygon(geoPolygon, bboxes, &hexCenter)) {
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Otherwise set it in the output array
|
|
887
|
+
out[loc] = hex;
|
|
888
|
+
|
|
889
|
+
// Set the hexagon in the found hash
|
|
890
|
+
found[numFoundHexes] = hex;
|
|
891
|
+
numFoundHexes++;
|
|
892
|
+
}
|
|
893
|
+
currentSearchNum++;
|
|
894
|
+
i++;
|
|
707
895
|
}
|
|
896
|
+
|
|
897
|
+
// Swap the search and found pointers, copy the found hex count to the
|
|
898
|
+
// search hex count, and zero everything related to the found memory.
|
|
899
|
+
H3Index* temp = search;
|
|
900
|
+
search = found;
|
|
901
|
+
found = temp;
|
|
902
|
+
for (int j = 0; j < numSearchHexes; j++) found[j] = 0;
|
|
903
|
+
numSearchHexes = numFoundHexes;
|
|
904
|
+
numFoundHexes = 0;
|
|
905
|
+
// Repeat until no new hexagons are found
|
|
708
906
|
}
|
|
907
|
+
// The out memory structure should be complete, end it here
|
|
709
908
|
free(bboxes);
|
|
909
|
+
free(search);
|
|
910
|
+
free(found);
|
|
911
|
+
return 0;
|
|
710
912
|
}
|
|
711
913
|
|
|
712
914
|
/**
|
|
@@ -88,34 +88,59 @@ double _hexRadiusKm(H3Index h3Index) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @param
|
|
95
|
-
* @
|
|
91
|
+
* bboxHexEstimate returns an estimated number of hexagons that fit
|
|
92
|
+
* within the cartesian-projected bounding box
|
|
93
|
+
*
|
|
94
|
+
* @param bbox the bounding box to estimate the hexagon fill level
|
|
95
|
+
* @param res the resolution of the H3 hexagons to fill the bounding box
|
|
96
|
+
* @return the estimated number of hexagons to fill the bounding box
|
|
96
97
|
*/
|
|
97
|
-
int
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
int bboxHexEstimate(const BBox* bbox, int res) {
|
|
99
|
+
// Get the area of the pentagon as the maximally-distorted area possible
|
|
100
|
+
H3Index pentagons[12] = {0};
|
|
101
|
+
H3_EXPORT(getPentagonIndexes)(res, pentagons);
|
|
102
|
+
double pentagonRadiusKm = _hexRadiusKm(pentagons[0]);
|
|
103
|
+
// Area of a regular hexagon is 3/2*sqrt(3) * r * r
|
|
104
|
+
// The pentagon has the most distortion (smallest edges) and shares its
|
|
105
|
+
// edges with hexagons, so the most-distorted hexagons have this area
|
|
106
|
+
double pentagonAreaKm2 =
|
|
107
|
+
2.59807621135 * pentagonRadiusKm * pentagonRadiusKm;
|
|
101
108
|
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
// Then get the area of the bounding box of the geofence in question
|
|
110
|
+
GeoCoord p1, p2;
|
|
111
|
+
p1.lat = bbox->north;
|
|
112
|
+
p1.lon = bbox->east;
|
|
113
|
+
p2.lat = bbox->south;
|
|
114
|
+
p2.lon = bbox->east;
|
|
115
|
+
double h = _geoDistKm(&p1, &p2);
|
|
116
|
+
p2.lat = bbox->north;
|
|
117
|
+
p2.lon = bbox->west;
|
|
118
|
+
double w = _geoDistKm(&p1, &p2);
|
|
107
119
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
120
|
+
// Divide the two to get an estimate of the number of hexagons needed
|
|
121
|
+
int estimate = (int)ceil(w * h / pentagonAreaKm2);
|
|
122
|
+
if (estimate == 0) estimate = 1;
|
|
123
|
+
return estimate;
|
|
124
|
+
}
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
/**
|
|
127
|
+
* lineHexEstimate returns an estimated number of hexagons that trace
|
|
128
|
+
* the cartesian-projected line
|
|
129
|
+
*
|
|
130
|
+
* @param origin the origin coordinates
|
|
131
|
+
* @param destination the destination coordinates
|
|
132
|
+
* @param res the resolution of the H3 hexagons to trace the line
|
|
133
|
+
* @return the estimated number of hexagons required to trace the line
|
|
134
|
+
*/
|
|
135
|
+
int lineHexEstimate(const GeoCoord* origin, const GeoCoord* destination,
|
|
136
|
+
int res) {
|
|
137
|
+
// Get the area of the pentagon as the maximally-distorted area possible
|
|
138
|
+
H3Index pentagons[12] = {0};
|
|
139
|
+
H3_EXPORT(getPentagonIndexes)(res, pentagons);
|
|
140
|
+
double pentagonRadiusKm = _hexRadiusKm(pentagons[0]);
|
|
114
141
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// Rounded *up* to guarantee containment
|
|
120
|
-
return (int)ceil(bboxRadiusKm / (1.5 * centerHexRadiusKm));
|
|
142
|
+
double dist = _geoDistKm(origin, destination);
|
|
143
|
+
int estimate = (int)ceil(dist / (2 * pentagonRadiusKm));
|
|
144
|
+
if (estimate == 0) estimate = 1;
|
|
145
|
+
return estimate;
|
|
121
146
|
}
|
|
@@ -266,6 +266,9 @@ H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
|
|
|
266
266
|
*/
|
|
267
267
|
int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
268
268
|
const int numHexes) {
|
|
269
|
+
if (numHexes == 0) {
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
269
272
|
int res = H3_GET_RESOLUTION(h3Set[0]);
|
|
270
273
|
if (res == 0) {
|
|
271
274
|
// No compaction possible, just copy the set to output
|
data/lib/h3/version.rb
CHANGED
data/spec/region_spec.rb
CHANGED
|
@@ -42,7 +42,7 @@ RSpec.describe H3 do
|
|
|
42
42
|
File.read(File.join(File.dirname(__FILE__), "support/fixtures/banbury.json"))
|
|
43
43
|
end
|
|
44
44
|
let(:resolution) { 9 }
|
|
45
|
-
let(:expected_count) {
|
|
45
|
+
let(:expected_count) { 36_193 }
|
|
46
46
|
|
|
47
47
|
subject(:max_polyfill_size) { H3.max_polyfill_size(geojson, resolution) }
|
|
48
48
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: h3
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.6.
|
|
4
|
+
version: 3.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lachlan Laycock
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2019-
|
|
12
|
+
date: 2019-11-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: ffi
|
|
@@ -248,6 +248,7 @@ files:
|
|
|
248
248
|
- ext/h3/src/src/apps/testapps/testMaxH3ToChildrenSize.c
|
|
249
249
|
- ext/h3/src/src/apps/testapps/testPentagonIndexes.c
|
|
250
250
|
- ext/h3/src/src/apps/testapps/testPolyfill.c
|
|
251
|
+
- ext/h3/src/src/apps/testapps/testPolyfill_GH136.c
|
|
251
252
|
- ext/h3/src/src/apps/testapps/testPolygon.c
|
|
252
253
|
- ext/h3/src/src/apps/testapps/testVec2d.c
|
|
253
254
|
- ext/h3/src/src/apps/testapps/testVec3d.c
|