/src/h3/src/h3lib/lib/polyfill.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2023 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 polyfill.c |
17 | | * @brief Functions relating to the cell-to-polygon algorithm |
18 | | */ |
19 | | |
20 | | #include "polyfill.h" |
21 | | |
22 | | #include <math.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include "alloc.h" |
26 | | #include "baseCells.h" |
27 | | #include "coordijk.h" |
28 | | #include "h3Assert.h" |
29 | | #include "h3Index.h" |
30 | | #include "polygon.h" |
31 | | |
32 | | // Factor by which to scale the cell bounding box to include all cells. |
33 | | // This was determined empirically by finding the smallest factor that |
34 | | // passed exhaustive tests. |
35 | 16.8M | #define CELL_SCALE_FACTOR 1.1 |
36 | | |
37 | | // Factor by which to scale the cell bounding box to include all children. |
38 | | // This was determined empirically by finding the smallest factor that |
39 | | // passed exhaustive tests. |
40 | 16.9M | #define CHILD_SCALE_FACTOR 1.4 |
41 | | |
42 | | /** |
43 | | * Max cell edge length, in radians, for each resolution. This was computed |
44 | | * by taking the max exact edge length for cells at the center of each base |
45 | | * cell at that resolution. |
46 | | */ |
47 | | static double MAX_EDGE_LENGTH_RADS[MAX_H3_RES + 1] = { |
48 | | 0.21577206265130, 0.08308767068495, 0.03148970436439, 0.01190662871439, |
49 | | 0.00450053330908, 0.00170105523619, 0.00064293917678, 0.00024300820659, |
50 | | 0.00009184847087, 0.00003471545901, 0.00001312121017, 0.00000495935129, |
51 | | 0.00000187445860, 0.00000070847876, 0.00000026777980, 0.00000010121125}; |
52 | | |
53 | | /** All cells that contain the north pole, by res */ |
54 | | static H3Index NORTH_POLE_CELLS[MAX_H3_RES + 1] = { |
55 | | 0x8001fffffffffff, 0x81033ffffffffff, 0x820327fffffffff, 0x830326fffffffff, |
56 | | 0x8403263ffffffff, 0x85032623fffffff, 0x860326237ffffff, 0x870326233ffffff, |
57 | | 0x880326233bfffff, 0x890326233abffff, 0x8a0326233ab7fff, 0x8b0326233ab0fff, |
58 | | 0x8c0326233ab03ff, 0x8d0326233ab03bf, 0x8e0326233ab039f, 0x8f0326233ab0399}; |
59 | | |
60 | | /** All cells that contain the south pole, by res */ |
61 | | static H3Index SOUTH_POLE_CELLS[MAX_H3_RES + 1] = { |
62 | | 0x80f3fffffffffff, 0x81f2bffffffffff, 0x82f297fffffffff, 0x83f293fffffffff, |
63 | | 0x84f2939ffffffff, 0x85f29383fffffff, 0x86f29380fffffff, 0x87f29380effffff, |
64 | | 0x88f29380e1fffff, 0x89f29380e0fffff, 0x8af29380e0d7fff, 0x8bf29380e0d0fff, |
65 | | 0x8cf29380e0d0dff, 0x8df29380e0d0cff, 0x8ef29380e0d0cc7, 0x8ff29380e0d0cc4}; |
66 | | |
67 | | /** Pre-calculated bounding boxes for all res 0 cells */ |
68 | | static BBox RES0_BBOXES[NUM_BASE_CELLS] = { |
69 | | {1.52480158339146, 1.20305471830087, -0.60664883654036, 0.00568297271999}, |
70 | | {1.52480158339146, 1.17872424267511, -0.60664883654036, 2.54046980298264}, |
71 | | {1.52480158339146, 1.09069387298096, -2.85286053297673, 1.64310689027893}, |
72 | | {1.41845302535151, 1.01285145697208, 0.00568297271999, -1.16770379632602}, |
73 | | {1.27950477868453, 0.97226652536306, 0.55556064983494, -0.18229924845326}, |
74 | | {1.32929586572429, 0.91898920750071, 2.05622344943192, 1.08813154278274}, |
75 | | {1.32899086063916, 0.94271815376360, -2.29875289606378, 3.01700008041993}, |
76 | | {1.26020983864103, 0.84291228415618, -0.89971867664861, -1.75967359310997}, |
77 | | {1.21114673854945, 0.86170600921069, 1.19129757609455, 0.43777608996454}, |
78 | | {1.21075831414294, 0.83795331049498, -1.72022875779891, -2.43793861727138}, |
79 | | {1.15546530929588, 0.78982455384253, 2.53659412229266, 1.85709133451243}, |
80 | | {1.15528445067052, 0.76641428724335, -3.06738507202411, 2.53646110244042}, |
81 | | {1.10121643537669, 0.71330093663066, 0.09640581900154, -0.52154514518248}, |
82 | | {1.07042472765165, 0.67603948819406, -0.47984202840088, -1.10306159603090}, |
83 | | {1.03270228748960, 0.72356358827215, -2.24990138725146, -2.74510220919157}, |
84 | | {1.01929924623886, 0.65491232835426, 0.63035574240731, 0.03537030096470}, |
85 | | {1.01786037568858, 0.58827636737638, 1.53192721817065, 0.93672682511233}, |
86 | | {0.98081434136020, 0.61076063532947, -2.67100636598529, 3.06516463008733}, |
87 | | {0.98106023192774, 0.58679836571570, 2.02829766214461, 1.51334374970280}, |
88 | | {0.96374551790056, 0.55186491737474, -1.42976721313659, -1.96852202530104}, |
89 | | {0.87536136210723, 0.50008952762292, -1.92435613571430, -2.41641343219793}, |
90 | | {0.88611243445554, 0.52742963716774, -0.95781946324194, -1.47628966305930}, |
91 | | {0.86881343251986, 0.50770567021439, 1.03236795495839, 0.50347284027426}, |
92 | | {0.89235638181782, 0.48781264892508, 2.76430302119150, 2.29989716697031}, |
93 | | {0.82570569254601, 0.52173101741059, 2.30921681461428, 1.93198541828980}, |
94 | | {0.80599330438546, 0.40150819579319, -3.06417559403240, 2.70079300784409}, |
95 | | {0.81612079704781, 0.38396800633226, -0.21614378891839, -0.70420149722178}, |
96 | | {0.75822779851431, 0.39943555383751, -2.34059978084699, -2.82127373822444}, |
97 | | {0.78861390967531, 0.38742018303868, 0.23115687731652, -0.22599491086066}, |
98 | | {0.71515840341957, 0.33012478438475, -0.64847976163163, -1.08249728121219}, |
99 | | {0.70359051048414, 0.29148673180722, 1.71441081857246, 1.28443348381696}, |
100 | | {0.69190629544818, 0.28808313184381, 0.64863909244647, 0.16372369282557}, |
101 | | {0.64863235654749, 0.26290420067147, 2.10318098268379, 1.69556122548344}, |
102 | | {0.65722892279906, 0.28222653310929, 1.30918693285466, 0.87594416271685}, |
103 | | {0.64750997738584, 0.24149865709850, -1.30272192474556, -1.68708570163242}, |
104 | | {0.62380174028378, 0.25522080363509, -2.72428423026826, 3.10401473237630}, |
105 | | {0.64228460410023, 0.21206753429148, -1.67639240992071, -2.11772366767341}, |
106 | | {0.59919175361146, 0.21620460836570, 2.48592868387690, 2.07350353893591}, |
107 | | {0.55637406851384, 0.25276557437230, -0.99885388505694, -1.32642489358939}, |
108 | | {0.55648013300665, 0.15187401321019, 2.87032088421324, 2.44642320475367}, |
109 | | {0.54603687970450, 0.15589091511369, -2.06789866067060, -2.49091419631961}, |
110 | | {0.51206347752697, 0.15522020377124, 0.95446767315996, 0.54443262110414}, |
111 | | {0.49767951537101, 0.10944898890579, -0.04335162263358, -0.42900268178569}, |
112 | | {0.46538045483671, 0.06029968637720, -0.41240613713421, -0.80603623808166}, |
113 | | {0.44686891066946, 0.06926857458503, 0.32053284794952, -0.07005748900849}, |
114 | | {0.43208958202064, 0.07796440938140, -3.06232453079660, 2.80602499990282}, |
115 | | {0.43103892586713, 0.02927431919853, -2.41589238618422, -2.85735809951951}, |
116 | | {0.38073727558986, -0.00297016159959, -0.77039553861218, -1.14788248745028}, |
117 | | {0.39113816687141, -0.01518764903038, 1.49130246958290, 1.14714731736311}, |
118 | | {0.33421063142418, 0.02526613430348, 1.15141032578749, 0.85000706261644}, |
119 | | {0.38915669778582, -0.04371359825454, 1.88046353933242, 1.48230231380717}, |
120 | | {0.33787520825987, -0.04835090128296, -1.12274014380603, -1.49454408844749}, |
121 | | {0.33601418932337, -0.06675068178541, 2.23792354204464, 1.85723423013211}, |
122 | | {0.31838318078049, -0.05821955623722, 0.66058854060373, 0.25452572938783}, |
123 | | {0.33630761471457, -0.07589541031521, -1.47957331741818, -1.85981735718264}, |
124 | | {0.28924817322870, -0.09150638064667, -1.83561930288569, -2.21855897384292}, |
125 | | {0.26678632252475, -0.10058088990867, -2.76808651991421, 3.12792953247061}, |
126 | | {0.29285254112587, -0.13483165093783, 2.61406468380434, 2.20466422911705}, |
127 | | {0.20150342788824, -0.10279852729762, 0.06881896344365, -0.23925229432978}, |
128 | | {0.21283813275258, -0.18626835417891, 2.93800440256577, 2.57470747655623}, |
129 | | {0.19587614179884, -0.17237030304155, -2.16941795427335, -2.55405165906601}, |
130 | | {0.17237030304155, -0.19587614179884, 0.97217469931645, 0.58754099452378}, |
131 | | {0.18626835417891, -0.21283813275258, -0.20358825102402, -0.56688517703356}, |
132 | | {0.10279852729762, -0.20150342788824, -3.07277369014614, 2.90234035926002}, |
133 | | {0.13483165093783, -0.29285254112587, -0.52752796978545, -0.93692842447275}, |
134 | | {0.10058088990867, -0.26678632252475, 0.37350613367558, -0.01366312111919}, |
135 | | {0.09150638064667, -0.28924817322870, 1.30597335070410, 0.92303367974687}, |
136 | | {0.07589541031521, -0.33630761471457, 1.66201933617161, 1.28177529640715}, |
137 | | {0.05821955623722, -0.31838318078049, -2.48100411298606, -2.88706692420196}, |
138 | | {0.06675068178541, -0.33601418932337, -0.90366911154516, -1.28435842345769}, |
139 | | {0.04835090128296, -0.33787520825987, 2.01885250978376, 1.64704856514230}, |
140 | | {0.04371359825454, -0.38915669778582, -1.26112911425737, -1.65929033978262}, |
141 | | {-0.02526613430348, -0.33421063142418, -1.99018232780231, |
142 | | -2.29158559097336}, |
143 | | {0.01518764903038, -0.39113816687140, -1.65029018400690, -1.99444533622668}, |
144 | | {0.00297016159959, -0.38073727558986, 2.37119711497761, 1.99371016613951}, |
145 | | {-0.02927431919853, -0.43103892586713, 0.72570026740558, 0.28423455407029}, |
146 | | {-0.07796440938140, -0.43208958202064, 0.07926812279319, -0.33556765368697}, |
147 | | {-0.06926857458503, -0.44686891066946, -2.82105980564027, 3.07153516458131}, |
148 | | {-0.06029968637720, -0.46538045483671, 2.72918651645558, 2.33555641550814}, |
149 | | {-0.10944898890579, -0.49767951537101, 3.09824103095621, 2.71258997180410}, |
150 | | {-0.15522020377124, -0.51206347752697, -2.18712498042983, |
151 | | -2.59716003248565}, |
152 | | {-0.15589091511369, -0.54603687970450, 1.07369399291919, 0.65067845727018}, |
153 | | {-0.15187401321019, -0.55648013300665, -0.27127176937655, |
154 | | -0.69516944883612}, |
155 | | {-0.25276557437230, -0.55637406851385, 2.14273876853285, 1.81516776000041}, |
156 | | {-0.21620460836570, -0.59919175361146, -0.65566396971290, |
157 | | -1.06808911465388}, |
158 | | {-0.21206753429148, -0.64228460410023, 1.46520024366909, 1.02386898591638}, |
159 | | {-0.25522080363509, -0.62380174028378, 0.41730842332153, -0.03757792121350}, |
160 | | {-0.24149865709850, -0.64750997738584, 1.83887072884423, 1.45450695195737}, |
161 | | {-0.28222653310929, -0.65722892279906, -1.83240572073513, |
162 | | -2.26564849087294}, |
163 | | {-0.26290420067147, -0.64863235654749, -1.03841167090601, |
164 | | -1.44603142810635}, |
165 | | {-0.28808313184381, -0.69190629544818, -2.49295356114332, |
166 | | -2.97786896076422}, |
167 | | {-0.29148673180722, -0.70359051048414, -1.42718183501734, |
168 | | -1.85715916977284}, |
169 | | {-0.33012478438475, -0.71515840341957, 2.49311289195816, 2.05909537237761}, |
170 | | {-0.38742018303868, -0.78861390967531, -2.91043577627328, 2.91559774272914}, |
171 | | {-0.39943555383751, -0.75822779851431, 0.80099287274280, 0.32031891536535}, |
172 | | {-0.38396800633226, -0.81612079704781, 2.92544886467140, 2.43739115636801}, |
173 | | {-0.40150819579319, -0.80599330438546, 0.07741705955739, -0.44079964574570}, |
174 | | {-0.52173101741059, -0.82570569254601, -0.83237583897551, |
175 | | -1.20960723529999}, |
176 | | {-0.48781264892508, -0.89235638181782, -0.37728963239830, |
177 | | -0.84169548661948}, |
178 | | {-0.50770567021439, -0.86881343251986, -2.10922469863141, |
179 | | -2.63811981331554}, |
180 | | {-0.52742963716774, -0.88611243445554, 2.18377319034785, 1.66530299053050}, |
181 | | {-0.50008952762292, -0.87536136210723, 1.21723651787549, 0.72517922139186}, |
182 | | {-0.55186491737474, -0.96374551790056, 1.71182544045320, 1.17307062828876}, |
183 | | {-0.58679836571570, -0.98106023192774, -1.11329499144518, |
184 | | -1.62824890388699}, |
185 | | {-0.61076063532947, -0.98081434136020, 0.47058628760450, -0.07642802350246}, |
186 | | {-0.58827636737638, -1.01786037568858, -1.60966543541914, |
187 | | -2.20486582847747}, |
188 | | {-0.65491232835426, -1.01929924623886, -2.51123691118248, |
189 | | -3.10622235262510}, |
190 | | {-0.72356358827215, -1.03270228748960, 0.89169126633833, 0.39649044439822}, |
191 | | {-0.67603948819406, -1.07042472765165, 2.66175062518892, 2.03853105755889}, |
192 | | {-0.71330093663066, -1.10121643537669, -3.04518683458825, 2.62004750840731}, |
193 | | {-0.76641428724335, -1.15528445067052, 0.07420758156568, -0.60513155114938}, |
194 | | {-0.78982455384253, -1.15546530929588, -0.60499853129713, |
195 | | -1.28450131907736}, |
196 | | {-0.83795331049498, -1.21075831414294, 1.42136389579088, 0.70365403631841}, |
197 | | {-0.86170600921069, -1.21114673854945, -1.95029507749525, |
198 | | -2.70381656362525}, |
199 | | {-0.84291228415618, -1.26020983864103, 2.24187397694118, 1.38191906047983}, |
200 | | {-0.94271815376360, -1.32899086063916, 0.84283975752601, -0.12459257316986}, |
201 | | {-0.91898920750071, -1.32929586572429, -1.08536920415787, |
202 | | -2.05346111080706}, |
203 | | {-0.97226652536306, -1.27950477868453, -2.58603200375485, 2.95929340513654}, |
204 | | {-1.01285145697208, -1.41845302535151, -3.13590968086981, 1.97388885726377}, |
205 | | {-1.09069387298096, -1.52480158339146, 0.28873212061306, -1.49848576331087}, |
206 | | {-1.17872424267511, -1.52480158339146, 2.53494381704943, -0.60112285060716}, |
207 | | {-1.20305471830087, -1.52480158339146, -0.60112285060716, |
208 | | 2.53494381704943}}; |
209 | | |
210 | | static BBox VALID_RANGE_BBOX = {M_PI_2, -M_PI_2, M_PI, -M_PI}; |
211 | | |
212 | | /** |
213 | | * For a given cell, return its bounding box. If coverChildren is true, the bbox |
214 | | * will be guaranteed to contain its children at any finer resolution. Note that |
215 | | * no guarantee is provided as to the level of accuracy, and the bounding box |
216 | | * may have a significant margin of error. |
217 | | * @param cell Cell to calculate bbox for |
218 | | * @param out BBox to hold output |
219 | | * @param coverChildren Whether the bounding box should cover all children |
220 | | */ |
221 | 33.7M | H3Error cellToBBox(H3Index cell, BBox *out, bool coverChildren) { |
222 | | // Adjust the BBox to handle poles, if needed |
223 | 33.7M | int res = H3_GET_RESOLUTION(cell); |
224 | | |
225 | 33.7M | if (res == 0) { |
226 | 1.00M | int baseCell = H3_GET_BASE_CELL(cell); |
227 | 1.00M | if (NEVER(baseCell < 0) || baseCell >= NUM_BASE_CELLS) { |
228 | 0 | return E_CELL_INVALID; |
229 | 0 | } |
230 | 1.00M | *out = RES0_BBOXES[baseCell]; |
231 | 32.7M | } else { |
232 | 32.7M | LatLng center; |
233 | 32.7M | H3Error centerErr = H3_EXPORT(cellToLatLng)(cell, ¢er); |
234 | 32.7M | if (centerErr != E_SUCCESS) { |
235 | 0 | return centerErr; |
236 | 0 | } |
237 | 32.7M | double lngRatio = 1 / cos(center.lat); |
238 | 32.7M | out->north = center.lat + MAX_EDGE_LENGTH_RADS[res]; |
239 | 32.7M | out->south = center.lat - MAX_EDGE_LENGTH_RADS[res]; |
240 | 32.7M | out->east = center.lng + MAX_EDGE_LENGTH_RADS[res] * lngRatio; |
241 | 32.7M | out->west = center.lng - MAX_EDGE_LENGTH_RADS[res] * lngRatio; |
242 | 32.7M | } |
243 | | |
244 | | // Buffer the bounding box to cover children. Call this even if no buffering |
245 | | // is required in order to normalize the bbox to lat/lng bounds |
246 | 33.7M | scaleBBox(out, coverChildren ? CHILD_SCALE_FACTOR : CELL_SCALE_FACTOR); |
247 | | |
248 | | // Cell that contains the north pole |
249 | 33.7M | if (cell == NORTH_POLE_CELLS[res]) { |
250 | 13.1k | out->north = M_PI_2; |
251 | 13.1k | } |
252 | | |
253 | | // Cell that contains the south pole |
254 | 33.7M | if (cell == SOUTH_POLE_CELLS[res]) { |
255 | 13.9k | out->south = -M_PI_2; |
256 | 13.9k | } |
257 | | |
258 | | // If we contain a pole, expand the longitude to include the full domain, |
259 | | // effectively making the bbox a circle around the pole. |
260 | 33.7M | if (out->north == M_PI_2 || out->south == -M_PI_2) { |
261 | 69.7k | out->east = M_PI; |
262 | 69.7k | out->west = -M_PI; |
263 | 69.7k | } |
264 | | |
265 | 33.7M | return E_SUCCESS; |
266 | 33.7M | } |
267 | | |
268 | | /** |
269 | | * Get a base cell by number, or H3_NULL if out of bounds |
270 | | */ |
271 | 1.01M | H3Index baseCellNumToCell(int baseCellNum) { |
272 | 1.01M | if (baseCellNum < 0 || baseCellNum >= NUM_BASE_CELLS) { |
273 | 8.11k | return H3_NULL; |
274 | 8.11k | } |
275 | 1.00M | H3Index baseCell; |
276 | 1.00M | setH3Index(&baseCell, 0, baseCellNum, 0); |
277 | 1.00M | return baseCell; |
278 | 1.01M | } |
279 | | |
280 | | static void iterErrorPolygonCompact(IterCellsPolygonCompact *iter, |
281 | 48 | H3Error error) { |
282 | 48 | iterDestroyPolygonCompact(iter); |
283 | 48 | iter->error = error; |
284 | 48 | } |
285 | | |
286 | | /** |
287 | | * Given a cell, find the next cell in the sequence of all cells |
288 | | * to check in the iteration. |
289 | | */ |
290 | 29.3M | static H3Index nextCell(H3Index cell) { |
291 | 29.3M | int res = H3_GET_RESOLUTION(cell); |
292 | 34.0M | while (true) { |
293 | | // If this is a base cell, set to next base cell (or H3_NULL if done) |
294 | 34.0M | if (res == 0) { |
295 | 1.00M | return baseCellNumToCell(H3_GET_BASE_CELL(cell) + 1); |
296 | 1.00M | } |
297 | | |
298 | | // Faster cellToParent when we know the resolution is valid |
299 | | // and we're only moving up one level |
300 | 33.0M | H3Index parent = cell; |
301 | 33.0M | H3_SET_RESOLUTION(parent, res - 1); |
302 | 33.0M | H3_SET_INDEX_DIGIT(parent, res, H3_DIGIT_MASK); |
303 | | |
304 | | // If not the last sibling of parent, return next sibling |
305 | 33.0M | Direction digit = H3_GET_INDEX_DIGIT(cell, res); |
306 | 33.0M | if (digit < INVALID_DIGIT - 1) { |
307 | 28.3M | H3_SET_INDEX_DIGIT(cell, res, |
308 | 28.3M | digit + ((H3_EXPORT(isPentagon)(parent) && |
309 | 28.3M | digit == CENTER_DIGIT) |
310 | 28.3M | ? 2 // Skip missing pentagon child |
311 | 28.3M | : 1)); |
312 | 28.3M | return cell; |
313 | 28.3M | } |
314 | | // Move up to the parent for the next loop iteration |
315 | 4.72M | res--; |
316 | 4.72M | cell = parent; |
317 | 4.72M | } |
318 | 29.3M | } |
319 | | |
320 | | /** |
321 | | * Internal function - initialize the iterator without stepping to the first |
322 | | * value |
323 | | */ |
324 | | static IterCellsPolygonCompact _iterInitPolygonCompact( |
325 | 8.46k | const GeoPolygon *polygon, int res, uint32_t flags) { |
326 | 8.46k | IterCellsPolygonCompact iter = {// Initialize output properties. The first |
327 | | // valid cell will be set in iterStep |
328 | 8.46k | .cell = baseCellNumToCell(0), |
329 | 8.46k | .error = E_SUCCESS, |
330 | | // Save input arguments |
331 | 8.46k | ._polygon = polygon, |
332 | 8.46k | ._res = res, |
333 | 8.46k | ._flags = flags, |
334 | 8.46k | ._bboxes = NULL, |
335 | 8.46k | ._started = false}; |
336 | | |
337 | 8.46k | if (res < 0 || res > MAX_H3_RES) { |
338 | 48 | iterErrorPolygonCompact(&iter, E_RES_DOMAIN); |
339 | 48 | return iter; |
340 | 48 | } |
341 | | |
342 | 8.42k | H3Error flagErr = validatePolygonFlags(flags); |
343 | 8.42k | if (flagErr) { |
344 | 0 | iterErrorPolygonCompact(&iter, flagErr); |
345 | 0 | return iter; |
346 | 0 | } |
347 | | |
348 | | // Initialize bounding boxes for polygon and any holes. Memory allocated |
349 | | // here must be released through iterDestroyPolygonCompact |
350 | 8.42k | iter._bboxes = H3_MEMORY(calloc)((polygon->numHoles + 1), sizeof(BBox)); |
351 | 8.42k | if (!iter._bboxes) { |
352 | 0 | iterErrorPolygonCompact(&iter, E_MEMORY_ALLOC); |
353 | 0 | return iter; |
354 | 0 | } |
355 | 8.42k | bboxesFromGeoPolygon(polygon, iter._bboxes); |
356 | | |
357 | 8.42k | return iter; |
358 | 8.42k | } |
359 | | |
360 | | /** |
361 | | * Initialize a IterCellsPolygonCompact struct representing the sequence of |
362 | | * compact cells within the target polygon. The test for including edge cells is |
363 | | * defined by the polyfill mode passed in the `flags` argument. |
364 | | * |
365 | | * Initialization of this object may fail, in which case the `error` property |
366 | | * will be set and all iteration will return H3_NULL. It is the responsibility |
367 | | * of the caller to check the error property after initialization. |
368 | | * |
369 | | * At any point in the iteration, starting once the struct is initialized, the |
370 | | * output value can be accessed through the `cell` property. |
371 | | * |
372 | | * Note that initializing the iterator allocates memory. If an iterator is |
373 | | * exhausted or returns an error that memory is released; otherwise it must be |
374 | | * released manually with iterDestroyPolygonCompact. |
375 | | * |
376 | | * @param polygon Polygon to fill with compact cells |
377 | | * @param res Finest resolution for output cells |
378 | | * @param flags Bit mask of option flags |
379 | | * @return Initialized iterator, with the first value available |
380 | | */ |
381 | | IterCellsPolygonCompact iterInitPolygonCompact(const GeoPolygon *polygon, |
382 | 4.14k | int res, uint32_t flags) { |
383 | 4.14k | IterCellsPolygonCompact iter = _iterInitPolygonCompact(polygon, res, flags); |
384 | | |
385 | | // Start the iterator by taking the first step. |
386 | | // This is necessary to have a valid value after initialization. |
387 | 4.14k | iterStepPolygonCompact(&iter); |
388 | | |
389 | 4.14k | return iter; |
390 | 4.14k | } |
391 | | |
392 | | /** |
393 | | * Increment the polyfill iterator, running the polygon to cells algorithm. |
394 | | * |
395 | | * Briefly, the algorithm checks every cell in the global grid hierarchically, |
396 | | * starting with the base cells. Cells coarser than the target resolution are |
397 | | * checked for complete child inclusion using a bounding box guaranteed to |
398 | | * contain all children. |
399 | | * - If the bounding box is contained by the polygon, output is set to the cell |
400 | | * - If the bounding box intersects, recurse into the first child |
401 | | * - Otherwise, continue with the next cell in sequence |
402 | | * |
403 | | * For cells at the target resolution, a finer-grained check is used according |
404 | | * to the inclusion criteria set in flags. |
405 | | * |
406 | | * @param iter Iterator to increment |
407 | | */ |
408 | 7.13M | void iterStepPolygonCompact(IterCellsPolygonCompact *iter) { |
409 | 7.13M | H3Index cell = iter->cell; |
410 | | |
411 | | // once the cell is H3_NULL, the iterator returns an infinite sequence of |
412 | | // H3_NULL |
413 | 7.13M | if (cell == H3_NULL) return; |
414 | | |
415 | | // For the first step, we need to evaluate the current cell; after that, we |
416 | | // should start with the next cell. |
417 | 7.13M | if (iter->_started) { |
418 | 7.12M | cell = nextCell(cell); |
419 | 7.12M | } else { |
420 | 8.42k | iter->_started = true; |
421 | 8.42k | } |
422 | | |
423 | | // Short-circuit iteration for 0-vert polygon |
424 | 7.13M | if (iter->_polygon->geoloop.numVerts == 0) { |
425 | 80 | iterDestroyPolygonCompact(iter); |
426 | 80 | return; |
427 | 80 | } |
428 | | |
429 | 7.13M | ContainmentMode mode = FLAG_GET_CONTAINMENT_MODE(iter->_flags); |
430 | | |
431 | 34.0M | while (cell) { |
432 | 34.0M | int cellRes = H3_GET_RESOLUTION(cell); |
433 | | |
434 | | // Target res: Do a fine-grained check |
435 | 34.0M | if (cellRes == iter->_res) { |
436 | 24.5M | if (mode == CONTAINMENT_CENTER || mode == CONTAINMENT_OVERLAPPING || |
437 | 19.8M | mode == CONTAINMENT_OVERLAPPING_BBOX) { |
438 | | // Check if the cell center is inside the polygon |
439 | 19.8M | LatLng center; |
440 | 19.8M | H3Error centerErr = H3_EXPORT(cellToLatLng)(cell, ¢er); |
441 | 19.8M | if (centerErr != E_SUCCESS) { |
442 | 0 | iterErrorPolygonCompact(iter, centerErr); |
443 | 0 | return; |
444 | 0 | } |
445 | 19.8M | if (pointInsidePolygon(iter->_polygon, iter->_bboxes, |
446 | 19.8M | ¢er)) { |
447 | | // Set to next output |
448 | 3.88M | iter->cell = cell; |
449 | 3.88M | return; |
450 | 3.88M | } |
451 | 19.8M | } |
452 | 20.6M | if (mode == CONTAINMENT_OVERLAPPING || |
453 | 16.8M | mode == CONTAINMENT_OVERLAPPING_BBOX) { |
454 | | // For overlapping, we need to do a quick check to determine |
455 | | // whether the polygon is wholly contained by the cell. We |
456 | | // check the first polygon vertex, which if it is contained |
457 | | // could also mean we simply intersect. |
458 | | |
459 | | // Deferencing verts[0] is safe because we check numVerts above |
460 | 12.0M | LatLng firstVertex = iter->_polygon->geoloop.verts[0]; |
461 | | |
462 | | // We have to check whether the point is in the expected range |
463 | | // first, because out-of-bounds values will yield false |
464 | | // positives with latLngToCell |
465 | 12.0M | if (bboxContains(&VALID_RANGE_BBOX, &firstVertex)) { |
466 | 10.6M | H3Index polygonCell; |
467 | 10.6M | H3Error polygonCellErr = H3_EXPORT(latLngToCell)( |
468 | 10.6M | &(iter->_polygon->geoloop.verts[0]), cellRes, |
469 | 10.6M | &polygonCell); |
470 | 10.6M | if (NEVER(polygonCellErr != E_SUCCESS)) { |
471 | | // This should be unreachable with the bbox check |
472 | 0 | iterErrorPolygonCompact(iter, polygonCellErr); |
473 | 0 | return; |
474 | 0 | } |
475 | 10.6M | if (polygonCell == cell) { |
476 | | // Set to next output |
477 | 3.78k | iter->cell = cell; |
478 | 3.78k | return; |
479 | 3.78k | } |
480 | 10.6M | } |
481 | 12.0M | } |
482 | 20.6M | if (mode == CONTAINMENT_FULL || mode == CONTAINMENT_OVERLAPPING || |
483 | 16.8M | mode == CONTAINMENT_OVERLAPPING_BBOX) { |
484 | 16.8M | CellBoundary boundary; |
485 | 16.8M | H3Error boundaryErr = |
486 | 16.8M | H3_EXPORT(cellToBoundary)(cell, &boundary); |
487 | 16.8M | if (boundaryErr != E_SUCCESS) { |
488 | 0 | iterErrorPolygonCompact(iter, boundaryErr); |
489 | 0 | return; |
490 | 0 | } |
491 | 16.8M | BBox bbox; |
492 | 16.8M | H3Error bboxErr = cellToBBox(cell, &bbox, false); |
493 | 16.8M | if (NEVER(bboxErr != E_SUCCESS)) { |
494 | | // Should be unreachable - invalid cells would be caught in |
495 | | // the previous boundaryErr |
496 | 0 | iterErrorPolygonCompact(iter, bboxErr); |
497 | 0 | return; |
498 | 0 | } |
499 | | // Check if the cell is fully contained by the polygon |
500 | 16.8M | if ((mode == CONTAINMENT_FULL || |
501 | 12.0M | mode == CONTAINMENT_OVERLAPPING_BBOX) && |
502 | 12.9M | cellBoundaryInsidePolygon(iter->_polygon, iter->_bboxes, |
503 | 12.9M | &boundary, &bbox)) { |
504 | | // Set to next output |
505 | 549k | iter->cell = cell; |
506 | 549k | return; |
507 | 549k | } |
508 | | // For overlap, we've already checked for center point inclusion |
509 | | // above; if that failed, we only need to check for line |
510 | | // intersection |
511 | 16.2M | else if ((mode == CONTAINMENT_OVERLAPPING || |
512 | 12.4M | mode == CONTAINMENT_OVERLAPPING_BBOX) && |
513 | 12.0M | cellBoundaryCrossesPolygon( |
514 | 12.0M | iter->_polygon, iter->_bboxes, &boundary, &bbox)) { |
515 | | // Set to next output |
516 | 1.21M | iter->cell = cell; |
517 | 1.21M | return; |
518 | 1.21M | } |
519 | 16.8M | } |
520 | 18.8M | if (mode == CONTAINMENT_OVERLAPPING_BBOX) { |
521 | | // Get a bounding box containing all the cell's children, so |
522 | | // this can work for the max size calculation |
523 | 7.39M | BBox bbox; |
524 | 7.39M | H3Error bboxErr = cellToBBox(cell, &bbox, true); |
525 | 7.39M | if (bboxErr) { |
526 | 0 | iterErrorPolygonCompact(iter, bboxErr); |
527 | 0 | return; |
528 | 0 | } |
529 | 7.39M | if (bboxOverlapsBBox(&iter->_bboxes[0], &bbox)) { |
530 | 4.86M | CellBoundary bboxBoundary = bboxToCellBoundary(&bbox); |
531 | 4.86M | if ( |
532 | | // cell bbox contains the polygon |
533 | 4.86M | bboxContainsBBox(&bbox, &iter->_bboxes[0]) || |
534 | | // polygon contains cell bbox |
535 | 4.86M | pointInsidePolygon(iter->_polygon, iter->_bboxes, |
536 | 4.86M | &bboxBoundary.verts[0]) || |
537 | | // polygon crosses cell bbox |
538 | 4.80M | cellBoundaryCrossesPolygon(iter->_polygon, |
539 | 4.80M | iter->_bboxes, &bboxBoundary, |
540 | 4.80M | &bbox)) { |
541 | 350k | iter->cell = cell; |
542 | 350k | return; |
543 | 350k | } |
544 | 4.86M | } |
545 | 7.39M | } |
546 | 18.8M | } |
547 | | |
548 | | // Coarser cell: Check the bounding box |
549 | 28.0M | if (cellRes < iter->_res) { |
550 | | // Get a bounding box for all of the cell's children |
551 | 9.51M | BBox bbox; |
552 | 9.51M | H3Error bboxErr = cellToBBox(cell, &bbox, true); |
553 | 9.51M | if (bboxErr) { |
554 | 0 | iterErrorPolygonCompact(iter, bboxErr); |
555 | 0 | return; |
556 | 0 | } |
557 | 9.51M | if (bboxOverlapsBBox(&iter->_bboxes[0], &bbox)) { |
558 | | // Quick check for possible containment |
559 | 5.85M | if (bboxContainsBBox(&iter->_bboxes[0], &bbox)) { |
560 | 3.49M | CellBoundary bboxBoundary = bboxToCellBoundary(&bbox); |
561 | | // Do a fine-grained, more expensive check on the polygon |
562 | 3.49M | if (cellBoundaryInsidePolygon(iter->_polygon, iter->_bboxes, |
563 | 3.49M | &bboxBoundary, &bbox)) { |
564 | | // Bounding box is fully contained, so all children are |
565 | | // included. Set to next output. |
566 | 1.12M | iter->cell = cell; |
567 | 1.12M | return; |
568 | 1.12M | } |
569 | 3.49M | } |
570 | | // Otherwise, the intersecting bbox means we need to test all |
571 | | // children, starting with the first child |
572 | 4.72M | H3Index child; |
573 | 4.72M | H3Error childErr = |
574 | 4.72M | H3_EXPORT(cellToCenterChild)(cell, cellRes + 1, &child); |
575 | 4.72M | if (childErr) { |
576 | 0 | iterErrorPolygonCompact(iter, childErr); |
577 | 0 | return; |
578 | 0 | } |
579 | | // Restart the loop with the child cell |
580 | 4.72M | cell = child; |
581 | 4.72M | continue; |
582 | 4.72M | } |
583 | 9.51M | } |
584 | | |
585 | | // Find the next cell in the sequence of all cells and continue |
586 | 22.2M | cell = nextCell(cell); |
587 | 22.2M | } |
588 | | // If we make it out of the loop, we're done |
589 | 8.11k | iterDestroyPolygonCompact(iter); |
590 | 8.11k | } |
591 | | |
592 | | /** |
593 | | * Destroy an iterator, releasing any allocated memory. Iterators destroyed in |
594 | | * this manner are safe to use but will always return H3_NULL. |
595 | | * @param iter Iterator to destroy |
596 | | */ |
597 | 8.46k | void iterDestroyPolygonCompact(IterCellsPolygonCompact *iter) { |
598 | 8.46k | if (iter->_bboxes) { |
599 | 8.42k | H3_MEMORY(free)(iter->_bboxes); |
600 | 8.42k | } |
601 | 8.46k | iter->cell = H3_NULL; |
602 | 8.46k | iter->error = E_SUCCESS; |
603 | 8.46k | iter->_polygon = NULL; |
604 | 8.46k | iter->_res = -1; |
605 | 8.46k | iter->_flags = 0; |
606 | 8.46k | iter->_bboxes = NULL; |
607 | 8.46k | } |
608 | | |
609 | | /** |
610 | | * Initialize a IterCellsPolygon struct representing the sequence of |
611 | | * cells within the target polygon. The test for including edge cells is defined |
612 | | * by the polyfill mode passed in the `flags` argument. |
613 | | * |
614 | | * Initialization of this object may fail, in which case the `error` property |
615 | | * will be set and all iteration will return H3_NULL. It is the responsibility |
616 | | * of the caller to check the error property after initialization. |
617 | | * |
618 | | * At any point in the iteration, starting once the struct is initialized, the |
619 | | * output value can be accessed through the `cell` property. |
620 | | * |
621 | | * Note that initializing the iterator allocates memory. If an iterator is |
622 | | * exhausted or returns an error that memory is released; otherwise it must be |
623 | | * released manually with iterDestroyPolygon. |
624 | | * |
625 | | * @param polygon Polygon to fill with cells |
626 | | * @param res Resolution for output cells |
627 | | * @param flags Bit mask of option flags |
628 | | * @return Initialized iterator, with the first value available |
629 | | */ |
630 | | IterCellsPolygon iterInitPolygon(const GeoPolygon *polygon, int res, |
631 | 4.14k | uint32_t flags) { |
632 | | // Create the sub-iterator for compact cells |
633 | 4.14k | IterCellsPolygonCompact cellIter = |
634 | 4.14k | iterInitPolygonCompact(polygon, res, flags); |
635 | | // Create the sub-iterator for children |
636 | 4.14k | IterCellsChildren childIter = iterInitParent(cellIter.cell, res); |
637 | | |
638 | 4.14k | IterCellsPolygon iter = {.cell = childIter.h, |
639 | 4.14k | .error = cellIter.error, |
640 | 4.14k | ._cellIter = cellIter, |
641 | 4.14k | ._childIter = childIter}; |
642 | 4.14k | return iter; |
643 | 4.14k | } |
644 | | |
645 | | /** |
646 | | * Increment the polyfill iterator, outputting the latest cell at the |
647 | | * desired resolution. |
648 | | * |
649 | | * @param iter Iterator to increment |
650 | | */ |
651 | 71.6M | void iterStepPolygon(IterCellsPolygon *iter) { |
652 | 71.6M | if (iter->cell == H3_NULL) return; |
653 | | |
654 | | // See if there are more children to output |
655 | 71.6M | iterStepChild(&(iter->_childIter)); |
656 | 71.6M | if (iter->_childIter.h) { |
657 | 66.8M | iter->cell = iter->_childIter.h; |
658 | 66.8M | return; |
659 | 66.8M | } |
660 | | |
661 | | // Otherwise, increment the polyfill iterator |
662 | 4.72M | iterStepPolygonCompact(&(iter->_cellIter)); |
663 | 4.72M | if (iter->_cellIter.cell) { |
664 | 4.71M | _iterInitParent(iter->_cellIter.cell, iter->_cellIter._res, |
665 | 4.71M | &(iter->_childIter)); |
666 | 4.71M | iter->cell = iter->_childIter.h; |
667 | 4.71M | return; |
668 | 4.71M | } |
669 | | |
670 | | // All done, set to null and report errors if any |
671 | 3.18k | iter->cell = H3_NULL; |
672 | 3.18k | iter->error = iter->_cellIter.error; |
673 | 3.18k | } |
674 | | |
675 | | /** |
676 | | * Destroy an iterator, releasing any allocated memory. Iterators destroyed in |
677 | | * this manner are safe to use but will always return H3_NULL. |
678 | | * @param iter Iterator to destroy |
679 | | */ |
680 | 228 | void iterDestroyPolygon(IterCellsPolygon *iter) { |
681 | 228 | iterDestroyPolygonCompact(&(iter->_cellIter)); |
682 | | // null out the child iterator by passing H3_NULL |
683 | 228 | _iterInitParent(H3_NULL, 0, &(iter->_childIter)); |
684 | 228 | iter->cell = H3_NULL; |
685 | 228 | iter->error = E_SUCCESS; |
686 | 228 | } |
687 | | |
688 | | /** |
689 | | * polygonToCells takes a given GeoJSON-like data structure and preallocated, |
690 | | * zeroed memory, and fills it with the hexagons that are contained by |
691 | | * the GeoJSON-like data structure. Polygons are considered in Cartesian space. |
692 | | * |
693 | | * @param polygon The geoloop and holes defining the relevant area |
694 | | * @param res The Hexagon resolution (0-15) |
695 | | * @param flags Algorithm flags such as containment mode |
696 | | * @param size Maximum number of indexes to write to `out`. |
697 | | * @param out The slab of zeroed memory to write to. Must be at least of size |
698 | | * `size`. |
699 | | */ |
700 | | H3Error H3_EXPORT(polygonToCellsExperimental)(const GeoPolygon *polygon, |
701 | | int res, uint32_t flags, |
702 | 4.14k | int64_t size, H3Index *out) { |
703 | 4.14k | IterCellsPolygon iter = iterInitPolygon(polygon, res, flags); |
704 | 4.14k | int64_t i = 0; |
705 | 71.6M | for (; iter.cell; iterStepPolygon(&iter)) { |
706 | 71.6M | if (i >= size) { |
707 | 228 | iterDestroyPolygon(&iter); |
708 | 228 | return E_MEMORY_BOUNDS; |
709 | 228 | } |
710 | 71.6M | out[i++] = iter.cell; |
711 | 71.6M | } |
712 | 3.92k | return iter.error; |
713 | 4.14k | } |
714 | | |
715 | | static int MAX_SIZE_CELL_THRESHOLD = 10; |
716 | | |
717 | 9.73k | static double getAverageCellArea(int res) { |
718 | 9.73k | double hexAreaKm2; |
719 | 9.73k | H3_EXPORT(getHexagonAreaAvgKm2)(res, &hexAreaKm2); |
720 | 9.73k | return hexAreaKm2; |
721 | 9.73k | } |
722 | | |
723 | | /** |
724 | | * maxPolygonToCellsSize returns the number of cells to allocate space for |
725 | | * when performing a polygonToCells on the given GeoJSON-like data structure. |
726 | | * @param polygon A GeoJSON-like data structure indicating the poly to fill |
727 | | * @param res Hexagon resolution (0-15) |
728 | | * @param flags Bit mask of option flags |
729 | | * @param out number of cells to allocate for |
730 | | * @return 0 (E_SUCCESS) on success. |
731 | | */ |
732 | | H3Error H3_EXPORT(maxPolygonToCellsSizeExperimental)(const GeoPolygon *polygon, |
733 | | int res, uint32_t flags, |
734 | 4.43k | int64_t *out) { |
735 | | // Special case: 0-vertex polygon |
736 | 4.43k | if (polygon->geoloop.numVerts == 0) { |
737 | 112 | *out = 0; |
738 | 112 | return E_SUCCESS; |
739 | 112 | } |
740 | | |
741 | | // Initialize the iterator without stepping, so we can adjust the res and |
742 | | // flags (after they are validated by the initialization) before we start |
743 | 4.32k | IterCellsPolygonCompact iter = _iterInitPolygonCompact(polygon, res, flags); |
744 | | |
745 | 4.32k | if (iter.error) { |
746 | 16 | return iter.error; |
747 | 16 | } |
748 | | |
749 | | // Ignore the requested flags and use the faster overlapping-bbox mode |
750 | 4.30k | iter._flags = CONTAINMENT_OVERLAPPING_BBOX; |
751 | | |
752 | | // Get a (very) rough area of the polygon bounding box |
753 | 4.30k | BBox *polygonBBox = &iter._bboxes[0]; |
754 | 4.30k | double polygonBBoxAreaKm2 = |
755 | 4.30k | bboxHeightRads(polygonBBox) * bboxWidthRads(polygonBBox) / |
756 | 4.30k | cos(fmin(fabs(polygonBBox->north), fabs(polygonBBox->south))) * |
757 | 4.30k | EARTH_RADIUS_KM * EARTH_RADIUS_KM; |
758 | | |
759 | | // Determine the res for the size estimate, based on a (very) rough estimate |
760 | | // of the number of cells at various resolutions that would fit in the |
761 | | // polygon. All we need here is a general order of magnitude. |
762 | 12.4k | while (iter._res > 0 && |
763 | 9.73k | polygonBBoxAreaKm2 / getAverageCellArea(iter._res - 1) > |
764 | 9.73k | MAX_SIZE_CELL_THRESHOLD) { |
765 | 8.09k | iter._res--; |
766 | 8.09k | } |
767 | | |
768 | | // Now run the polyfill, counting the output in the target res. |
769 | | // We have to take the first step outside the loop, to get the first |
770 | | // valid output cell |
771 | 4.30k | iterStepPolygonCompact(&iter); |
772 | | |
773 | 4.30k | *out = 0; |
774 | 4.30k | int64_t childrenSize; |
775 | 2.41M | for (; iter.cell; iterStepPolygonCompact(&iter)) { |
776 | 2.40M | H3_EXPORT(cellToChildrenSize)(iter.cell, res, &childrenSize); |
777 | 2.40M | *out += childrenSize; |
778 | 2.40M | } |
779 | | |
780 | 4.30k | return iter.error; |
781 | 4.32k | } |