h3 3.6.0 → 3.7.2
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/.github/workflows/ruby_ci.yml +30 -0
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +39 -0
- data/Gemfile.lock +6 -24
- data/LICENSE.md +1 -1
- data/README.md +2 -3
- data/ext/h3/src/.github/workflows/test-linux.yml +118 -0
- data/ext/h3/src/.github/workflows/test-macos.yml +42 -0
- data/ext/h3/src/.github/workflows/test-website.yml +32 -0
- data/ext/h3/src/.github/workflows/test-windows.yml +44 -0
- data/ext/h3/src/.gitignore +5 -0
- data/ext/h3/src/.travis.yml +20 -42
- data/ext/h3/src/CHANGELOG.md +57 -0
- data/ext/h3/src/CMakeLists.txt +135 -33
- data/ext/h3/src/CONTRIBUTING.md +1 -1
- data/ext/h3/src/README.md +61 -11
- data/ext/h3/src/RELEASE.md +3 -1
- data/ext/h3/src/VERSION +1 -1
- data/ext/h3/src/dev-docs/RFCs/rfc-template.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/error-handling-rfc.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/names_for_concepts_types_functions.md +276 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/overrideable-allocators-rfc.md +141 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/polyfill-modes-rfc.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/vertex-mode-rfc.md +50 -0
- data/ext/h3/src/dev-docs/build_windows.md +6 -1
- data/ext/h3/src/dev-docs/creating_bindings.md +3 -3
- data/ext/h3/src/dev-docs/custom_alloc.md +27 -0
- data/ext/h3/src/docs/{overview/mainpage.md → README.md} +2 -3
- data/ext/h3/src/docs/api/misc.md +76 -0
- data/ext/h3/src/docs/community/applications.md +1 -0
- data/ext/h3/src/docs/community/bindings.md +10 -0
- data/ext/h3/src/docs/community/tutorials.md +8 -3
- data/ext/h3/src/docs/core-library/coordsystems.md +5 -4
- data/ext/h3/src/docs/core-library/filters.md +8 -9
- data/ext/h3/src/docs/core-library/geoToH3desc.md +2 -3
- data/ext/h3/src/docs/core-library/h3ToGeoBoundaryDesc.md +4 -5
- data/ext/h3/src/docs/core-library/h3ToGeoDesc.md +3 -4
- data/ext/h3/src/docs/core-library/h3indexing.md +26 -17
- data/ext/h3/src/docs/core-library/overview.md +2 -3
- data/ext/h3/src/docs/core-library/restable.md +1 -2
- data/ext/h3/src/docs/core-library/usage.md +1 -2
- data/ext/h3/src/docs/table-of-contents.json +47 -0
- data/ext/h3/src/docs/{overview/usecases.md → usecases.md} +6 -11
- data/ext/h3/src/scripts/binding_functions.sh +1 -1
- data/ext/h3/src/scripts/coverage.sh.in +1 -1
- data/ext/h3/src/scripts/update_version.sh +2 -2
- data/ext/h3/src/src/apps/applib/include/args.h +1 -0
- data/ext/h3/src/src/apps/applib/include/test.h +1 -0
- data/ext/h3/src/src/apps/applib/include/utility.h +7 -1
- data/ext/h3/src/src/apps/applib/lib/args.c +2 -0
- data/ext/h3/src/src/apps/applib/lib/kml.c +2 -0
- data/ext/h3/src/src/apps/applib/lib/test.c +1 -0
- data/ext/h3/src/src/apps/applib/lib/utility.c +133 -2
- data/ext/h3/src/src/apps/benchmarks/benchmarkH3Api.c +1 -1
- data/ext/h3/src/{website/html.config.js → src/apps/benchmarks/benchmarkH3UniEdge.c} +15 -12
- data/ext/h3/src/src/apps/filters/h3ToComponents.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToGeo.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToLocalIj.c +1 -0
- data/ext/h3/src/src/apps/filters/hexRange.c +1 -0
- data/ext/h3/src/src/apps/filters/kRing.c +1 -0
- data/ext/h3/src/src/apps/filters/localIjToH3.c +1 -0
- data/ext/h3/src/src/apps/miscapps/generateFaceCenterPoint.c +1 -0
- data/ext/h3/src/src/apps/miscapps/generateNumHexagons.c +1 -0
- data/ext/h3/src/src/apps/miscapps/generatePentagonDirectionFaces.c +67 -0
- data/ext/h3/src/src/apps/miscapps/h3ToGeoBoundaryHier.c +1 -0
- data/ext/h3/src/src/apps/miscapps/h3ToGeoHier.c +1 -0
- data/ext/h3/src/src/apps/miscapps/h3ToHier.c +1 -0
- data/ext/h3/src/src/apps/testapps/mkRandGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/mkRandGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/testapps/testBBox.c +1 -0
- data/ext/h3/src/src/apps/testapps/testBaseCells.c +15 -1
- data/ext/h3/src/src/apps/testapps/testCompact.c +109 -2
- data/ext/h3/src/src/apps/testapps/testCoordIj.c +1 -0
- data/ext/h3/src/src/apps/testapps/testGeoCoord.c +47 -8
- data/ext/h3/src/src/apps/testapps/testGeoToH3.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3Api.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3CellArea.c +47 -0
- data/ext/h3/src/src/apps/testapps/testH3CellAreaExhaustive.c +180 -0
- data/ext/h3/src/src/apps/testapps/testH3Distance.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3DistanceExhaustive.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3GetFaces.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3Index.c +33 -3
- data/ext/h3/src/src/apps/testapps/testH3Line.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3LineExhaustive.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3Memory.c +175 -0
- data/ext/h3/src/src/apps/testapps/testH3NeighborRotations.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3SetToLinkedGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3SetToVertexGraph.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToCenterChild.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToChildren.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +12 -6
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIjExhaustive.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToParent.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3UniEdge.c +45 -16
- data/ext/h3/src/src/apps/testapps/testH3UniEdgeExhaustive.c +111 -0
- data/ext/h3/src/src/apps/testapps/testHexRanges.c +1 -0
- data/ext/h3/src/src/apps/testapps/testHexRing.c +1 -0
- data/ext/h3/src/src/apps/testapps/testKRing.c +19 -0
- data/ext/h3/src/src/apps/testapps/testLinkedGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testMaxH3ToChildrenSize.c +1 -0
- data/ext/h3/src/src/apps/testapps/testPentagonIndexes.c +1 -0
- data/ext/h3/src/src/apps/testapps/testPolyfill.c +72 -9
- data/ext/h3/src/src/apps/testapps/testPolyfillReported.c +157 -0
- data/ext/h3/src/src/apps/testapps/testPolygon.c +27 -1
- data/ext/h3/src/src/apps/testapps/testVec2d.c +1 -0
- data/ext/h3/src/src/apps/testapps/testVec3d.c +1 -0
- data/ext/h3/src/src/apps/testapps/testVertex.c +66 -0
- data/ext/h3/src/src/apps/testapps/testVertexGraph.c +1 -0
- data/ext/h3/src/src/h3lib/include/algos.h +8 -0
- data/ext/h3/src/src/h3lib/include/alloc.h +40 -0
- data/ext/h3/src/src/h3lib/include/baseCells.h +4 -0
- data/ext/h3/src/src/h3lib/include/bbox.h +4 -1
- data/ext/h3/src/src/h3lib/include/faceijk.h +3 -2
- data/ext/h3/src/src/h3lib/include/geoCoord.h +2 -3
- data/ext/h3/src/src/h3lib/include/h3Index.h +37 -4
- data/ext/h3/src/src/h3lib/include/h3api.h.in +65 -17
- data/ext/h3/src/src/h3lib/include/linkedGeo.h +1 -0
- data/ext/h3/src/src/h3lib/include/polygon.h +1 -0
- data/ext/h3/src/src/h3lib/include/polygonAlgos.h +1 -0
- data/ext/h3/src/src/h3lib/include/vertex.h +44 -0
- data/ext/h3/src/src/h3lib/include/vertexGraph.h +1 -0
- data/ext/h3/src/src/h3lib/lib/algos.c +304 -76
- data/ext/h3/src/src/h3lib/lib/baseCells.c +26 -4
- data/ext/h3/src/src/h3lib/lib/bbox.c +56 -27
- data/ext/h3/src/src/h3lib/lib/coordijk.c +2 -0
- data/ext/h3/src/src/h3lib/lib/faceijk.c +32 -21
- data/ext/h3/src/src/h3lib/lib/geoCoord.c +162 -44
- data/ext/h3/src/src/h3lib/lib/h3Index.c +83 -42
- data/ext/h3/src/src/h3lib/lib/h3UniEdge.c +42 -57
- data/ext/h3/src/src/h3lib/lib/linkedGeo.c +20 -15
- data/ext/h3/src/src/h3lib/lib/localij.c +1 -1
- data/ext/h3/src/src/h3lib/lib/polygon.c +2 -0
- data/ext/h3/src/src/h3lib/lib/vec2d.c +1 -0
- data/ext/h3/src/src/h3lib/lib/vec3d.c +1 -0
- data/ext/h3/src/src/h3lib/lib/vertex.c +134 -0
- data/ext/h3/src/src/h3lib/lib/vertexGraph.c +8 -5
- data/ext/h3/src/website/.eslintignore +2 -0
- data/ext/h3/src/website/.gitignore +57 -0
- data/ext/h3/src/website/.nvmrc +1 -0
- data/ext/h3/src/website/README.md +8 -6
- data/ext/h3/src/website/gatsby-config.js +83 -0
- data/ext/h3/src/website/package.json +20 -12
- data/ext/h3/src/website/scripts/build-to-gh-pages.sh +7 -5
- data/ext/h3/src/website/src/.gitkeep +0 -0
- data/ext/h3/src/website/templates/documentation.jsx +129 -0
- data/ext/h3/src/website/yarn.lock +13723 -0
- data/h3.gemspec +2 -2
- data/lib/h3/bindings/base.rb +14 -4
- data/lib/h3/bindings/private.rb +12 -9
- data/lib/h3/hierarchy.rb +0 -18
- data/lib/h3/indexing.rb +0 -18
- data/lib/h3/inspection.rb +3 -59
- data/lib/h3/miscellaneous.rb +119 -14
- data/lib/h3/regions.rb +3 -0
- data/lib/h3/traversal.rb +0 -18
- data/lib/h3/unidirectional_edges.rb +5 -60
- data/lib/h3/version.rb +1 -1
- data/spec/geo_json_spec.rb +8 -0
- data/spec/miscellaneous_spec.rb +117 -0
- data/spec/{region_spec.rb → regions_spec.rb} +1 -1
- data/spec/spec_helper.rb +2 -2
- metadata +44 -36
- data/.travis.yml +0 -11
- data/ext/h3/src/.ycm_extra_conf.py +0 -92
- data/ext/h3/src/appveyor.yml +0 -50
- data/ext/h3/src/website/src/config.js +0 -46
- data/ext/h3/src/website/src/mdRoutes.js +0 -151
- data/ext/h3/src/website/src/styles/_variables.scss +0 -16
- data/ext/h3/src/website/src/styles/index.scss +0 -3
- data/ext/h3/src/website/static/index.html +0 -15
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 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
|
+
/** @file vertex.h
|
|
17
|
+
* @brief Functions for working with cell vertexes.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#ifndef H3VERTEX_H
|
|
21
|
+
#define H3VERTEX_H
|
|
22
|
+
|
|
23
|
+
#include "h3Index.h"
|
|
24
|
+
#include "faceijk.h"
|
|
25
|
+
|
|
26
|
+
/** @struct PentagonDirectionFaces
|
|
27
|
+
* @brief The faces in each axial direction of a given pentagon base cell
|
|
28
|
+
*/
|
|
29
|
+
typedef struct {
|
|
30
|
+
int baseCell; ///< base cell number
|
|
31
|
+
int faces[NUM_PENT_VERTS]; ///< face numbers for each axial direction,
|
|
32
|
+
/// in order, starting with J
|
|
33
|
+
} PentagonDirectionFaces;
|
|
34
|
+
|
|
35
|
+
/** Invalid vertex number */
|
|
36
|
+
#define INVALID_VERTEX_NUM -1
|
|
37
|
+
|
|
38
|
+
/** Max number of faces a base cell's descendants may appear on */
|
|
39
|
+
#define MAX_BASE_CELL_FACES 5
|
|
40
|
+
|
|
41
|
+
int vertexRotations(H3Index cell);
|
|
42
|
+
int vertexNumForDirection(const H3Index origin, const Direction direction);
|
|
43
|
+
|
|
44
|
+
#endif
|
|
@@ -18,12 +18,15 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
#include "algos.h"
|
|
21
|
+
|
|
21
22
|
#include <assert.h>
|
|
22
23
|
#include <float.h>
|
|
23
24
|
#include <math.h>
|
|
24
25
|
#include <stdbool.h>
|
|
25
26
|
#include <stdlib.h>
|
|
26
27
|
#include <string.h>
|
|
28
|
+
|
|
29
|
+
#include "alloc.h"
|
|
27
30
|
#include "baseCells.h"
|
|
28
31
|
#include "bbox.h"
|
|
29
32
|
#include "faceijk.h"
|
|
@@ -41,6 +44,9 @@
|
|
|
41
44
|
#define HEX_RANGE_SUCCESS 0
|
|
42
45
|
#define HEX_RANGE_PENTAGON 1
|
|
43
46
|
#define HEX_RANGE_K_SUBSEQUENCE 2
|
|
47
|
+
#define MAX_ONE_RING_SIZE 7
|
|
48
|
+
#define HEX_HASH_OVERFLOW -1
|
|
49
|
+
#define POLYFILL_BUFFER 12
|
|
44
50
|
|
|
45
51
|
/**
|
|
46
52
|
* Directions used for traversing a hexagonal ring counterclockwise around
|
|
@@ -150,74 +156,86 @@ static const Direction NEW_ADJUSTMENT_III[7][7] = {
|
|
|
150
156
|
CENTER_DIGIT, IJ_AXES_DIGIT}};
|
|
151
157
|
|
|
152
158
|
/**
|
|
153
|
-
* Maximum number of
|
|
159
|
+
* Maximum number of cells that result from the kRing algorithm with the given
|
|
154
160
|
* k. Formula source and proof: https://oeis.org/A003215
|
|
155
161
|
*
|
|
156
|
-
* @param
|
|
162
|
+
* @param k k value, k >= 0.
|
|
157
163
|
*/
|
|
158
164
|
int H3_EXPORT(maxKringSize)(int k) { return 3 * k * (k + 1) + 1; }
|
|
159
165
|
|
|
160
166
|
/**
|
|
161
|
-
*
|
|
167
|
+
* Produce cells within grid distance k of the origin cell.
|
|
162
168
|
*
|
|
163
|
-
* k-ring 0 is defined as the origin
|
|
164
|
-
* all neighboring
|
|
169
|
+
* k-ring 0 is defined as the origin cell, k-ring 1 is defined as k-ring 0 and
|
|
170
|
+
* all neighboring cells, and so on.
|
|
165
171
|
*
|
|
166
172
|
* Output is placed in the provided array in no particular order. Elements of
|
|
167
173
|
* the output array may be left zero, as can happen when crossing a pentagon.
|
|
168
174
|
*
|
|
169
|
-
* @param
|
|
170
|
-
* @param
|
|
171
|
-
* @param
|
|
175
|
+
* @param origin origin cell
|
|
176
|
+
* @param k k >= 0
|
|
177
|
+
* @param out zero-filled array which must be of size maxKringSize(k)
|
|
172
178
|
*/
|
|
173
179
|
void H3_EXPORT(kRing)(H3Index origin, int k, H3Index* out) {
|
|
174
|
-
|
|
175
|
-
int* distances = malloc(maxIdx * sizeof(int));
|
|
176
|
-
H3_EXPORT(kRingDistances)(origin, k, out, distances);
|
|
177
|
-
free(distances);
|
|
180
|
+
H3_EXPORT(kRingDistances)(origin, k, out, NULL);
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
/**
|
|
181
|
-
*
|
|
184
|
+
* Produce cells and their distances from the given origin cell, up to
|
|
185
|
+
* distance k.
|
|
182
186
|
*
|
|
183
|
-
* k-ring 0 is defined as the origin
|
|
184
|
-
* all neighboring
|
|
187
|
+
* k-ring 0 is defined as the origin cell, k-ring 1 is defined as k-ring 0 and
|
|
188
|
+
* all neighboring cells, and so on.
|
|
185
189
|
*
|
|
186
190
|
* Output is placed in the provided array in no particular order. Elements of
|
|
187
191
|
* the output array may be left zero, as can happen when crossing a pentagon.
|
|
188
192
|
*
|
|
189
|
-
* @param
|
|
190
|
-
* @param
|
|
191
|
-
* @param
|
|
192
|
-
* @param
|
|
193
|
+
* @param origin origin cell
|
|
194
|
+
* @param k k >= 0
|
|
195
|
+
* @param out zero-filled array which must be of size maxKringSize(k)
|
|
196
|
+
* @param distances NULL or a zero-filled array which must be of size
|
|
197
|
+
* maxKringSize(k)
|
|
193
198
|
*/
|
|
194
199
|
void H3_EXPORT(kRingDistances)(H3Index origin, int k, H3Index* out,
|
|
195
200
|
int* distances) {
|
|
196
|
-
const int maxIdx = H3_EXPORT(maxKringSize)(k);
|
|
197
201
|
// Optimistically try the faster hexRange algorithm first
|
|
198
202
|
const bool failed = H3_EXPORT(hexRangeDistances)(origin, k, out, distances);
|
|
199
203
|
if (failed) {
|
|
204
|
+
const int maxIdx = H3_EXPORT(maxKringSize)(k);
|
|
200
205
|
// Fast algo failed, fall back to slower, correct algo
|
|
201
206
|
// and also wipe out array because contents untrustworthy
|
|
202
|
-
memset(out, 0, maxIdx * sizeof(
|
|
203
|
-
|
|
204
|
-
|
|
207
|
+
memset(out, 0, maxIdx * sizeof(H3Index));
|
|
208
|
+
|
|
209
|
+
if (distances == NULL) {
|
|
210
|
+
distances = H3_MEMORY(calloc)(maxIdx, sizeof(int));
|
|
211
|
+
if (!distances) {
|
|
212
|
+
// TODO: Return an error code when this is not void
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
_kRingInternal(origin, k, out, distances, maxIdx, 0);
|
|
216
|
+
H3_MEMORY(free)(distances);
|
|
217
|
+
} else {
|
|
218
|
+
memset(distances, 0, maxIdx * sizeof(int));
|
|
219
|
+
_kRingInternal(origin, k, out, distances, maxIdx, 0);
|
|
220
|
+
}
|
|
205
221
|
}
|
|
206
222
|
}
|
|
207
223
|
|
|
208
224
|
/**
|
|
209
225
|
* Internal helper function called recursively for kRingDistances.
|
|
210
226
|
*
|
|
211
|
-
* Adds the origin
|
|
227
|
+
* Adds the origin cell to the output set (treating it as a hash set)
|
|
212
228
|
* and recurses to its neighbors, if needed.
|
|
213
229
|
*
|
|
214
|
-
* @param
|
|
215
|
-
* @param
|
|
216
|
-
* @param
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
230
|
+
* @param origin Origin cell
|
|
231
|
+
* @param k Maximum distance to move from the origin
|
|
232
|
+
* @param out Array treated as a hash set, elements being either
|
|
233
|
+
* H3Index or 0.
|
|
234
|
+
* @param distances Scratch area, with elements paralleling the out array.
|
|
235
|
+
* Elements indicate ijk distance from the origin cell to
|
|
236
|
+
* the output cell
|
|
237
|
+
* @param maxIdx Size of out and scratch arrays (must be maxKringSize(k))
|
|
238
|
+
* @param curK Current distance from the origin
|
|
221
239
|
*/
|
|
222
240
|
void _kRingInternal(H3Index origin, int k, H3Index* out, int* distances,
|
|
223
241
|
int maxIdx, int curK) {
|
|
@@ -260,7 +278,7 @@ void _kRingInternal(H3Index origin, int k, H3Index* out, int* distances,
|
|
|
260
278
|
* @param rotations Number of ccw rotations to perform to reorient the
|
|
261
279
|
* translation vector. Will be modified to the new number of
|
|
262
280
|
* rotations to perform (such as when crossing a face edge.)
|
|
263
|
-
* @return H3Index of the specified neighbor or
|
|
281
|
+
* @return H3Index of the specified neighbor or H3_NULL if deleted k-subsequence
|
|
264
282
|
* distortion is encountered.
|
|
265
283
|
*/
|
|
266
284
|
H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
|
|
@@ -299,7 +317,10 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
|
|
|
299
317
|
} else {
|
|
300
318
|
Direction oldDigit = H3_GET_INDEX_DIGIT(out, r + 1);
|
|
301
319
|
Direction nextDir;
|
|
302
|
-
if (
|
|
320
|
+
if (oldDigit == INVALID_DIGIT) {
|
|
321
|
+
// Only possible on invalid input
|
|
322
|
+
return H3_NULL;
|
|
323
|
+
} else if (isResClassIII(r + 1)) {
|
|
303
324
|
H3_SET_INDEX_DIGIT(out, r + 1, NEW_DIGIT_II[oldDigit][dir]);
|
|
304
325
|
nextDir = NEW_ADJUSTMENT_II[oldDigit][dir];
|
|
305
326
|
} else {
|
|
@@ -345,7 +366,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
|
|
|
345
366
|
// base cell.
|
|
346
367
|
if (oldLeadingDigit == CENTER_DIGIT) {
|
|
347
368
|
// Undefined: the k direction is deleted from here
|
|
348
|
-
return
|
|
369
|
+
return H3_NULL;
|
|
349
370
|
} else if (oldLeadingDigit == JK_AXES_DIGIT) {
|
|
350
371
|
// Rotate out of the deleted k subsequence
|
|
351
372
|
// We also need an additional change to the direction we're
|
|
@@ -360,7 +381,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
|
|
|
360
381
|
*rotations = *rotations + 5;
|
|
361
382
|
} else {
|
|
362
383
|
// Should never occur
|
|
363
|
-
return
|
|
384
|
+
return H3_NULL; // LCOV_EXCL_LINE
|
|
364
385
|
}
|
|
365
386
|
}
|
|
366
387
|
}
|
|
@@ -410,7 +431,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
|
|
|
410
431
|
* @return 0 if no pentagon or pentagonal distortion area was encountered.
|
|
411
432
|
*/
|
|
412
433
|
int H3_EXPORT(hexRange)(H3Index origin, int k, H3Index* out) {
|
|
413
|
-
return H3_EXPORT(hexRangeDistances)(origin, k, out,
|
|
434
|
+
return H3_EXPORT(hexRangeDistances)(origin, k, out, NULL);
|
|
414
435
|
}
|
|
415
436
|
|
|
416
437
|
/**
|
|
@@ -623,9 +644,8 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
|
623
644
|
* maxPolyfillSize returns the number of hexagons to allocate space for when
|
|
624
645
|
* performing a polyfill on the given GeoJSON-like data structure.
|
|
625
646
|
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* a Python application? ;)
|
|
647
|
+
* The size is the maximum of either the number of points in the geofence or the
|
|
648
|
+
* number of hexagons in the bounding box of the geofence.
|
|
629
649
|
*
|
|
630
650
|
* @param geoPolygon A GeoJSON-like data structure indicating the poly to fill
|
|
631
651
|
* @param res Hexagon resolution (0-15)
|
|
@@ -634,12 +654,23 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
|
634
654
|
int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
|
|
635
655
|
// Get the bounding box for the GeoJSON-like struct
|
|
636
656
|
BBox bbox;
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
//
|
|
641
|
-
// the
|
|
642
|
-
|
|
657
|
+
const Geofence geofence = geoPolygon->geofence;
|
|
658
|
+
bboxFromGeofence(&geofence, &bbox);
|
|
659
|
+
int numHexagons = bboxHexEstimate(&bbox, res);
|
|
660
|
+
// This algorithm assumes that the number of vertices is usually less than
|
|
661
|
+
// the number of hexagons, but when it's wrong, this will keep it from
|
|
662
|
+
// failing
|
|
663
|
+
int totalVerts = geofence.numVerts;
|
|
664
|
+
for (int i = 0; i < geoPolygon->numHoles; i++) {
|
|
665
|
+
totalVerts += geoPolygon->holes[i].numVerts;
|
|
666
|
+
}
|
|
667
|
+
if (numHexagons < totalVerts) numHexagons = totalVerts;
|
|
668
|
+
// When the polygon is very small, near an icosahedron edge and is an odd
|
|
669
|
+
// resolution, the line tracing needs an extra buffer than the estimator
|
|
670
|
+
// function provides (but beefing that up to cover causes most situations to
|
|
671
|
+
// overallocate memory)
|
|
672
|
+
numHexagons += POLYFILL_BUFFER;
|
|
673
|
+
return numHexagons;
|
|
643
674
|
}
|
|
644
675
|
|
|
645
676
|
/**
|
|
@@ -647,15 +678,109 @@ int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
|
|
|
647
678
|
* zeroed memory, and fills it with the hexagons that are contained by
|
|
648
679
|
* the GeoJSON-like data structure.
|
|
649
680
|
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
681
|
+
* This implementation traces the GeoJSON geofence(s) in cartesian space with
|
|
682
|
+
* hexagons, tests them and their neighbors to be contained by the geofence(s),
|
|
683
|
+
* and then any newly found hexagons are used to test again until no new
|
|
684
|
+
* hexagons are found.
|
|
653
685
|
*
|
|
654
686
|
* @param geoPolygon The geofence and holes defining the relevant area
|
|
655
687
|
* @param res The Hexagon resolution (0-15)
|
|
656
688
|
* @param out The slab of zeroed memory to write to. Assumed to be big enough.
|
|
657
689
|
*/
|
|
658
690
|
void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
691
|
+
// TODO: Eliminate this wrapper with the H3 4.0.0 release
|
|
692
|
+
int failure = _polyfillInternal(geoPolygon, res, out);
|
|
693
|
+
// The polyfill algorithm can theoretically fail if the allocated memory is
|
|
694
|
+
// not large enough for the polygon, but this should be impossible given the
|
|
695
|
+
// conservative overestimation of the number of hexagons possible.
|
|
696
|
+
// LCOV_EXCL_START
|
|
697
|
+
if (failure) {
|
|
698
|
+
int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
|
|
699
|
+
for (int i = 0; i < numHexagons; i++) out[i] = H3_NULL;
|
|
700
|
+
}
|
|
701
|
+
// LCOV_EXCL_STOP
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* _getEdgeHexagons takes a given geofence ring (either the main geofence or
|
|
706
|
+
* one of the holes) and traces it with hexagons and updates the search and
|
|
707
|
+
* found memory blocks. This is used for determining the initial hexagon set
|
|
708
|
+
* for the polyfill algorithm to execute on.
|
|
709
|
+
*
|
|
710
|
+
* @param geofence The geofence (or hole) to be traced
|
|
711
|
+
* @param numHexagons The maximum number of hexagons possible for the geofence
|
|
712
|
+
* (also the bounds of the search and found arrays)
|
|
713
|
+
* @param res The hexagon resolution (0-15)
|
|
714
|
+
* @param numSearchHexes The number of hexagons found so far to be searched
|
|
715
|
+
* @param search The block of memory containing the hexagons to search from
|
|
716
|
+
* @param found The block of memory containing the hexagons found from the
|
|
717
|
+
* search
|
|
718
|
+
*
|
|
719
|
+
* @return An error code if the hash function cannot insert a found hexagon
|
|
720
|
+
* into the found array.
|
|
721
|
+
*/
|
|
722
|
+
int _getEdgeHexagons(const Geofence* geofence, int numHexagons, int res,
|
|
723
|
+
int* numSearchHexes, H3Index* search, H3Index* found) {
|
|
724
|
+
for (int i = 0; i < geofence->numVerts; i++) {
|
|
725
|
+
GeoCoord origin = geofence->verts[i];
|
|
726
|
+
GeoCoord destination = i == geofence->numVerts - 1
|
|
727
|
+
? geofence->verts[0]
|
|
728
|
+
: geofence->verts[i + 1];
|
|
729
|
+
const int numHexesEstimate =
|
|
730
|
+
lineHexEstimate(&origin, &destination, res);
|
|
731
|
+
for (int j = 0; j < numHexesEstimate; j++) {
|
|
732
|
+
GeoCoord interpolate;
|
|
733
|
+
interpolate.lat =
|
|
734
|
+
(origin.lat * (numHexesEstimate - j) / numHexesEstimate) +
|
|
735
|
+
(destination.lat * j / numHexesEstimate);
|
|
736
|
+
interpolate.lon =
|
|
737
|
+
(origin.lon * (numHexesEstimate - j) / numHexesEstimate) +
|
|
738
|
+
(destination.lon * j / numHexesEstimate);
|
|
739
|
+
H3Index pointHex = H3_EXPORT(geoToH3)(&interpolate, res);
|
|
740
|
+
// A simple hash to store the hexagon, or move to another place if
|
|
741
|
+
// needed
|
|
742
|
+
int loc = (int)(pointHex % numHexagons);
|
|
743
|
+
int loopCount = 0;
|
|
744
|
+
while (found[loc] != 0) {
|
|
745
|
+
// If this conditional is reached, the `found` memory block is
|
|
746
|
+
// too small for the given polygon. This should not happen.
|
|
747
|
+
if (loopCount > numHexagons)
|
|
748
|
+
return HEX_HASH_OVERFLOW; // LCOV_EXCL_LINE
|
|
749
|
+
if (found[loc] == pointHex)
|
|
750
|
+
break; // At least two points of the geofence index to the
|
|
751
|
+
// same cell
|
|
752
|
+
loc = (loc + 1) % numHexagons;
|
|
753
|
+
loopCount++;
|
|
754
|
+
}
|
|
755
|
+
if (found[loc] == pointHex)
|
|
756
|
+
continue; // Skip this hex, already exists in the found hash
|
|
757
|
+
// Otherwise, set it in the found hash for now
|
|
758
|
+
found[loc] = pointHex;
|
|
759
|
+
|
|
760
|
+
search[*numSearchHexes] = pointHex;
|
|
761
|
+
(*numSearchHexes)++;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return 0;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* _polyfillInternal traces the provided geoPolygon data structure with hexagons
|
|
769
|
+
* and then iteratively searches through these hexagons and their immediate
|
|
770
|
+
* neighbors to see if they are contained within the polygon or not. Those that
|
|
771
|
+
* are found are added to the out array as well as the found array. Once all
|
|
772
|
+
* hexagons to search are checked, the found hexagons become the new search
|
|
773
|
+
* array and the found array is wiped and the process repeats until no new
|
|
774
|
+
* hexagons can be found.
|
|
775
|
+
*
|
|
776
|
+
* @param geoPolygon The geofence and holes defining the relevant area
|
|
777
|
+
* @param res The Hexagon resolution (0-15)
|
|
778
|
+
* @param out The slab of zeroed memory to write to. Assumed to be big enough.
|
|
779
|
+
*
|
|
780
|
+
* @return An error code if any of the hash operations fails to insert a hexagon
|
|
781
|
+
* into an array of memory.
|
|
782
|
+
*/
|
|
783
|
+
int _polyfillInternal(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
659
784
|
// One of the goals of the polyfill algorithm is that two adjacent polygons
|
|
660
785
|
// with zero overlap have zero overlapping hexagons. That the hexagons are
|
|
661
786
|
// uniquely assigned. There are a few approaches to take here, such as
|
|
@@ -674,39 +799,142 @@ void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
|
|
|
674
799
|
// This first part is identical to the maxPolyfillSize above.
|
|
675
800
|
|
|
676
801
|
// Get the bounding boxes for the polygon and any holes
|
|
677
|
-
BBox* bboxes = malloc((geoPolygon->numHoles + 1) * sizeof(BBox));
|
|
802
|
+
BBox* bboxes = H3_MEMORY(malloc)((geoPolygon->numHoles + 1) * sizeof(BBox));
|
|
678
803
|
assert(bboxes != NULL);
|
|
679
804
|
bboxesFromGeoPolygon(geoPolygon, bboxes);
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
//
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
//
|
|
693
|
-
//
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
805
|
+
|
|
806
|
+
// Get the estimated number of hexagons and allocate some temporary memory
|
|
807
|
+
// for the hexagons
|
|
808
|
+
int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
|
|
809
|
+
H3Index* search = H3_MEMORY(calloc)(numHexagons, sizeof(H3Index));
|
|
810
|
+
H3Index* found = H3_MEMORY(calloc)(numHexagons, sizeof(H3Index));
|
|
811
|
+
|
|
812
|
+
// Some metadata for tracking the state of the search and found memory
|
|
813
|
+
// blocks
|
|
814
|
+
int numSearchHexes = 0;
|
|
815
|
+
int numFoundHexes = 0;
|
|
816
|
+
|
|
817
|
+
// 1. Trace the hexagons along the polygon defining the outer geofence and
|
|
818
|
+
// add them to the search hash. The hexagon containing the geofence point
|
|
819
|
+
// may or may not be contained by the geofence (as the hexagon's center
|
|
820
|
+
// point may be outside of the boundary.)
|
|
821
|
+
const Geofence geofence = geoPolygon->geofence;
|
|
822
|
+
int failure = _getEdgeHexagons(&geofence, numHexagons, res, &numSearchHexes,
|
|
823
|
+
search, found);
|
|
824
|
+
// If this branch is reached, we have exceeded the maximum number of
|
|
825
|
+
// hexagons possible and need to clean up the allocated memory.
|
|
826
|
+
// LCOV_EXCL_START
|
|
827
|
+
if (failure) {
|
|
828
|
+
H3_MEMORY(free)(search);
|
|
829
|
+
H3_MEMORY(free)(found);
|
|
830
|
+
H3_MEMORY(free)(bboxes);
|
|
831
|
+
return failure;
|
|
832
|
+
}
|
|
833
|
+
// LCOV_EXCL_STOP
|
|
834
|
+
|
|
835
|
+
// 2. Iterate over all holes, trace the polygons defining the holes with
|
|
836
|
+
// hexagons and add to only the search hash. We're going to temporarily use
|
|
837
|
+
// the `found` hash to use for dedupe purposes and then re-zero it once
|
|
838
|
+
// we're done here, otherwise we'd have to scan the whole set on each insert
|
|
839
|
+
// to make sure there's no duplicates, which is very inefficient.
|
|
840
|
+
for (int i = 0; i < geoPolygon->numHoles; i++) {
|
|
841
|
+
Geofence* hole = &(geoPolygon->holes[i]);
|
|
842
|
+
failure = _getEdgeHexagons(hole, numHexagons, res, &numSearchHexes,
|
|
843
|
+
search, found);
|
|
844
|
+
// If this branch is reached, we have exceeded the maximum number of
|
|
845
|
+
// hexagons possible and need to clean up the allocated memory.
|
|
846
|
+
// LCOV_EXCL_START
|
|
847
|
+
if (failure) {
|
|
848
|
+
H3_MEMORY(free)(search);
|
|
849
|
+
H3_MEMORY(free)(found);
|
|
850
|
+
H3_MEMORY(free)(bboxes);
|
|
851
|
+
return failure;
|
|
698
852
|
}
|
|
699
|
-
//
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
853
|
+
// LCOV_EXCL_STOP
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// 3. Re-zero the found hash so it can be used in the main loop below
|
|
857
|
+
for (int i = 0; i < numHexagons; i++) found[i] = 0;
|
|
858
|
+
|
|
859
|
+
// 4. Begin main loop. While the search hash is not empty do the following
|
|
860
|
+
while (numSearchHexes > 0) {
|
|
861
|
+
// Iterate through all hexagons in the current search hash, then loop
|
|
862
|
+
// through all neighbors and test Point-in-Poly, if point-in-poly
|
|
863
|
+
// succeeds, add to out and found hashes if not already there.
|
|
864
|
+
int currentSearchNum = 0;
|
|
865
|
+
int i = 0;
|
|
866
|
+
while (currentSearchNum < numSearchHexes) {
|
|
867
|
+
H3Index ring[MAX_ONE_RING_SIZE] = {0};
|
|
868
|
+
H3Index searchHex = search[i];
|
|
869
|
+
H3_EXPORT(kRing)(searchHex, 1, ring);
|
|
870
|
+
for (int j = 0; j < MAX_ONE_RING_SIZE; j++) {
|
|
871
|
+
if (ring[j] == H3_NULL) {
|
|
872
|
+
continue; // Skip if this was a pentagon and only had 5
|
|
873
|
+
// neighbors
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
H3Index hex = ring[j];
|
|
877
|
+
|
|
878
|
+
// A simple hash to store the hexagon, or move to another place
|
|
879
|
+
// if needed. This MUST be done before the point-in-poly check
|
|
880
|
+
// since that's far more expensive
|
|
881
|
+
int loc = (int)(hex % numHexagons);
|
|
882
|
+
int loopCount = 0;
|
|
883
|
+
while (out[loc] != 0) {
|
|
884
|
+
// If this branch is reached, we have exceeded the maximum
|
|
885
|
+
// number of hexagons possible and need to clean up the
|
|
886
|
+
// allocated memory.
|
|
887
|
+
// LCOV_EXCL_START
|
|
888
|
+
if (loopCount > numHexagons) {
|
|
889
|
+
H3_MEMORY(free)(search);
|
|
890
|
+
H3_MEMORY(free)(found);
|
|
891
|
+
H3_MEMORY(free)(bboxes);
|
|
892
|
+
return -1;
|
|
893
|
+
}
|
|
894
|
+
// LCOV_EXCL_STOP
|
|
895
|
+
if (out[loc] == hex) break; // Skip duplicates found
|
|
896
|
+
loc = (loc + 1) % numHexagons;
|
|
897
|
+
loopCount++;
|
|
898
|
+
}
|
|
899
|
+
if (out[loc] == hex) {
|
|
900
|
+
continue; // Skip this hex, already exists in the out hash
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Check if the hexagon is in the polygon or not
|
|
904
|
+
GeoCoord hexCenter;
|
|
905
|
+
H3_EXPORT(h3ToGeo)(hex, &hexCenter);
|
|
906
|
+
|
|
907
|
+
// If not, skip
|
|
908
|
+
if (!pointInsidePolygon(geoPolygon, bboxes, &hexCenter)) {
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// Otherwise set it in the output array
|
|
913
|
+
out[loc] = hex;
|
|
914
|
+
|
|
915
|
+
// Set the hexagon in the found hash
|
|
916
|
+
found[numFoundHexes] = hex;
|
|
917
|
+
numFoundHexes++;
|
|
918
|
+
}
|
|
919
|
+
currentSearchNum++;
|
|
920
|
+
i++;
|
|
707
921
|
}
|
|
922
|
+
|
|
923
|
+
// Swap the search and found pointers, copy the found hex count to the
|
|
924
|
+
// search hex count, and zero everything related to the found memory.
|
|
925
|
+
H3Index* temp = search;
|
|
926
|
+
search = found;
|
|
927
|
+
found = temp;
|
|
928
|
+
for (int j = 0; j < numSearchHexes; j++) found[j] = 0;
|
|
929
|
+
numSearchHexes = numFoundHexes;
|
|
930
|
+
numFoundHexes = 0;
|
|
931
|
+
// Repeat until no new hexagons are found
|
|
708
932
|
}
|
|
709
|
-
|
|
933
|
+
// The out memory structure should be complete, end it here
|
|
934
|
+
H3_MEMORY(free)(bboxes);
|
|
935
|
+
H3_MEMORY(free)(search);
|
|
936
|
+
H3_MEMORY(free)(found);
|
|
937
|
+
return 0;
|
|
710
938
|
}
|
|
711
939
|
|
|
712
940
|
/**
|