h3 3.6.0 → 3.7.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
/**
|