The Tiny HTM Library
|
00001 00014 #include "tinyhtm/htm.h" 00015 00016 #include <stdlib.h> 00017 00018 #include "tinyhtm/tree.h" 00019 #include "tinyhtm/varint.h" 00020 00021 00022 #ifdef __cplusplus 00023 extern "C" { 00024 #endif 00025 00026 00027 /* 00028 HTM triangles are subdivided into 4 sub-triangles as follows : 00029 00030 v2 00031 * 00032 / \ 00033 / \ 00034 sv1 *-----* sv0 00035 / \ / \ 00036 / \ / \ 00037 v0 *-----*-----* v1 00038 sv2 00039 00040 - vertices are unit magnitude 3-vectors 00041 - edges are great circles on the unit sphere 00042 - vertices are stored in counter-clockwise order 00043 (when viewed from outside the unit sphere in a 00044 right handed coordinate system) 00045 - sv0 = (v1 + v2) / ||v1 + v2||, and likewise for sv1, sv2 00046 00047 Note that if the HTM triangle given by (v0,v1,v2) has index I, then: 00048 - sub triangle T0 = (v0,sv2,sv1) has index I*4 00049 - sub triangle T1 = (v1,sv0,sv2) has index I*4 + 1 00050 - sub triangle T2 = (v2,sv1,sv0) has index I*4 + 2 00051 - sub triangle T3 = (sv0,sv1,sv2) has index I*4 + 3 00052 00053 All HTM triangles are obtained via subdivision of 8 initial 00054 triangles, defined from the following set of 6 vertices : 00055 - V0 = ( 0, 0, 1) north pole 00056 - V1 = ( 1, 0, 0) 00057 - V2 = ( 0, 1, 0) 00058 - V3 = (-1, 0, 0) 00059 - V4 = ( 0, -1, 0) 00060 - V5 = ( 0, 0, -1) south pole 00061 00062 The root triangles (corresponding to subdivision level 0) are : 00063 - S0 = (V1, V5, V2), HTM index = 8 00064 - S1 = (V2, V5, V3), HTM index = 9 00065 - S2 = (V3, V5, V4), HTM index = 10 00066 - S3 = (V4, V5, V1), HTM index = 11 00067 - N0 = (V1, V0, V4), HTM index = 12 00068 - N1 = (V4, V0, V3), HTM index = 13 00069 - N2 = (V3, V0, V2), HTM index = 14 00070 - N3 = (V2, V0, V1), HTM index = 15 00071 00072 'S' denotes a triangle in the southern hemisphere, 00073 'N' denotes a triangle in the northern hemisphere. 00074 */ 00075 00076 00077 /* ---- Types ---- */ 00078 00081 enum _htm_cov { 00082 HTM_DISJOINT = 0, 00083 HTM_INTERSECT = 1, 00084 HTM_CONTAINS = 2, 00085 HTM_INSIDE = 3 00086 }; 00087 00090 struct _htm_node { 00091 struct htm_v3 mid_vert[3]; 00092 struct htm_v3 mid_edge[3]; 00093 const struct htm_v3 *vert[3]; 00094 const struct htm_v3 *edge[3]; 00095 struct htm_v3p *end; 00096 const unsigned char *s; 00097 uint64_t index; 00098 int64_t id; 00099 int child; 00100 }; 00101 00104 struct _htm_path { 00105 enum htm_root root; 00106 struct _htm_node node[HTM_MAX_LEVEL + 1]; 00107 }; 00108 00109 00110 /* ---- Data ---- */ 00111 00112 /* HTM root triangle vertices/edge plane normals. 00113 */ 00114 static const struct htm_v3 _htm_root_v3[6] = { 00115 { 0.0, 0.0, 1.0 }, 00116 { 1.0, 0.0, 0.0 }, 00117 { 0.0, 1.0, 0.0 }, 00118 {-1.0, 0.0, 0.0 }, 00119 { 0.0, -1.0, 0.0 }, 00120 { 0.0, 0.0, -1.0 } 00121 }; 00122 00123 #define HTM_Z &_htm_root_v3[0] 00124 #define HTM_X &_htm_root_v3[1] 00125 #define HTM_Y &_htm_root_v3[2] 00126 #define HTM_NX &_htm_root_v3[3] 00127 #define HTM_NY &_htm_root_v3[4] 00128 #define HTM_NZ &_htm_root_v3[5] 00129 00130 /* Vertex pointers for the 3 vertices of each HTM root triangle. 00131 */ 00132 static const struct htm_v3 * const _htm_root_vert[24] = { 00133 HTM_X, HTM_NZ, HTM_Y, /* S0 */ 00134 HTM_Y, HTM_NZ, HTM_NX, /* S1 */ 00135 HTM_NX, HTM_NZ, HTM_NY, /* S2 */ 00136 HTM_NY, HTM_NZ, HTM_X, /* S3 */ 00137 HTM_X, HTM_Z, HTM_NY, /* N0 */ 00138 HTM_NY, HTM_Z, HTM_NX, /* N1 */ 00139 HTM_NX, HTM_Z, HTM_Y, /* N2 */ 00140 HTM_Y, HTM_Z, HTM_X /* N3 */ 00141 }; 00142 00143 /* Edge normal pointers for the 3 edge normals of each HTM root triangle. 00144 */ 00145 static const struct htm_v3 * const _htm_root_edge[24] = { 00146 HTM_Y, HTM_X, HTM_NZ, /* S0 */ 00147 HTM_NX, HTM_Y, HTM_NZ, /* S1 */ 00148 HTM_NY, HTM_NX, HTM_NZ, /* S2 */ 00149 HTM_X, HTM_NY, HTM_NZ, /* S3 */ 00150 HTM_NY, HTM_X, HTM_Z, /* N0 */ 00151 HTM_NX, HTM_NY, HTM_Z, /* N1 */ 00152 HTM_Y, HTM_NX, HTM_Z, /* N2 */ 00153 HTM_X, HTM_Y, HTM_Z /* N3 */ 00154 }; 00155 00156 00157 /* ---- Implementation details ---- */ 00158 00159 /* Sets path to the i-th HTM root triangle. 00160 */ 00161 HTM_INLINE void _htm_path_root(struct _htm_path *path, enum htm_root r) 00162 { 00163 path->node[0].vert[0] = _htm_root_vert[r*3]; 00164 path->node[0].vert[1] = _htm_root_vert[r*3 + 1]; 00165 path->node[0].vert[2] = _htm_root_vert[r*3 + 2]; 00166 path->node[0].edge[0] = _htm_root_edge[r*3]; 00167 path->node[0].edge[1] = _htm_root_edge[r*3 + 1]; 00168 path->node[0].edge[2] = _htm_root_edge[r*3 + 2]; 00169 path->node[0].id = r + 8; 00170 path->node[0].child = 0; 00171 path->root = r; 00172 } 00173 00174 /* Computes the normalized average of two input vertices. 00175 */ 00176 HTM_INLINE void _htm_vertex(struct htm_v3 *out, 00177 const struct htm_v3 *v1, 00178 const struct htm_v3 *v2) 00179 { 00180 htm_v3_add(out, v1, v2); 00181 htm_v3_normalize(out, out); 00182 } 00183 00184 /* Computes quantities needed by _htm_node_make0(node). 00185 */ 00186 HTM_INLINE void _htm_node_prep0(struct _htm_node *node) 00187 { 00188 _htm_vertex(&node->mid_vert[1], node->vert[2], node->vert[0]); 00189 _htm_vertex(&node->mid_vert[2], node->vert[0], node->vert[1]); 00190 htm_v3_rcross(&node->mid_edge[1], &node->mid_vert[2], &node->mid_vert[1]); 00191 } 00192 00193 /* Sets node[1] to child 0 of node[0]. Assumes _htm_node_prep0(node) 00194 has been called. 00195 */ 00196 HTM_INLINE void _htm_node_make0(struct _htm_node *node) 00197 { 00198 node[1].vert[0] = node[0].vert[0]; 00199 node[1].vert[1] = &node[0].mid_vert[2]; 00200 node[1].vert[2] = &node[0].mid_vert[1]; 00201 node[1].edge[0] = node[0].edge[0]; 00202 node[1].edge[1] = &node[0].mid_edge[1]; 00203 node[1].edge[2] = node[0].edge[2]; 00204 node[0].child = 1; 00205 node[1].id = node[0].id << 2; 00206 node[1].child = 0; 00207 } 00208 00209 /* Computes quantities needed by _htm_node_make1(node). Assumes 00210 _htm_node_prep0(node) has been called. 00211 */ 00212 HTM_INLINE void _htm_node_prep1(struct _htm_node *node) 00213 { 00214 _htm_vertex(&node->mid_vert[0], node->vert[1], node->vert[2]); 00215 htm_v3_rcross(&node->mid_edge[2], &node->mid_vert[0], &node->mid_vert[2]); 00216 } 00217 00218 /* Sets node[1] to child 1 of node[0]. Assumes _htm_node_prep1(node) 00219 has been called. 00220 */ 00221 HTM_INLINE void _htm_node_make1(struct _htm_node *node) 00222 { 00223 node[1].vert[0] = node[0].vert[1]; 00224 node[1].vert[1] = &node[0].mid_vert[0]; 00225 node[1].vert[2] = &node[0].mid_vert[2]; 00226 node[1].edge[0] = node[0].edge[1]; 00227 node[1].edge[1] = &node[0].mid_edge[2]; 00228 node[1].edge[2] = node[0].edge[0]; 00229 node[0].child = 2; 00230 node[1].id = (node[0].id << 2) + 1; 00231 node[1].child = 0; 00232 } 00233 00234 /* Computes quantities needed by _htm_node_make2(node). Assumes 00235 _htm_node_prep1 has been called. 00236 */ 00237 HTM_INLINE void _htm_node_prep2(struct _htm_node *node) 00238 { 00239 htm_v3_rcross(&node->mid_edge[0], &node->mid_vert[1], &node->mid_vert[0]); 00240 } 00241 00242 /* Sets node[1] to child 2 of node[0]. Assumes _htm_node_prep2(node) 00243 has been called. 00244 */ 00245 HTM_INLINE void _htm_node_make2(struct _htm_node *node) 00246 { 00247 node[1].vert[0] = node[0].vert[2]; 00248 node[1].vert[1] = &node[0].mid_vert[1]; 00249 node[1].vert[2] = &node[0].mid_vert[0]; 00250 node[1].edge[0] = node[0].edge[2]; 00251 node[1].edge[1] = &node[0].mid_edge[0]; 00252 node[1].edge[2] = node[0].edge[1]; 00253 node[0].child = 3; 00254 node[1].id = (node[0].id << 2) + 2; 00255 node[1].child = 0; 00256 } 00257 00258 /* Sets node[1] to child 3 of node[0]. Assumes _htm_node_prep2(node) 00259 has been called. 00260 */ 00261 HTM_INLINE void _htm_node_make3(struct _htm_node *node) 00262 { 00263 htm_v3_neg(&node[0].mid_edge[0], &node[0].mid_edge[0]); 00264 htm_v3_neg(&node[0].mid_edge[1], &node[0].mid_edge[1]); 00265 htm_v3_neg(&node[0].mid_edge[2], &node[0].mid_edge[2]); 00266 node[1].vert[0] = &node[0].mid_vert[0]; 00267 node[1].vert[1] = &node[0].mid_vert[1]; 00268 node[1].vert[2] = &node[0].mid_vert[2]; 00269 node[1].edge[0] = &node[0].mid_edge[0]; 00270 node[1].edge[1] = &node[0].mid_edge[1]; 00271 node[1].edge[2] = &node[0].mid_edge[2]; 00272 node[0].child = 4; 00273 node[1].id = (node[0].id << 2) + 3; 00274 node[1].child = 0; 00275 } 00276 00277 /* Reorders the vectors in [begin,end) such that the resulting array can be 00278 partitioned into [begin,m) and [m,end), where all vectors in [begin,m) are 00279 inside the partitioning plane, and all vectors in [m, end) are outside. 00280 00281 A pointer to the partitioning element m is returned. 00282 00283 Assumes that plane != 0, begin != 0, end != 0, and begin <= end. 00284 */ 00285 static struct htm_v3p * _htm_partition(const struct htm_v3 *plane, 00286 struct htm_v3p *beg, 00287 struct htm_v3p *end) 00288 { 00289 struct htm_v3p tmp; 00290 for (; beg < end; ++beg) { 00291 if (htm_v3_dot(plane, &beg->v) < 0.0) { 00292 /* beg is outside plane, find end which is inside, 00293 swap contents of beg and end. */ 00294 for (--end; end > beg; --end) { 00295 if (htm_v3_dot(plane, &end->v) >= 0.0) { 00296 break; 00297 } 00298 } 00299 if (end <= beg) { 00300 break; 00301 } 00302 tmp = *beg; 00303 *beg = *end; 00304 *end = tmp; 00305 } 00306 } 00307 return beg; 00308 } 00309 00310 /* Perform a depth-first traversal of an HTM tree. At each step of the 00311 traversal, the input position list is partitioned into the list of 00312 points inside the current HTM node and those outside - the full 00313 depth-first traverals of the HTM tree therefore yields a list of 00314 positions sorted on their HTM indexes. This can be faster than computing 00315 HTM indexes one at a time when inputs are clustered spatially, since the 00316 boundary representation of a given HTM triangle is computed at most once. 00317 */ 00318 static void _htm_path_sort(struct _htm_path *path, 00319 struct htm_v3p *begin, 00320 struct htm_v3p *end, 00321 int64_t *ids, 00322 int level) 00323 { 00324 struct _htm_node * const root = path->node; 00325 struct _htm_node * const leaf = root + level; 00326 struct _htm_node *curnode = path->node; 00327 struct htm_v3p *beg = begin; 00328 00329 curnode->end = end; 00330 00331 while (1) { 00332 if (curnode != leaf) { 00333 /* Not a leaf node, so continue descending the tree. 00334 Mid-points and edge normals are computed on-demand. */ 00335 int child = curnode->child; 00336 if (child == 0) { 00337 _htm_node_prep0(curnode); 00338 end = _htm_partition(&curnode->mid_edge[1], beg, end); 00339 if (beg < end) { 00340 _htm_node_make0(curnode); 00341 ++curnode; 00342 curnode->end = end; 00343 continue; 00344 } 00345 end = curnode->end; 00346 } 00347 if (child <= 1) { 00348 _htm_node_prep1(curnode); 00349 end = _htm_partition(&curnode->mid_edge[2], beg, end); 00350 if (beg < end) { 00351 _htm_node_make1(curnode); 00352 ++curnode; 00353 curnode->end = end; 00354 continue; 00355 } 00356 end = curnode->end; 00357 } 00358 if (child <= 2) { 00359 _htm_node_prep2(curnode); 00360 end = _htm_partition(&curnode->mid_edge[0], beg, end); 00361 if (beg < end) { 00362 _htm_node_make2(curnode); 00363 ++curnode; 00364 curnode->end = end; 00365 continue; 00366 } 00367 end = curnode->end; 00368 } 00369 if (beg < end) { 00370 _htm_node_make3(curnode); 00371 ++curnode; 00372 curnode->end = end; 00373 continue; 00374 } 00375 } else { 00376 /* reached a leaf triangle - all points between beg and end are 00377 inside and have the same HTM index. */ 00378 int64_t id = curnode->id; 00379 size_t i = beg - begin; 00380 size_t j = end - begin; 00381 for (; i < j; ++i) { 00382 ids[i] = id; 00383 } 00384 beg = end; 00385 } 00386 /* walk back up the path until we find a node which 00387 still contains unsorted points. */ 00388 do { 00389 if (curnode == root) { 00390 return; 00391 } 00392 --curnode; 00393 end = curnode->end; 00394 } while (beg == end); 00395 } 00396 } 00397 00398 #define HTM_IDS_INIT_CAP 16 00399 00400 static struct htm_ids * _htm_ids_init() 00401 { 00402 struct htm_ids *ids = (struct htm_ids *) malloc( 00403 sizeof(struct htm_ids) + HTM_IDS_INIT_CAP * sizeof(struct htm_range)); 00404 if (ids != NULL) { 00405 ids->n = 0; 00406 ids->cap = HTM_IDS_INIT_CAP; 00407 } 00408 return ids; 00409 } 00410 00411 static struct htm_ids * _htm_ids_grow(struct htm_ids *ids) 00412 { 00413 size_t cap = ids->cap; 00414 size_t nbytes = sizeof(struct htm_ids) + 2 * cap * sizeof(struct htm_range); 00415 struct htm_ids *out = (struct htm_ids *) realloc(ids, nbytes); 00416 if (out != NULL) { 00417 out->cap = 2 * cap; 00418 } else { 00419 free(ids); 00420 } 00421 return out; 00422 } 00423 00424 HTM_INLINE struct htm_ids * _htm_ids_add(struct htm_ids *ids, 00425 int64_t min, 00426 int64_t max) 00427 { 00428 size_t n = ids->n; 00429 if (n == 0) { 00430 ids->n = 1; 00431 ids->range[0].min = min; 00432 ids->range[0].max = max; 00433 } else if (min == ids->range[n - 1].max + 1) { 00434 ids->range[n - 1].max = max; 00435 } else { 00436 if (n == ids->cap) { 00437 ids = _htm_ids_grow(ids); 00438 if (ids == NULL) { 00439 return NULL; 00440 } 00441 } 00442 ids->n = n + 1; 00443 ids->range[n].min = min; 00444 ids->range[n].max = max; 00445 } 00446 return ids; 00447 } 00448 00449 00450 /* Returns the coverage code describing the spatial relationship between the 00451 given HTM triangle and spherical circle. 00452 */ 00453 static enum _htm_cov _htm_s2circle_htmcov(const struct _htm_node *n, 00454 const struct htm_v3 *c, 00455 double dist2) 00456 { 00457 int nin = htm_v3_dist2(c, n->vert[0]) <= dist2; 00458 nin += htm_v3_dist2(c, n->vert[1]) <= dist2; 00459 nin += htm_v3_dist2(c, n->vert[2]) <= dist2; 00460 if (nin == 3) { 00461 /* every vertex inside circle */ 00462 return HTM_INSIDE; 00463 } else if (nin != 0) { 00464 return HTM_INTERSECT; 00465 } 00466 /* no triangle vertices inside circle */ 00467 if (htm_v3_edgedist2(c, n->vert[0], n->vert[1], n->edge[0]) <= dist2 || 00468 htm_v3_edgedist2(c, n->vert[1], n->vert[2], n->edge[1]) <= dist2 || 00469 htm_v3_edgedist2(c, n->vert[2], n->vert[0], n->edge[2]) <= dist2) { 00470 /* min distance to at least one edge is <= circle radius */ 00471 return HTM_INTERSECT; 00472 } 00473 /* min distance to every edge is > circle radius - circle 00474 is either inside triangle or disjoint from it */ 00475 if (htm_v3_dot(c, n->edge[0]) >= 0.0 && 00476 htm_v3_dot(c, n->edge[1]) >= 0.0 && 00477 htm_v3_dot(c, n->edge[2]) >= 0.0) { 00478 return HTM_CONTAINS; 00479 } 00480 return HTM_DISJOINT; 00481 } 00482 00483 00484 /* Returns 1 if the edge between v1 and v2 intersects the given spherical 00485 ellipse. 00486 00487 Let M be the 3x3 symmetric matrix corresponding to the ellipse; the 00488 ellipse boundary is given by: 00489 00490 v' M v = 0 00491 00492 (where ' denotes transpose, and v = [x y z]'). The lines of intersection, 00493 between the plane defined by v1, v2 and M are given by: 00494 00495 a*(v1 + v2) + b*(v2 - v1) 00496 00497 where a,b are scalars to be determined. Note that we can use any basis 00498 for the plane; (v1 + v2, v2 - v1) is chosen because of numerical stability 00499 when v1 and v2 are nearly identical, and because it yields a simple test 00500 for whether a particular solution lies on the edge in question. 00501 00502 Note that if a,b is a solution, so is k*a,k*b for any scalar k. So 00503 wlog, set a = 1 and plug into the ellipse boundary equation: 00504 00505 0 = (v1 + v2)' M (v1 + v2) + b*(v2 - v1)' M (v1 + v2) + 00506 b*(v1 + v2)' M (v2 - v1) + b^2*(v2 - v1)' M (v2 - v1) 00507 00508 Since M is symmetric: 00509 00510 0 = b^2 * (v2 - v1)' M (v2 - v1) + 00511 2b * (v2 - v1)' M (v1 + v2) + 00512 (v1 + v2)' M (v1 + v2) 00513 00514 0 = c22 * b^2 + 2*c21 * b + c11 00515 00516 Solving this quadratic equation yields 0, 1, or 2 lines of intersection. 00517 Note that for an intersection to lie on the edge between v1 and v2, 00518 b must be in the range [-1, 1]. 00519 */ 00520 static int _htm_s2ellipse_isect(const struct htm_v3 *v1, 00521 const struct htm_v3 *v2, 00522 const struct htm_s2ellipse *ellipse) 00523 { 00524 struct htm_v3 e1, e2, v; 00525 double c11, c21, c22, delta; 00526 00527 htm_v3_add(&e1, v1, v2); 00528 htm_v3_sub(&e2, v2, v1); 00529 /* compute coeffs of quadratic eqn. */ 00530 c11 = e1.x * e1.x * ellipse->xx + 00531 e1.y * e1.y * ellipse->yy + 00532 e1.z * e1.z * ellipse->zz + 00533 e1.x * e1.y * ellipse->xy * 2.0 + 00534 e1.x * e1.z * ellipse->xz * 2.0 + 00535 e1.y * e1.z * ellipse->yz * 2.0; 00536 c22 = e2.x * e2.x * ellipse->xx + 00537 e2.y * e2.y * ellipse->yy + 00538 e2.z * e2.z * ellipse->zz + 00539 e2.x * e2.y * ellipse->xy * 2.0 + 00540 e2.x * e2.z * ellipse->xz * 2.0 + 00541 e2.y * e2.z * ellipse->yz * 2.0; 00542 c21 = e2.x * e1.x * ellipse->xx + 00543 e2.y * e1.y * ellipse->yy + 00544 e2.z * e1.z * ellipse->zz + 00545 (e2.x * e1.y + e2.y * e1.x) * ellipse->xy + 00546 (e2.x * e1.z + e2.z * e1.x) * ellipse->xz + 00547 (e2.y * e1.z + e2.z * e1.y) * ellipse->yz; 00548 if (c11 == 0.0) { 00549 /* v1 + v2 is a solution, and lies on the edge */ 00550 if (ellipse->a >= 90.0 || htm_v3_dot(&e1, &ellipse->cen) >= 0.0) { 00551 return 1; 00552 } 00553 /* other solution is given by a linear equation */ 00554 if (c22 == 0.0 || fabs(c22) < fabs(2.0*c21)) { 00555 return 0; 00556 } 00557 /* check whether solution lies in correct hemisphere */ 00558 htm_v3_mul(&v, &e2, -2.0*c21/c22); 00559 htm_v3_add(&v, &v, &e1); 00560 return htm_v3_dot(&v, &ellipse->cen) >= 0.0; 00561 } 00562 if (c22 == 0.0) { 00563 /* v2 - v1 is a solution, the other is given by b = -c11/(2*c21). */ 00564 if (c21 == 0.0) { 00565 return 0; 00566 } 00567 if (fabs(c11) <= fabs(2.0*c21)) { 00568 if (ellipse->a >= 90.0) { 00569 return 1; 00570 } 00571 /* check whether solution lies in correct hemisphere */ 00572 htm_v3_mul(&v, &e2, -0.5*c11/c21); 00573 htm_v3_add(&v, &v, &e1); 00574 return htm_v3_dot(&v, &ellipse->cen) >= 0.0; 00575 } 00576 return 0; 00577 } 00578 delta = c21*c21 - c11*c22; 00579 if (delta < 0.0) { 00580 /* no solutions */ 00581 return 0; 00582 } 00583 /* 1 or 2 solutions */ 00584 delta = sqrt(delta); 00585 if (fabs(c22) >= fabs(delta - c21)) { 00586 if (ellipse->a >= 90.0) { 00587 return 1; 00588 } 00589 /* check whether solution lies in correct hemisphere */ 00590 htm_v3_mul(&v, &e2, (delta - c21)/c22); 00591 htm_v3_add(&v, &v, &e1); 00592 return htm_v3_dot(&v, &ellipse->cen) >= 0.0; 00593 } 00594 if (fabs(c22) >= fabs(delta + c21)) { 00595 if (ellipse->a >= 90.0) { 00596 return 1; 00597 } 00598 /* check whether solution lies in correct hemisphere */ 00599 htm_v3_mul(&v, &e2, -(delta + c21)/c22); 00600 htm_v3_add(&v, &v, &e1); 00601 return htm_v3_dot(&v, &ellipse->cen) >= 0.0; 00602 } 00603 return 0; 00604 } 00605 00606 00607 /* Returns the coverage code describing the spatial relationship between the 00608 given HTM triangle and spherical ellipse. 00609 */ 00610 static enum _htm_cov _htm_s2ellipse_htmcov(const struct _htm_node *n, 00611 const struct htm_s2ellipse *e) 00612 { 00613 int nin = htm_s2ellipse_cv3(e, n->vert[0]); 00614 nin += htm_s2ellipse_cv3(e, n->vert[1]); 00615 nin += htm_s2ellipse_cv3(e, n->vert[2]); 00616 if (nin == 3) { 00617 return HTM_INSIDE; 00618 } else if (nin != 0) { 00619 return HTM_INTERSECT; 00620 } 00621 /* no triangle vertices inside ellipse - check for edge/ellipse 00622 intersections */ 00623 if (_htm_s2ellipse_isect(n->vert[0], n->vert[1], e) || 00624 _htm_s2ellipse_isect(n->vert[1], n->vert[2], e) || 00625 _htm_s2ellipse_isect(n->vert[2], n->vert[0], e)) { 00626 return HTM_INTERSECT; 00627 } 00628 /* no triangle/ellipse intersections */ 00629 if (htm_v3_dot(&e->cen, n->edge[0]) >= 0.0 && 00630 htm_v3_dot(&e->cen, n->edge[1]) >= 0.0 && 00631 htm_v3_dot(&e->cen, n->edge[2]) >= 0.0) { 00632 /* ellipse center inside triangle */ 00633 return HTM_CONTAINS; 00634 } 00635 return HTM_DISJOINT; 00636 } 00637 00638 00639 static const double HTM_INF = 1.0 / 0.0; 00640 static const double HTM_NEG_INF = -1.0 / 0.0; 00641 00642 /* Tests whether poly intersects the edge (v1, v2) with plane normal n. 00643 00644 The idea is that a solution v = (x,y,z) must satisfy: 00645 00646 v . n = 0, v != 0 00647 v . (n ^ v1) >= 0 00648 v . (v2 ^ n) >= 0 00649 v . e_i >= 0 00650 00651 where e_i are the edge plane normals for the polygon, and (n ^ v1), 00652 (v2 ^ n) are plane normals that bound the lune defined by n, v1, and v2. 00653 Write this as: 00654 00655 v . n = 0 00656 v . c_i >= 0 00657 00658 Now assume nz > 0 (for a non zero solution, at least one of nx, ny, nz 00659 must be non-zero, and treatment of negative values is analagous). Use 00660 the equality to obtain 00661 00662 z = - (x * nx + y * ny) / nz 00663 00664 and substitute into the inequalities to obtain: 00665 00666 x * (c_ix * nz - c_iz * nx) + y * (c_iy * nz - c_iz * ny) >= 0 00667 00668 which we write 00669 00670 x * a_i + y * b_i >= 0 00671 00672 If a solution v exists, then Kv is also a solution (for positive scalar K), 00673 so we can fix y = 1 and look for solutions to 00674 00675 x * a_i + b_i >= 0 00676 00677 If there are none, fix y = -1 and look for solutions to: 00678 00679 x * a_i - b_i >= 0 00680 00681 If again there are none, then y = 0, and the problem reduces to checking 00682 whether 00683 00684 x * a_i >= 0 00685 00686 has any solutions. This is the case when the non-zero a_i have the same 00687 sign. 00688 */ 00689 static int _htm_isect_test(const struct htm_v3 *v1, 00690 const struct htm_v3 *v2, 00691 const struct htm_v3 *n, 00692 const struct htm_s2cpoly *poly, 00693 double *ab) 00694 { 00695 struct htm_v3 c0; 00696 struct htm_v3 c1; 00697 double min_1, max_1, min_m1, max_m1; 00698 size_t nv, i, neg, pos; 00699 00700 htm_v3_cross(&c0, n, v1); 00701 htm_v3_cross(&c1, v2, n); 00702 nv = poly->n; 00703 if (n->z != 0.0) { 00704 double s = (n->z > 0.0) ? 1.0 : -1.0; 00705 ab[0] = s * (c0.x * n->z - c0.z * n->x); 00706 ab[1] = s * (c0.y * n->z - c0.z * n->y); 00707 ab[2] = s * (c1.x * n->z - c1.z * n->x); 00708 ab[3] = s * (c1.y * n->z - c1.z * n->y); 00709 for (i = 0; i < nv; ++i) { 00710 ab[2*i + 4] = s * (poly->ve[nv + i].x * n->z - poly->ve[nv + i].z * n->x); 00711 ab[2*i + 5] = s * (poly->ve[nv + i].y * n->z - poly->ve[nv + i].z * n->y); 00712 } 00713 } else if (n->y != 0.0) { 00714 double s = (n->y > 0.0) ? 1.0 : -1.0; 00715 ab[0] = s * (c0.x * n->y - c0.y * n->x); 00716 ab[1] = s * (c0.z * n->y); 00717 ab[2] = s * (c1.x * n->y - c1.y * n->x); 00718 ab[3] = s * (c1.z * n->y); 00719 for (i = 0; i < nv; ++i) { 00720 ab[2*i + 4] = s * (poly->ve[nv + i].x * n->y - poly->ve[nv + i].y * n->x); 00721 ab[2*i + 5] = s * (poly->ve[nv + i].z * n->y); 00722 } 00723 } else if (n->x != 0.0) { 00724 double s = (n->x > 0.0) ? 1.0 : -1.0; 00725 ab[0] = s * (c0.y * n->x); 00726 ab[1] = s * (c0.z * n->x); 00727 ab[2] = s * (c1.y * n->x); 00728 ab[3] = s * (c1.z * n->x); 00729 for (i = 0; i < nv; ++i) { 00730 ab[2*i + 4] = s * (poly->ve[nv + i].y * n->x); 00731 ab[2*i + 5] = s * (poly->ve[nv + i].z * n->x); 00732 } 00733 } else { 00734 return 0; 00735 } 00736 /* search for solutions to a*x +/- b >= 0, with constraint coeffs stored in 00737 ab */ 00738 min_1 = min_m1 = HTM_NEG_INF; 00739 max_1 = max_m1 = HTM_INF; 00740 for (i = 0, neg = 0, pos = 0; i < nv + 2; ++i) { 00741 double a = ab[2*i]; 00742 double b = ab[2*i + 1]; 00743 if (a == 0.0) { 00744 if (b < 0.0) { 00745 min_1 = HTM_INF; 00746 max_1 = HTM_NEG_INF; 00747 } else if (b > 0.0) { 00748 min_m1 = HTM_INF; 00749 max_m1 = HTM_NEG_INF; 00750 } 00751 } else if (a < 0.0) { 00752 ++neg; 00753 double d = -b / a; 00754 if (d < max_1) { 00755 max_1 = d; 00756 } 00757 if (-d < max_m1) { 00758 max_m1 = -d; 00759 } 00760 } else { 00761 ++pos; 00762 double d = -b / a; 00763 if (d > min_1) { 00764 min_1 = d; 00765 } 00766 if (-d > min_m1) { 00767 min_m1 = -d; 00768 } 00769 } 00770 } 00771 if (min_1 <= max_1 || min_m1 <= max_m1) { 00772 return 1; 00773 } 00774 return (neg == 0 || pos == 0); 00775 } 00776 00777 /* Returns the coverage code describing the spatial relationship between the 00778 given HTM triangle and spherical convex polygon. 00779 */ 00780 static enum _htm_cov _htm_s2cpoly_htmcov(const struct _htm_node *n, 00781 const struct htm_s2cpoly *poly, 00782 double *ab) 00783 { 00784 int nin = htm_s2cpoly_cv3(poly, n->vert[0]); 00785 nin += htm_s2cpoly_cv3(poly, n->vert[1]); 00786 nin += htm_s2cpoly_cv3(poly, n->vert[2]); 00787 00788 if (nin == 3) { 00789 /* all triangle vertices are inside poly, 00790 so triangle is inside by convexity. */ 00791 return HTM_INSIDE; 00792 } else if (nin != 0) { 00793 return HTM_INTERSECT; 00794 } 00795 /* all triangle vertices are outside poly - check for edge intersections */ 00796 if (_htm_isect_test(n->vert[0], n->vert[1], n->edge[0], poly, ab) != 0 || 00797 _htm_isect_test(n->vert[1], n->vert[2], n->edge[1], poly, ab) != 0 || 00798 _htm_isect_test(n->vert[2], n->vert[0], n->edge[2], poly, ab) != 0) { 00799 return HTM_INTERSECT; 00800 } 00801 /* All triangle vertices are outside poly and there are no edge/edge 00802 intersections. Polygon is either inside triangle or disjoint from 00803 it */ 00804 if (htm_v3_dot(&poly->vsum, n->edge[0]) >= 0.0 && 00805 htm_v3_dot(&poly->vsum, n->edge[1]) >= 0.0 && 00806 htm_v3_dot(&poly->vsum, n->edge[2]) >= 0.0) { 00807 return HTM_CONTAINS; 00808 } 00809 return HTM_DISJOINT; 00810 } 00811 00812 /* Returns the HTM root triangle for a point. 00813 */ 00814 HTM_INLINE enum htm_root _htm_v3_htmroot(const struct htm_v3 *v) 00815 { 00816 if (v->z < 0.0) { 00817 /* S0, S1, S2, S3 */ 00818 if (v->y > 0.0) { 00819 return (v->x > 0.0) ? HTM_S0 : HTM_S1; 00820 } else if (v->y == 0.0) { 00821 return (v->x >= 0.0) ? HTM_S0 : HTM_S2; 00822 } else { 00823 return (v->x < 0.0) ? HTM_S2 : HTM_S3; 00824 } 00825 } else { 00826 /* N0, N1, N2, N3 */ 00827 if (v->y > 0.0) { 00828 return (v->x > 0.0) ? HTM_N3 : HTM_N2; 00829 } else if (v->y == 0.0) { 00830 return (v->x >= 0.0) ? HTM_N3 : HTM_N1; 00831 } else { 00832 return (v->x < 0.0) ? HTM_N1 : HTM_N0; 00833 } 00834 } 00835 } 00836 00837 /* Partitions an array of points according to their root triangle numbers. 00838 */ 00839 static size_t _htm_rootpart(struct htm_v3p *points, 00840 unsigned char *ids, 00841 size_t n, 00842 enum htm_root root) 00843 { 00844 struct htm_v3p tmp; 00845 size_t beg, end; 00846 unsigned char c; 00847 for (beg = 0, end = n; beg < end; ++beg) { 00848 if (ids[beg] >= root) { 00849 for (; end > beg; --end) { 00850 if (ids[end - 1] < root) { 00851 break; 00852 } 00853 } 00854 if (end == beg) { 00855 break; 00856 } 00857 tmp = points[beg]; 00858 points[beg] = points[end - 1]; 00859 points[end - 1] = tmp; 00860 c = ids[beg]; 00861 ids[beg] = ids[end - 1]; 00862 ids[end - 1] = c; 00863 } 00864 } 00865 return beg; 00866 } 00867 00868 /* Sorts the given array of positions by root triangle number. 00869 */ 00870 static void _htm_rootsort(size_t roots[HTM_NROOTS + 1], 00871 struct htm_v3p *points, 00872 unsigned char *ids, 00873 size_t n) 00874 { 00875 size_t i, n0, n2, s2; 00876 00877 /* compute root ids for all points */ 00878 for (i = 0; i < n; ++i) { 00879 ids[i] = (unsigned char) _htm_v3_htmroot(&points[i].v); 00880 } 00881 n0 = _htm_rootpart(points, ids, n, HTM_N0); 00882 s2 = _htm_rootpart(points, ids, n0, HTM_S2); 00883 roots[HTM_S0] = 0; 00884 roots[HTM_S1] = _htm_rootpart(points, ids, s2, HTM_S1); 00885 roots[HTM_S2] = s2; 00886 roots[HTM_S3] = _htm_rootpart(points + s2, ids + s2, n0 - s2, HTM_S3) + s2; 00887 n2 = _htm_rootpart(points + n0, ids + n0, n - n0, HTM_N2) + n0; 00888 roots[HTM_N0] = n0; 00889 roots[HTM_N1] = _htm_rootpart(points + n0, ids + n0, n2 - n0, HTM_N1) + n0; 00890 roots[HTM_N2] = n2; 00891 roots[HTM_N3] = _htm_rootpart(points + n2, ids + n2, n - n2, HTM_N3) + n2; 00892 roots[HTM_NROOTS] = n; 00893 } 00894 00895 /* Reduces the effective subdivision level of an HTM id range list by n levels 00896 and merges adjacent ranges. This typically reduces the number of ranges in 00897 the list, but also makes it a poorer approximation of the underlying 00898 geometry. Note that with sufficiently large n, any range list can be shrunk 00899 down to at most 4 ranges. 00900 00901 In detail: a range [I1, I2] is mapped to [I1 & ~mask, I2 | mask], where 00902 mask = (1 << 2*n) - 1. 00903 */ 00904 static void _htm_simplify_ids(struct htm_ids *ids, int n) 00905 { 00906 size_t i, j, nr; 00907 int64_t mask; 00908 if (n <= 0 || ids == 0 || ids->n == 0) { 00909 return; 00910 } 00911 mask = (((int64_t) 1) << 2*n) - 1; 00912 for (i = 0, j = 0, nr = ids->n; i < nr; ++i, ++j) { 00913 int64_t min = ids->range[i].min & ~mask; 00914 int64_t max = ids->range[i].max | mask; 00915 for (; i < nr - 1; ++i) { 00916 int64_t next = ids->range[i + 1].min & ~mask; 00917 if (next > max + 1) { 00918 break; 00919 } 00920 max = ids->range[i + 1].max | mask; 00921 } 00922 ids->range[j].min = min; 00923 ids->range[j].max = max; 00924 } 00925 ids->n = j; 00926 } 00927 00928 00929 /* Constructs the next non-empty child of \p node. 00930 */ 00931 static const unsigned char * _htm_subdivide(struct _htm_node *node, 00932 const unsigned char *s) 00933 { 00934 uint64_t off; 00935 switch (node->child) { 00936 case 0: 00937 off = htm_varint_decode(s); 00938 s += 1 + htm_varint_nfollow(*s); 00939 _htm_node_prep0(node); 00940 _htm_node_make0(node); 00941 if (off != 0) { 00942 break; 00943 } 00944 /* fall-through */ 00945 case 1: 00946 off = htm_varint_decode(s); 00947 s += 1 + htm_varint_nfollow(*s); 00948 _htm_node_prep1(node); 00949 _htm_node_make1(node); 00950 if (off != 0) { 00951 break; 00952 } 00953 /* fall-through */ 00954 case 2: 00955 off = htm_varint_decode(s); 00956 s += 1 + htm_varint_nfollow(*s); 00957 _htm_node_prep2(node); 00958 _htm_node_make2(node); 00959 if (off != 0) { 00960 break; 00961 } 00962 /* fall-through */ 00963 case 3: 00964 off = htm_varint_decode(s); 00965 s += 1 + htm_varint_nfollow(*s); 00966 if (off != 0) { 00967 _htm_node_make3(node); 00968 break; 00969 } 00970 default: 00971 return NULL; 00972 } 00973 node->s = s; 00974 return s + (off - 1); 00975 } 00976 00977 00978 /* ---- API ---- */ 00979 00980 int64_t htm_v3_id(const struct htm_v3 *point, int level) 00981 { 00982 struct htm_v3 v0, v1, v2; 00983 struct htm_v3 sv0, sv1, sv2; 00984 struct htm_v3 e; 00985 int64_t id; 00986 int curlevel; 00987 enum htm_root r; 00988 00989 if (point == NULL) { 00990 return 0; 00991 } 00992 if (level < 0 || level > HTM_MAX_LEVEL) { 00993 return 0; 00994 } 00995 r = _htm_v3_htmroot(point); 00996 v0 = *_htm_root_vert[r*3]; 00997 v1 = *_htm_root_vert[r*3 + 1]; 00998 v2 = *_htm_root_vert[r*3 + 2]; 00999 id = r + 8; 01000 for (curlevel = 0; curlevel < level; ++curlevel) { 01001 _htm_vertex(&sv1, &v2, &v0); 01002 _htm_vertex(&sv2, &v0, &v1); 01003 htm_v3_rcross(&e, &sv2, &sv1); 01004 if (htm_v3_dot(&e, point) >= 0) { 01005 v1 = sv2; 01006 v2 = sv1; 01007 id = id << 2; 01008 continue; 01009 } 01010 _htm_vertex(&sv0, &v1, &v2); 01011 htm_v3_rcross(&e, &sv0, &sv2); 01012 if (htm_v3_dot(&e, point) >= 0) { 01013 v0 = v1; 01014 v1 = sv0; 01015 v2 = sv2; 01016 id = (id << 2) + 1; 01017 continue; 01018 } 01019 htm_v3_rcross(&e, &sv1, &sv0); 01020 if (htm_v3_dot(&e, point) >= 0) { 01021 v0 = v2; 01022 v1 = sv1; 01023 v2 = sv0; 01024 id = (id << 2) + 2; 01025 } else { 01026 v0 = sv0; 01027 v1 = sv1; 01028 v2 = sv2; 01029 id = (id << 2) + 3; 01030 } 01031 } 01032 return id; 01033 } 01034 01035 01036 enum htm_errcode htm_v3p_idsort(struct htm_v3p *points, 01037 int64_t *ids, 01038 size_t n, 01039 int level) 01040 { 01041 struct _htm_path path; 01042 size_t roots[HTM_NROOTS + 1]; 01043 enum htm_root r; 01044 01045 if (n == 0) { 01046 return HTM_ELEN; 01047 } else if (points == 0 || ids == 0) { 01048 return HTM_ENULLPTR; 01049 } else if (level < 0 || level > HTM_MAX_LEVEL) { 01050 return HTM_ELEVEL; 01051 } 01052 _htm_rootsort(roots, points, (unsigned char *) ids, n); 01053 for (r = HTM_S0; r <= HTM_N3; ++r) { 01054 if (roots[r] < roots[r + 1]) { 01055 _htm_path_root(&path, r); 01056 _htm_path_sort(&path, points + roots[r], 01057 points + roots[r + 1], ids + roots[r], level); 01058 } 01059 } 01060 return HTM_OK; 01061 } 01062 01063 01064 int htm_level(int64_t id) 01065 { 01066 uint64_t x = (uint64_t) id; 01067 int l; 01068 if (id < 8) { 01069 return -1; 01070 } 01071 x |= (x >> 1); 01072 x |= (x >> 2); 01073 x |= (x >> 4); 01074 x |= (x >> 8); 01075 x |= (x >> 16); 01076 x |= (x >> 32); 01077 l = htm_popcount(x) - 4; 01078 /* check that l is even, in range, and that the 4 MSBs of id 01079 give a valid root ID (8-15) */ 01080 if ((l & 1) != 0 || ((id >> l) & 0x8) == 0 || l > HTM_MAX_LEVEL*2) { 01081 return -1; 01082 } 01083 return l / 2; 01084 } 01085 01086 01087 enum htm_errcode htm_tri_init(struct htm_tri *tri, int64_t id) 01088 { 01089 struct htm_v3 v0, v1, v2; 01090 struct htm_v3 sv0, sv1, sv2; 01091 int shift, level; 01092 enum htm_root r; 01093 01094 if (tri == NULL) { 01095 return HTM_ENULLPTR; 01096 } 01097 level = htm_level(id); 01098 if (level < 0) { 01099 return HTM_EID; 01100 } 01101 tri->id = id; 01102 tri->level = level; 01103 shift = 2*level; 01104 r = (id >> shift) & 0x7; 01105 v0 = *_htm_root_vert[r*3]; 01106 v1 = *_htm_root_vert[r*3 + 1]; 01107 v2 = *_htm_root_vert[r*3 + 2]; 01108 for (shift -= 2; shift >= 0; shift -= 2) { 01109 int child = (id >> shift) & 0x3; 01110 _htm_vertex(&sv1, &v2, &v0); 01111 _htm_vertex(&sv2, &v0, &v1); 01112 _htm_vertex(&sv0, &v1, &v2); 01113 switch (child) { 01114 case 0: 01115 v1 = sv2; 01116 v2 = sv1; 01117 break; 01118 case 1: 01119 v0 = v1; 01120 v1 = sv0; 01121 v2 = sv2; 01122 break; 01123 case 2: 01124 01125 v0 = v2; 01126 v1 = sv1; 01127 v2 = sv0; 01128 break; 01129 case 3: 01130 v0 = sv0; 01131 v1 = sv1; 01132 v2 = sv2; 01133 break; 01134 } 01135 } 01136 tri->verts[0] = v0; 01137 tri->verts[1] = v1; 01138 tri->verts[2] = v2; 01139 htm_v3_add(&sv0, &v0, &v1); 01140 htm_v3_add(&sv0, &sv0, &v2); 01141 htm_v3_normalize(&tri->center, &sv0); 01142 tri->radius = htm_v3_angsep(&sv0, &v0); 01143 return HTM_OK; 01144 } 01145 01146 01147 struct htm_ids * htm_s2circle_ids(struct htm_ids *ids, 01148 const struct htm_v3 *center, 01149 double radius, 01150 int level, 01151 size_t maxranges, 01152 enum htm_errcode *err) 01153 { 01154 struct _htm_path path; 01155 double dist2; 01156 enum htm_root root; 01157 int efflevel; 01158 01159 if (center == NULL) { 01160 if (err != NULL) { 01161 *err = HTM_ENULLPTR; 01162 } 01163 free(ids); 01164 return NULL; 01165 } else if (level < 0 || level > HTM_MAX_LEVEL) { 01166 if (err != NULL) { 01167 *err = HTM_ELEVEL; 01168 } 01169 free(ids); 01170 return NULL; 01171 } 01172 if (ids == NULL) { 01173 ids = _htm_ids_init(); 01174 if (ids == NULL) { 01175 if (err != NULL) { 01176 *err = HTM_ENOMEM; 01177 } 01178 return NULL; 01179 } 01180 } else { 01181 ids->n = 0; 01182 } 01183 /* Deal with degenerate cases */ 01184 if (radius < 0.0) { 01185 /* empty ID list */ 01186 if (err != NULL) { 01187 *err = HTM_OK; 01188 } 01189 return ids; 01190 } else if (radius >= 180.0) { 01191 /* the entire sky */ 01192 int64_t min_id = (8 + HTM_S0) << level * 2; 01193 int64_t max_id = ((8 + HTM_NROOTS) << level * 2) - 1; 01194 if (err != NULL) { 01195 *err = HTM_OK; 01196 } 01197 ids = _htm_ids_add(ids, min_id, max_id); 01198 if (ids == NULL && err != NULL) { 01199 *err = HTM_ENOMEM; 01200 } 01201 return ids; 01202 } 01203 01204 efflevel = level; 01205 /* compute square of secant distance corresponding to radius */ 01206 dist2 = sin(radius * 0.5 * HTM_RAD_PER_DEG); 01207 dist2 = 4.0 * dist2 * dist2; 01208 01209 for (root = HTM_S0; root <= HTM_N3; ++root) { 01210 struct _htm_node *curnode = path.node; 01211 int curlevel = 0; 01212 _htm_path_root(&path, root); 01213 01214 while (1) { 01215 switch (_htm_s2circle_htmcov(curnode, center, dist2)) { 01216 case HTM_CONTAINS: 01217 if (curlevel == 0) { 01218 /* no need to consider other roots */ 01219 root = HTM_N3; 01220 } else { 01221 /* no need to consider other children of parent */ 01222 curnode[-1].child = 4; 01223 } 01224 /* fall-through */ 01225 case HTM_INTERSECT: 01226 if (curlevel < efflevel) { 01227 /* continue subdividing */ 01228 _htm_node_prep0(curnode); 01229 _htm_node_make0(curnode); 01230 ++curnode; 01231 ++curlevel; 01232 continue; 01233 } 01234 /* fall-through */ 01235 case HTM_INSIDE: 01236 /* reached a leaf or fully covered HTM triangle, 01237 append HTM ID range to results */ 01238 { 01239 int64_t id = curnode->id << (level - curlevel) * 2; 01240 int64_t n = ((int64_t) 1) << (level - curlevel) * 2; 01241 ids = _htm_ids_add(ids, id, id + n - 1); 01242 } 01243 if (ids == NULL) { 01244 if (err != NULL) { 01245 *err = HTM_ENOMEM; 01246 } 01247 return NULL; 01248 } 01249 while (ids->n > maxranges && efflevel != 0) { 01250 /* too many ranges: 01251 reduce effective subdivision level */ 01252 --efflevel; 01253 if (curlevel > efflevel) { 01254 curnode = curnode - (curlevel - efflevel); 01255 curlevel = efflevel; 01256 } 01257 _htm_simplify_ids(ids, level - efflevel); 01258 } 01259 break; 01260 default: 01261 /* HTM triangle does not intersect circle */ 01262 break; 01263 } 01264 /* ascend towards the root */ 01265 --curlevel; 01266 --curnode; 01267 while (curlevel >= 0 && curnode->child == 4) { 01268 --curnode; 01269 --curlevel; 01270 } 01271 if (curlevel < 0) { 01272 /* finished with this root */ 01273 break; 01274 } 01275 if (curnode->child == 1) { 01276 _htm_node_prep1(curnode); 01277 _htm_node_make1(curnode); 01278 } else if (curnode->child == 2) { 01279 _htm_node_prep2(curnode); 01280 _htm_node_make2(curnode); 01281 } else { 01282 _htm_node_make3(curnode); 01283 } 01284 ++curnode; 01285 ++curlevel; 01286 } 01287 } 01288 if (err != NULL) { 01289 *err = HTM_OK; 01290 } 01291 return ids; 01292 } 01293 01294 01295 struct htm_ids * htm_s2ellipse_ids(struct htm_ids *ids, 01296 const struct htm_s2ellipse *ellipse, 01297 int level, 01298 size_t maxranges, 01299 enum htm_errcode *err) 01300 { 01301 struct _htm_path path; 01302 enum htm_root root; 01303 int efflevel; 01304 01305 if (ellipse == NULL) { 01306 if (err != NULL) { 01307 *err = HTM_ENULLPTR; 01308 } 01309 free(ids); 01310 return NULL; 01311 } else if (level < 0 || level > HTM_MAX_LEVEL) { 01312 if (err != NULL) { 01313 *err = HTM_ELEVEL; 01314 } 01315 free(ids); 01316 return NULL; 01317 } 01318 if (ids == NULL) { 01319 ids = _htm_ids_init(); 01320 if (ids == NULL) { 01321 if (err != NULL) { 01322 *err = HTM_ENOMEM; 01323 } 01324 return NULL; 01325 } 01326 } else { 01327 ids->n = 0; 01328 } 01329 01330 efflevel = level; 01331 for (root = HTM_S0; root <= HTM_N3; ++root) { 01332 struct _htm_node *curnode = path.node; 01333 int curlevel = 0; 01334 _htm_path_root(&path, root); 01335 01336 while (1) { 01337 switch (_htm_s2ellipse_htmcov(curnode, ellipse)) { 01338 case HTM_CONTAINS: 01339 if (curlevel == 0) { 01340 /* no need to consider other roots */ 01341 root = HTM_N3; 01342 } else { 01343 /* no need to consider other children of parent */ 01344 curnode[-1].child = 4; 01345 } 01346 /* fall-through */ 01347 case HTM_INTERSECT: 01348 if (curlevel < efflevel) { 01349 /* continue subdividing */ 01350 _htm_node_prep0(curnode); 01351 _htm_node_make0(curnode); 01352 ++curnode; 01353 ++curlevel; 01354 continue; 01355 } 01356 /* fall-through */ 01357 case HTM_INSIDE: 01358 /* reached a leaf or fully covered HTM triangle, 01359 append HTM ID range to results */ 01360 { 01361 int64_t id = curnode->id << (level - curlevel) * 2; 01362 int64_t n = ((int64_t) 1) << (level - curlevel) * 2; 01363 ids = _htm_ids_add(ids, id, id + n - 1); 01364 } 01365 if (ids == NULL) { 01366 if (err != NULL) { 01367 *err = HTM_ENOMEM; 01368 } 01369 return NULL; 01370 } 01371 while (ids->n > maxranges && efflevel != 0) { 01372 /* too many ranges: 01373 reduce effective subdivision level */ 01374 --efflevel; 01375 if (curlevel > efflevel) { 01376 curnode = curnode - (curlevel - efflevel); 01377 curlevel = efflevel; 01378 } 01379 _htm_simplify_ids(ids, level - efflevel); 01380 } 01381 break; 01382 default: 01383 /* HTM triangle does not intersect circle */ 01384 break; 01385 } 01386 /* ascend towards the root */ 01387 --curlevel; 01388 --curnode; 01389 while (curlevel >= 0 && curnode->child == 4) { 01390 --curnode; 01391 --curlevel; 01392 } 01393 if (curlevel < 0) { 01394 /* finished with this root */ 01395 break; 01396 } 01397 if (curnode->child == 1) { 01398 _htm_node_prep1(curnode); 01399 _htm_node_make1(curnode); 01400 } else if (curnode->child == 2) { 01401 _htm_node_prep2(curnode); 01402 _htm_node_make2(curnode); 01403 } else { 01404 _htm_node_make3(curnode); 01405 } 01406 ++curnode; 01407 ++curlevel; 01408 } 01409 } 01410 if (err != NULL) { 01411 *err = HTM_OK; 01412 } 01413 return ids; 01414 } 01415 01416 01417 struct htm_ids * htm_s2cpoly_ids(struct htm_ids *ids, 01418 const struct htm_s2cpoly *poly, 01419 int level, 01420 size_t maxranges, 01421 enum htm_errcode *err) 01422 { 01423 double stackab[2*256 + 4]; 01424 struct _htm_path path; 01425 enum htm_root root; 01426 double *ab; 01427 size_t nb; 01428 int efflevel; 01429 01430 if (poly == NULL) { 01431 if (err != NULL) { 01432 *err = HTM_ENULLPTR; 01433 } 01434 free(ids); 01435 return NULL; 01436 } else if (level < 0 || level > HTM_MAX_LEVEL) { 01437 if (err != NULL) { 01438 *err = HTM_ELEVEL; 01439 } 01440 free(ids); 01441 return NULL; 01442 } 01443 if (ids == NULL) { 01444 ids = _htm_ids_init(); 01445 if (ids == NULL) { 01446 if (err != NULL) { 01447 *err = HTM_ENOMEM; 01448 } 01449 return NULL; 01450 } 01451 } else { 01452 ids->n = 0; 01453 } 01454 nb = (2 * poly->n + 4) * sizeof(double); 01455 if (nb > sizeof(stackab)) { 01456 ab = (double *) malloc(nb); 01457 if (ab == NULL) { 01458 if (err != NULL) { 01459 *err = HTM_ENOMEM; 01460 } 01461 free(ids); 01462 return NULL; 01463 } 01464 } else { 01465 ab = stackab; 01466 } 01467 01468 efflevel = level; 01469 01470 for (root = HTM_S0; root <= HTM_N3; ++root) { 01471 struct _htm_node *curnode = path.node; 01472 int curlevel = 0; 01473 _htm_path_root(&path, root); 01474 01475 while (1) { 01476 switch (_htm_s2cpoly_htmcov(curnode, poly, ab)) { 01477 case HTM_CONTAINS: 01478 if (curlevel == 0) { 01479 /* no need to consider other roots */ 01480 root = HTM_N3; 01481 } else { 01482 /* no need to consider other children of parent */ 01483 curnode[-1].child = 4; 01484 } 01485 /* fall-through */ 01486 case HTM_INTERSECT: 01487 if (curlevel < efflevel) { 01488 /* continue subdividing */ 01489 _htm_node_prep0(curnode); 01490 _htm_node_make0(curnode); 01491 ++curnode; 01492 ++curlevel; 01493 continue; 01494 } 01495 /* fall-through */ 01496 case HTM_INSIDE: 01497 /* reached a leaf or fully covered HTM triangle, 01498 append HTM ID range to results */ 01499 { 01500 int64_t id = curnode->id << (level - curlevel) * 2; 01501 int64_t n = ((int64_t) 1) << (level - curlevel) * 2; 01502 ids = _htm_ids_add(ids, id, id + n - 1); 01503 } 01504 if (ids == NULL) { 01505 if (ab != stackab) { 01506 free(ab); 01507 } 01508 if (err != NULL) { 01509 *err = HTM_ENOMEM; 01510 } 01511 return ids; 01512 } 01513 while (ids->n > maxranges && efflevel != 0) { 01514 /* too many ranges: 01515 reduce effetive subdivision level */ 01516 --efflevel; 01517 if (curlevel > efflevel) { 01518 curnode = curnode - (curlevel - efflevel); 01519 curlevel = efflevel; 01520 } 01521 _htm_simplify_ids(ids, level - efflevel); 01522 } 01523 break; 01524 default: 01525 /* HTM triangle does not intersect polygon */ 01526 break; 01527 } 01528 /* ascend towards the root */ 01529 --curlevel; 01530 --curnode; 01531 while (curlevel >= 0 && curnode->child == 4) { 01532 --curnode; 01533 --curlevel; 01534 } 01535 if (curlevel < 0) { 01536 /* finished with this root */ 01537 break; 01538 } 01539 if (curnode->child == 1) { 01540 _htm_node_prep1(curnode); 01541 _htm_node_make1(curnode); 01542 } else if (curnode->child == 2) { 01543 _htm_node_prep2(curnode); 01544 _htm_node_make2(curnode); 01545 } else { 01546 _htm_node_make3(curnode); 01547 } 01548 ++curnode; 01549 ++curlevel; 01550 } 01551 } 01552 if (ab != stackab) { 01553 free(ab); 01554 } 01555 if (err != NULL) { 01556 *err = HTM_OK; 01557 } 01558 return ids; 01559 } 01560 01561 01562 int64_t htm_idtodec(int64_t id) 01563 { 01564 int64_t dec = 0; 01565 int64_t factor = 1; 01566 int level = htm_level(id); 01567 if (level < 0 || level > HTM_DEC_MAX_LEVEL) { 01568 return 0; 01569 } 01570 for (++level; level > 0; --level, id >>= 2, factor *= 10) { 01571 dec += factor * (id & 3); 01572 } 01573 if ((id & 1) == 1) { 01574 dec += 2*factor; 01575 } else { 01576 dec += factor; 01577 } 01578 return dec; 01579 } 01580 01581 01582 int64_t htm_tree_s2circle_count(const struct htm_tree *tree, 01583 const struct htm_v3 *center, 01584 double radius, 01585 enum htm_errcode *err) 01586 { 01587 struct _htm_path path; 01588 enum htm_root root; 01589 double d2; 01590 int64_t count; 01591 01592 if (tree == NULL || center == NULL) { 01593 if (err != NULL) { 01594 *err = HTM_ENULLPTR; 01595 } 01596 return -1; 01597 } 01598 if (tree->indexfd == -1) { 01599 return htm_tree_s2circle_scan(tree, center, radius, err); 01600 } else if (radius < 0.0) { 01601 /* circle is empty */ 01602 return 0; 01603 } else if (radius >= 180.0) { 01604 /* entire sky */ 01605 return (int64_t) tree->count; 01606 } 01607 01608 count = 0; 01609 /* compute square of secant distance corresponding to radius */ 01610 d2 = sin(radius * 0.5 * HTM_RAD_PER_DEG); 01611 d2 = 4.0 * d2 * d2; 01612 01613 for (root = HTM_S0; root <= HTM_N3; ++root) { 01614 struct _htm_node *curnode = path.node; 01615 const unsigned char *s = tree->root[root]; 01616 uint64_t index = 0; 01617 int level = 0; 01618 01619 if (s == NULL) { 01620 /* root contains no points */ 01621 continue; 01622 } 01623 _htm_path_root(&path, root); 01624 01625 while (1) { 01626 uint64_t curcount = htm_varint_decode(s); 01627 s += 1 + htm_varint_nfollow(*s); 01628 index += htm_varint_decode(s); 01629 s += 1 + htm_varint_nfollow(*s); 01630 curnode->index = index; 01631 01632 switch (_htm_s2circle_htmcov(curnode, center, d2)) { 01633 case HTM_CONTAINS: 01634 if (level == 0) { 01635 /* no need to consider other roots */ 01636 root = HTM_N3; 01637 } else { 01638 /* no need to consider other children of parent */ 01639 curnode[-1].child = 4; 01640 } 01641 /* fall-through */ 01642 case HTM_INTERSECT: 01643 if (level < 20 && curcount >= tree->leafthresh) { 01644 s = _htm_subdivide(curnode, s); 01645 if (s == NULL) { 01646 /* tree is invalid */ 01647 if (err != NULL) { 01648 *err = HTM_EINV; 01649 } 01650 return -1; 01651 } 01652 ++level; 01653 ++curnode; 01654 continue; 01655 } 01656 /* scan points in leaf */ 01657 { 01658 uint64_t i; 01659 for (i = index; i < index + curcount; ++i) { 01660 if (htm_v3_dist2(center, &tree->entries[i].v) <= d2) { 01661 ++count; 01662 } 01663 } 01664 } 01665 break; 01666 case HTM_INSIDE: 01667 /* fully covered HTM triangle */ 01668 count += (int64_t) curcount; 01669 break; 01670 default: 01671 /* HTM triangle does not intersect circle */ 01672 break; 01673 } 01674 /* ascend towards the root */ 01675 ascend: 01676 --level; 01677 --curnode; 01678 while (level >= 0 && curnode->child == 4) { 01679 --curnode; 01680 --level; 01681 } 01682 if (level < 0) { 01683 /* finished with this root */ 01684 break; 01685 } 01686 index = curnode->index; 01687 s = _htm_subdivide(curnode, curnode->s); 01688 if (s == NULL) { 01689 /* no non-empty children remain */ 01690 goto ascend; 01691 } 01692 ++level; 01693 ++curnode; 01694 } 01695 } 01696 if (err != NULL) { 01697 *err = HTM_OK; 01698 } 01699 return count; 01700 } 01701 01702 01703 int64_t htm_tree_s2ellipse_count(const struct htm_tree *tree, 01704 const struct htm_s2ellipse *ellipse, 01705 enum htm_errcode *err) 01706 { 01707 struct _htm_path path; 01708 enum htm_root root; 01709 int64_t count; 01710 01711 if (tree == NULL || ellipse == NULL) { 01712 if (err != NULL) { 01713 *err = HTM_ENULLPTR; 01714 } 01715 return -1; 01716 } 01717 if (tree->indexfd == -1) { 01718 return htm_tree_s2ellipse_scan(tree, ellipse, err); 01719 } 01720 01721 count = 0; 01722 01723 for (root = HTM_S0; root <= HTM_N3; ++root) { 01724 struct _htm_node *curnode = path.node; 01725 const unsigned char *s = tree->root[root]; 01726 uint64_t index = 0; 01727 int level = 0; 01728 01729 if (s == NULL) { 01730 /* root contains no points */ 01731 continue; 01732 } 01733 _htm_path_root(&path, root); 01734 01735 while (1) { 01736 uint64_t curcount = htm_varint_decode(s); 01737 s += 1 + htm_varint_nfollow(*s); 01738 index += htm_varint_decode(s); 01739 s += 1 + htm_varint_nfollow(*s); 01740 curnode->index = index; 01741 01742 switch (_htm_s2ellipse_htmcov(curnode, ellipse)) { 01743 case HTM_CONTAINS: 01744 if (level == 0) { 01745 /* no need to consider other roots */ 01746 root = HTM_N3; 01747 } else { 01748 /* no need to consider other children of parent */ 01749 curnode[-1].child = 4; 01750 } 01751 /* fall-through */ 01752 case HTM_INTERSECT: 01753 if (level < 20 && curcount >= tree->leafthresh) { 01754 s = _htm_subdivide(curnode, s); 01755 if (s == NULL) { 01756 /* tree is invalid */ 01757 if (err != NULL) { 01758 *err = HTM_EINV; 01759 } 01760 return -1; 01761 } 01762 ++level; 01763 ++curnode; 01764 continue; 01765 } 01766 /* scan points in leaf */ 01767 { 01768 uint64_t i; 01769 for (i = index; i < index + curcount; ++i) { 01770 if (htm_s2ellipse_cv3(ellipse, &tree->entries[i].v)) { 01771 ++count; 01772 } 01773 } 01774 } 01775 break; 01776 case HTM_INSIDE: 01777 /* fully covered HTM triangle */ 01778 count += (int64_t) curcount; 01779 break; 01780 default: 01781 /* HTM triangle does not intersect circle */ 01782 break; 01783 } 01784 /* ascend towards the root */ 01785 ascend: 01786 --level; 01787 --curnode; 01788 while (level >= 0 && curnode->child == 4) { 01789 --curnode; 01790 --level; 01791 } 01792 if (level < 0) { 01793 /* finished with this root */ 01794 break; 01795 } 01796 index = curnode->index; 01797 s = _htm_subdivide(curnode, curnode->s); 01798 if (s == NULL) { 01799 /* no non-empty children remain */ 01800 goto ascend; 01801 } 01802 ++level; 01803 ++curnode; 01804 } 01805 } 01806 if (err != NULL) { 01807 *err = HTM_OK; 01808 } 01809 return count; 01810 } 01811 01812 01813 int64_t htm_tree_s2cpoly_count(const struct htm_tree *tree, 01814 const struct htm_s2cpoly *poly, 01815 enum htm_errcode *err) 01816 { 01817 double stackab[2*256 + 4]; 01818 struct _htm_path path; 01819 enum htm_root root; 01820 double *ab; 01821 size_t nb; 01822 int64_t count; 01823 01824 if (tree == NULL || poly == NULL) { 01825 if (err != NULL) { 01826 *err = HTM_ENULLPTR; 01827 } 01828 return -1; 01829 } 01830 if (tree->indexfd == -1) { 01831 return htm_tree_s2cpoly_scan(tree, poly, err); 01832 } 01833 nb = (2 * poly->n + 4) * sizeof(double); 01834 if (nb > sizeof(stackab)) { 01835 ab = (double *) malloc(nb); 01836 if (ab == NULL) { 01837 if (err != NULL) { 01838 *err = HTM_ENOMEM; 01839 } 01840 return -1; 01841 } 01842 } else { 01843 ab = stackab; 01844 } 01845 count = 0; 01846 01847 for (root = HTM_S0; root <= HTM_N3; ++root) { 01848 struct _htm_node *curnode = path.node; 01849 const unsigned char *s = tree->root[root]; 01850 uint64_t index = 0; 01851 int level = 0; 01852 01853 if (s == NULL) { 01854 /* root contains no points */ 01855 continue; 01856 } 01857 _htm_path_root(&path, root); 01858 01859 while (1) { 01860 uint64_t curcount = htm_varint_decode(s); 01861 s += 1 + htm_varint_nfollow(*s); 01862 index += htm_varint_decode(s); 01863 s += 1 + htm_varint_nfollow(*s); 01864 curnode->index = index; 01865 01866 switch (_htm_s2cpoly_htmcov(curnode, poly, ab)) { 01867 case HTM_CONTAINS: 01868 if (level == 0) { 01869 /* no need to consider other roots */ 01870 root = HTM_N3; 01871 } else { 01872 /* no need to consider other children of parent */ 01873 curnode[-1].child = 4; 01874 } 01875 /* fall-through */ 01876 case HTM_INTERSECT: 01877 if (level < 20 && curcount >= tree->leafthresh) { 01878 s = _htm_subdivide(curnode, s); 01879 if (s == NULL) { 01880 /* tree is invalid */ 01881 if (ab != stackab) { 01882 free(ab); 01883 } 01884 if (err != NULL) { 01885 *err = HTM_EINV; 01886 } 01887 return -1; 01888 } 01889 ++level; 01890 ++curnode; 01891 continue; 01892 } 01893 /* scan points in leaf */ 01894 { 01895 uint64_t i; 01896 for (i = index; i < index + curcount; ++i) { 01897 if (htm_s2cpoly_cv3(poly, &tree->entries[i].v)) { 01898 ++count; 01899 } 01900 } 01901 } 01902 break; 01903 case HTM_INSIDE: 01904 /* fully covered HTM triangle */ 01905 count += (int64_t) curcount; 01906 break; 01907 default: 01908 /* HTM triangle does not intersect circle */ 01909 break; 01910 } 01911 /* ascend towards the root */ 01912 ascend: 01913 --level; 01914 --curnode; 01915 while (level >= 0 && curnode->child == 4) { 01916 --curnode; 01917 --level; 01918 } 01919 if (level < 0) { 01920 /* finished with this root */ 01921 break; 01922 } 01923 index = curnode->index; 01924 s = _htm_subdivide(curnode, curnode->s); 01925 if (s == NULL) { 01926 /* no non-empty children remain */ 01927 goto ascend; 01928 } 01929 ++level; 01930 ++curnode; 01931 } 01932 } 01933 if (ab != stackab) { 01934 free(ab); 01935 } 01936 if (err != NULL) { 01937 *err = HTM_OK; 01938 } 01939 return count; 01940 } 01941 01942 01943 struct htm_range htm_tree_s2circle_range(const struct htm_tree *tree, 01944 const struct htm_v3 *center, 01945 double radius, 01946 enum htm_errcode *err) 01947 { 01948 struct _htm_path path; 01949 enum htm_root root; 01950 double d2; 01951 struct htm_range range; 01952 01953 range.min = 0; 01954 range.max = 0; 01955 if (tree == NULL || center == NULL) { 01956 if (err != NULL) { 01957 *err = HTM_ENULLPTR; 01958 } 01959 range.max = -1; 01960 return range; 01961 } 01962 if (tree->indexfd == -1) { 01963 range.max = htm_tree_s2circle_scan(tree, center, radius, err); 01964 if (range.max >= 0) { 01965 range.min = range.max; 01966 } 01967 return range; 01968 } else if (radius < 0.0) { 01969 /* circle is empty */ 01970 return range; 01971 } else if (radius >= 180.0) { 01972 /* entire sky */ 01973 range.min = (int64_t) tree->count; 01974 range.max = (int64_t) tree->count; 01975 return range; 01976 } 01977 /* compute square of secant distance corresponding to radius */ 01978 d2 = sin(radius * 0.5 * HTM_RAD_PER_DEG); 01979 d2 = 4.0 * d2 * d2; 01980 01981 for (root = HTM_S0; root <= HTM_N3; ++root) { 01982 struct _htm_node *curnode = path.node; 01983 const unsigned char *s = tree->root[root]; 01984 int level = 0; 01985 01986 if (s == NULL) { 01987 /* root contains no points */ 01988 continue; 01989 } 01990 _htm_path_root(&path, root); 01991 01992 while (1) { 01993 uint64_t curcount = htm_varint_decode(s); 01994 s += 1 + htm_varint_nfollow(*s); 01995 s += 1 + htm_varint_nfollow(*s); 01996 switch (_htm_s2circle_htmcov(curnode, center, d2)) { 01997 case HTM_CONTAINS: 01998 if (level == 0) { 01999 /* no need to consider other roots */ 02000 root = HTM_N3; 02001 } else { 02002 /* no need to consider other children of parent */ 02003 curnode[-1].child = 4; 02004 } 02005 /* fall-through */ 02006 case HTM_INTERSECT: 02007 if (level < 20 && curcount >= tree->leafthresh) { 02008 s = _htm_subdivide(curnode, s); 02009 if (s == NULL) { 02010 /* tree is invalid */ 02011 if (err != NULL) { 02012 *err = HTM_EINV; 02013 } 02014 range.max = -1; 02015 return range; 02016 } 02017 ++level; 02018 ++curnode; 02019 continue; 02020 } 02021 range.max += (int64_t) curcount; 02022 break; 02023 case HTM_INSIDE: 02024 /* fully covered HTM triangle */ 02025 range.min += (int64_t) curcount; 02026 range.max += (int64_t) curcount; 02027 break; 02028 default: 02029 /* HTM triangle does not intersect circle */ 02030 break; 02031 } 02032 /* ascend towards the root */ 02033 ascend: 02034 --level; 02035 --curnode; 02036 while (level >= 0 && curnode->child == 4) { 02037 --curnode; 02038 --level; 02039 } 02040 if (level < 0) { 02041 /* finished with this root */ 02042 break; 02043 } 02044 s = _htm_subdivide(curnode, curnode->s); 02045 if (s == NULL) { 02046 /* no non-empty children remain */ 02047 goto ascend; 02048 } 02049 ++level; 02050 ++curnode; 02051 } 02052 } 02053 if (err != NULL) { 02054 *err = HTM_OK; 02055 } 02056 return range; 02057 } 02058 02059 02060 struct htm_range htm_tree_s2ellipse_range(const struct htm_tree *tree, 02061 const struct htm_s2ellipse *ellipse, 02062 enum htm_errcode *err) 02063 { 02064 struct _htm_path path; 02065 enum htm_root root; 02066 struct htm_range range; 02067 02068 range.min = 0; 02069 range.max = 0; 02070 if (tree == NULL || ellipse== NULL) { 02071 if (err != NULL) { 02072 *err = HTM_ENULLPTR; 02073 } 02074 range.max = -1; 02075 return range; 02076 } 02077 if (tree->indexfd == -1) { 02078 range.max = htm_tree_s2ellipse_scan(tree, ellipse, err); 02079 if (range.max >= 0) { 02080 range.min = range.max; 02081 } 02082 return range; 02083 } 02084 02085 for (root = HTM_S0; root <= HTM_N3; ++root) { 02086 struct _htm_node *curnode = path.node; 02087 const unsigned char *s = tree->root[root]; 02088 int level = 0; 02089 02090 if (s == NULL) { 02091 /* root contains no points */ 02092 continue; 02093 } 02094 _htm_path_root(&path, root); 02095 02096 while (1) { 02097 uint64_t curcount = htm_varint_decode(s); 02098 s += 1 + htm_varint_nfollow(*s); 02099 s += 1 + htm_varint_nfollow(*s); 02100 switch (_htm_s2ellipse_htmcov(curnode, ellipse)) { 02101 case HTM_CONTAINS: 02102 if (level == 0) { 02103 /* no need to consider other roots */ 02104 root = HTM_N3; 02105 } else { 02106 /* no need to consider other children of parent */ 02107 curnode[-1].child = 4; 02108 } 02109 /* fall-through */ 02110 case HTM_INTERSECT: 02111 if (level < 20 && curcount >= tree->leafthresh) { 02112 s = _htm_subdivide(curnode, s); 02113 if (s == NULL) { 02114 /* tree is invalid */ 02115 if (err != NULL) { 02116 *err = HTM_EINV; 02117 } 02118 range.max = -1; 02119 return range; 02120 } 02121 ++level; 02122 ++curnode; 02123 continue; 02124 } 02125 range.max += (int64_t) curcount; 02126 break; 02127 case HTM_INSIDE: 02128 /* fully covered HTM triangle */ 02129 range.min += (int64_t) curcount; 02130 range.max += (int64_t) curcount; 02131 break; 02132 default: 02133 /* HTM triangle does not intersect circle */ 02134 break; 02135 } 02136 /* ascend towards the root */ 02137 ascend: 02138 --level; 02139 --curnode; 02140 while (level >= 0 && curnode->child == 4) { 02141 --curnode; 02142 --level; 02143 } 02144 if (level < 0) { 02145 /* finished with this root */ 02146 break; 02147 } 02148 s = _htm_subdivide(curnode, curnode->s); 02149 if (s == NULL) { 02150 /* no non-empty children remain */ 02151 goto ascend; 02152 } 02153 ++level; 02154 ++curnode; 02155 } 02156 } 02157 if (err != NULL) { 02158 *err = HTM_OK; 02159 } 02160 return range; 02161 } 02162 02163 02164 struct htm_range htm_tree_s2cpoly_range(const struct htm_tree *tree, 02165 const struct htm_s2cpoly *poly, 02166 enum htm_errcode *err) 02167 { 02168 double stackab[2*256 + 4]; 02169 struct _htm_path path; 02170 enum htm_root root; 02171 double *ab; 02172 size_t nb; 02173 struct htm_range range; 02174 02175 range.min = 0; 02176 range.max = 0; 02177 if (tree == NULL || poly == NULL) { 02178 if (err != NULL) { 02179 *err = HTM_ENULLPTR; 02180 } 02181 range.max = -1; 02182 return range; 02183 } 02184 if (tree->indexfd == -1) { 02185 range.max = htm_tree_s2cpoly_scan(tree, poly, err); 02186 if (range.max >= 0) { 02187 range.min = range.max; 02188 } 02189 return range; 02190 } 02191 nb = (2 * poly->n + 4) * sizeof(double); 02192 if (nb > sizeof(stackab)) { 02193 ab = (double *) malloc(nb); 02194 if (ab == NULL) { 02195 if (err != NULL) { 02196 *err = HTM_ENOMEM; 02197 } 02198 range.max = -1; 02199 return range; 02200 } 02201 } else { 02202 ab = stackab; 02203 } 02204 02205 for (root = HTM_S0; root <= HTM_N3; ++root) { 02206 struct _htm_node *curnode = path.node; 02207 const unsigned char *s = tree->root[root]; 02208 int level = 0; 02209 02210 if (s == NULL) { 02211 /* root contains no points */ 02212 continue; 02213 } 02214 _htm_path_root(&path, root); 02215 02216 while (1) { 02217 uint64_t curcount = htm_varint_decode(s); 02218 s += 1 + htm_varint_nfollow(*s); 02219 s += 1 + htm_varint_nfollow(*s); 02220 switch (_htm_s2cpoly_htmcov(curnode, poly, ab)) { 02221 case HTM_CONTAINS: 02222 if (level == 0) { 02223 /* no need to consider other roots */ 02224 root = HTM_N3; 02225 } else { 02226 /* no need to consider other children of parent */ 02227 curnode[-1].child = 4; 02228 } 02229 /* fall-through */ 02230 case HTM_INTERSECT: 02231 if (level < 20 && curcount >= tree->leafthresh) { 02232 s = _htm_subdivide(curnode, s); 02233 if (s == NULL) { 02234 /* tree is invalid */ 02235 if (ab != stackab) { 02236 free(ab); 02237 } 02238 if (err != NULL) { 02239 *err = HTM_EINV; 02240 } 02241 range.max = -1; 02242 return range; 02243 } 02244 ++level; 02245 ++curnode; 02246 continue; 02247 } 02248 range.max += (int64_t) curcount; 02249 break; 02250 case HTM_INSIDE: 02251 /* fully covered HTM triangle */ 02252 range.min += (int64_t) curcount; 02253 range.max += (int64_t) curcount; 02254 break; 02255 default: 02256 /* HTM triangle does not intersect circle */ 02257 break; 02258 } 02259 /* ascend towards the root */ 02260 ascend: 02261 --level; 02262 --curnode; 02263 while (level >= 0 && curnode->child == 4) { 02264 --curnode; 02265 --level; 02266 } 02267 if (level < 0) { 02268 /* finished with this root */ 02269 break; 02270 } 02271 s = _htm_subdivide(curnode, curnode->s); 02272 if (s == NULL) { 02273 /* no non-empty children remain */ 02274 goto ascend; 02275 } 02276 ++level; 02277 ++curnode; 02278 } 02279 } 02280 if (ab != stackab) { 02281 free(ab); 02282 } 02283 if (err != NULL) { 02284 *err = HTM_OK; 02285 } 02286 return range; 02287 } 02288 02289 02290 #ifdef __cplusplus 02291 } 02292 #endif