github.com/liucxer/courier@v1.7.1/h3/coordijk.go (about) 1 package h3 2 3 import "C" 4 import ( 5 "math" 6 ) 7 8 /** 9 * @brief IJK hexagon coordinates 10 * 11 * Each axis is spaced 120 degrees apart. 12 */ 13 type CoordIJK struct { 14 i int 15 j int 16 k int 17 } 18 19 /** @brief CoordIJK unit vectors corresponding to the 7 H3 digits. 20 */ 21 var UNIT_VECS = [7]CoordIJK{ 22 {0, 0, 0}, // direction 0 23 {0, 0, 1}, // direction 1 24 {0, 1, 0}, // direction 2 25 {0, 1, 1}, // direction 3 26 {1, 0, 0}, // direction 4 27 {1, 0, 1}, // direction 5 28 {1, 1, 0}, // direction 6 29 } 30 31 type Direction uint 32 33 /** @brief H3 digit representing ijk+ axes direction. 34 * Values will be within the lowest 3 bits of an integer. 35 */ 36 const ( 37 /** H3 digit in center */ 38 CENTER_DIGIT Direction = 0 39 /** H3 digit in k-axes direction */ 40 K_AXES_DIGIT Direction = 1 41 /** H3 digit in j-axes direction */ 42 J_AXES_DIGIT Direction = 2 43 /** H3 digit in j == k direction */ 44 JK_AXES_DIGIT Direction = J_AXES_DIGIT | K_AXES_DIGIT /* 3 */ 45 /** H3 digit in i-axes direction */ 46 I_AXES_DIGIT Direction = 4 47 /** H3 digit in i == k direction */ 48 IK_AXES_DIGIT Direction = I_AXES_DIGIT | K_AXES_DIGIT /* 5 */ 49 /** H3 digit in i == j direction */ 50 IJ_AXES_DIGIT Direction = I_AXES_DIGIT | J_AXES_DIGIT /* 6 */ 51 /** H3 digit in the invalid direction */ 52 INVALID_DIGIT Direction = 7 53 /** Valid digits will be less than this value. Same value as INVALID_DIGIT. 54 */ 55 NUM_DIGITS Direction = INVALID_DIGIT 56 ) 57 58 /** 59 * Sets an IJK coordinate to the specified component values. 60 * 61 * @param ijk The IJK coordinate to set. 62 * @param i The desired i component value. 63 * @param j The desired j component value. 64 * @param k The desired k component value. 65 */ 66 func _setIJK(ijk *CoordIJK, i, j, k int) { 67 ijk.i = i 68 ijk.j = j 69 ijk.k = k 70 } 71 72 func fabsl(arg0 float64) float64 { 73 return math.Abs(arg0) 74 } 75 76 /** 77 * Determine the containing hex in ijk+ coordinates for a 2D cartesian 78 * coordinate vector (from DGGRID). 79 * 80 * @param v The 2D cartesian coordinate vector. 81 * @param h The ijk+ coordinates of the containing hex. 82 */ 83 func _hex2dToCoordIJK(v *Vec2d, h *CoordIJK) { 84 var a1, a2 float64 85 var x1, x2 float64 86 var m1, m2 int 87 var r1, r2 float64 88 89 // quantize into the ij system and then normalize 90 h.k = 0 91 a1 = fabsl(v.x) 92 a2 = fabsl(v.y) 93 94 // first do a reverse conversion 95 x2 = a2 / M_SIN60 96 x1 = a1 + x2/2.0 97 98 // check if we have the center of a hex 99 m1 = int(x1) 100 m2 = int(x2) 101 102 // otherwise round correctly 103 r1 = x1 - float64(m1) 104 r2 = x2 - float64(m2) 105 if r1 < 0.5 { 106 if r1 < 1.0/3.0 { 107 if r2 < (1.0+r1)/2.0 { 108 h.i = m1 109 h.j = m2 110 } else { 111 h.i = m1 112 h.j = m2 + 1 113 } 114 } else { 115 if r2 < (1.0 - r1) { 116 h.j = m2 117 } else { 118 h.j = m2 + 1 119 } 120 121 if (1.0-r1) <= r2 && r2 < (2.0*r1) { 122 h.i = m1 + 1 123 } else { 124 h.i = m1 125 } 126 } 127 } else { 128 if r1 < 2.0/3.0 { 129 if r2 < (1.0 - r1) { 130 h.j = m2 131 } else { 132 h.j = m2 + 1 133 } 134 135 if (2.0*r1-1.0) < r2 && r2 < (1.0-r1) { 136 h.i = m1 137 } else { 138 h.i = m1 + 1 139 } 140 } else { 141 if r2 < (r1 / 2.0) { 142 h.i = m1 + 1 143 h.j = m2 144 } else { 145 h.i = m1 + 1 146 h.j = m2 + 1 147 } 148 } 149 } 150 151 // now fold across the axes if necessary 152 if v.x < 0 { 153 if h.j%2 == 0 { 154 // even 155 axisi := int64(h.j / 2) 156 diff := int64(h.i) - axisi 157 h.i = int(float64(h.i) - 2*float64(diff)) 158 } else { 159 axisi := int64((h.j + 1) / 2) 160 diff := int64(h.i) - axisi 161 h.i = int(float64(h.i) - (2*float64(diff) + 1)) 162 } 163 } 164 165 if v.y < 0.0 { 166 h.i = h.i - (2*h.j+1)/2 167 h.j = -1 * h.j 168 } 169 170 _ijkNormalize(h) 171 } 172 173 /** 174 * Find the center point in 2D cartesian coordinates of a hex. 175 * 176 * @param h The ijk coordinates of the hex. 177 * @param v The 2D cartesian coordinates of the hex center point. 178 */ 179 func _ijkToHex2d(h *CoordIJK, v *Vec2d) { 180 i := float64(h.i - h.k) 181 j := float64(h.j - h.k) 182 v.x = i - 0.5*j 183 v.y = j * M_SQRT3_2 184 } 185 186 /** 187 * Returns whether or not two ijk coordinates contain exactly the same 188 * component values. 189 * 190 * @param c1 The first set of ijk coordinates. 191 * @param c2 The second set of ijk coordinates. 192 * @return 1 if the two addresses match, 0 if they do not. 193 */ 194 func _ijkMatches(c1 *CoordIJK, c2 *CoordIJK) bool { 195 return (c1.i == c2.i && c1.j == c2.j && c1.k == c2.k) 196 } 197 198 /** 199 * Add two ijk coordinates. 200 * 201 * @param h1 The first set of ijk coordinates. 202 * @param h2 The second set of ijk coordinates. 203 * @param sum The sum of the two sets of ijk coordinates. 204 */ 205 func _ijkAdd(h1 *CoordIJK, h2 *CoordIJK, sum *CoordIJK) { 206 sum.i = h1.i + h2.i 207 sum.j = h1.j + h2.j 208 sum.k = h1.k + h2.k 209 } 210 211 /** 212 * Subtract two ijk coordinates. 213 * 214 * @param h1 The first set of ijk coordinates. 215 * @param h2 The second set of ijk coordinates. 216 * @param diff The difference of the two sets of ijk coordinates (h1 - h2). 217 */ 218 func _ijkSub(h1 *CoordIJK, h2 *CoordIJK, diff *CoordIJK) { 219 diff.i = h1.i - h2.i 220 diff.j = h1.j - h2.j 221 diff.k = h1.k - h2.k 222 } 223 224 /** 225 * Uniformly scale ijk coordinates by a scalar. Works in place. 226 * 227 * @param c The ijk coordinates to scale. 228 * @param factor The scaling factor. 229 */ 230 func _ijkScale(c *CoordIJK, factor int) { 231 c.i *= factor 232 c.j *= factor 233 c.k *= factor 234 } 235 236 /** 237 * Normalizes ijk coordinates by setting the components to the smallest possible 238 * values. Works in place. 239 * 240 * @param c The ijk coordinates to normalize. 241 */ 242 func _ijkNormalize(c *CoordIJK) { 243 // remove any negative values 244 if c.i < 0 { 245 c.j -= c.i 246 c.k -= c.i 247 c.i = 0 248 } 249 250 if c.j < 0 { 251 c.i -= c.j 252 c.k -= c.j 253 c.j = 0 254 } 255 256 if c.k < 0 { 257 c.i -= c.k 258 c.j -= c.k 259 c.k = 0 260 } 261 262 // remove the min value if needed 263 min := c.i 264 if c.j < min { 265 min = c.j 266 } 267 if c.k < min { 268 min = c.k 269 } 270 if min > 0 { 271 c.i -= min 272 c.j -= min 273 c.k -= min 274 } 275 } 276 277 /** 278 * Determines the H3 digit corresponding to a unit vector in ijk coordinates. 279 * 280 * @param ijk The ijk coordinates; must be a unit vector. 281 * @return The H3 digit (0-6) corresponding to the ijk unit vector, or 282 * INVALID_DIGIT on failure. 283 */ 284 func _unitIjkToDigit(ijk *CoordIJK) Direction { 285 c := *ijk 286 _ijkNormalize(&c) 287 digit := INVALID_DIGIT 288 for i := int(CENTER_DIGIT); i < int(NUM_DIGITS); i++ { 289 if _ijkMatches(&c, &UNIT_VECS[i]) { 290 digit = Direction(i) 291 break 292 } 293 } 294 295 return digit 296 } 297 298 /** 299 * Find the normalized ijk coordinates of the indexing parent of a cell in a 300 * counter-clockwise aperture 7 grid. Works in place. 301 * 302 * @param ijk The ijk coordinates. 303 */ 304 func _upAp7(ijk *CoordIJK) { 305 // convert to CoordIJ 306 i := ijk.i - ijk.k 307 j := ijk.j - ijk.k 308 ijk.i = int(lroundl(float64(3*i-j) / 7.0)) 309 ijk.j = int(lroundl(float64(i+2*j) / 7.0)) 310 ijk.k = 0 311 _ijkNormalize(ijk) 312 } 313 314 /** 315 * Find the normalized ijk coordinates of the indexing parent of a cell in a 316 * clockwise aperture 7 grid. Works in place. 317 * 318 * @param ijk The ijk coordinates. 319 */ 320 func _upAp7r(ijk *CoordIJK) { 321 // convert to CoordIJ 322 i := ijk.i - ijk.k 323 j := ijk.j - ijk.k 324 ijk.i = int(lroundl(float64(2*i+j) / 7.0)) 325 ijk.j = int(lroundl(float64(3*j-i) / 7.0)) 326 ijk.k = 0 327 _ijkNormalize(ijk) 328 } 329 330 /** 331 * Find the normalized ijk coordinates of the hex centered on the indicated 332 * hex at the next finer aperture 7 counter-clockwise resolution. Works in 333 * place. 334 * 335 * @param ijk The ijk coordinates. 336 */ 337 func _downAp7(ijk *CoordIJK) { 338 // res r unit vectors in res r+1 339 iVec := CoordIJK{3, 0, 1} 340 jVec := CoordIJK{1, 3, 0} 341 kVec := CoordIJK{0, 1, 3} 342 _ijkScale(&iVec, ijk.i) 343 _ijkScale(&jVec, ijk.j) 344 _ijkScale(&kVec, ijk.k) 345 _ijkAdd(&iVec, &jVec, ijk) 346 _ijkAdd(ijk, &kVec, ijk) 347 _ijkNormalize(ijk) 348 } 349 350 /** 351 * Find the normalized ijk coordinates of the hex centered on the indicated 352 * hex at the next finer aperture 7 clockwise resolution. Works in place. 353 * 354 * @param ijk The ijk coordinates. 355 */ 356 func _downAp7r(ijk *CoordIJK) { 357 // res r unit vectors in res r+1 358 iVec := CoordIJK{3, 1, 0} 359 jVec := CoordIJK{0, 3, 1} 360 kVec := CoordIJK{1, 0, 3} 361 _ijkScale(&iVec, ijk.i) 362 _ijkScale(&jVec, ijk.j) 363 _ijkScale(&kVec, ijk.k) 364 _ijkAdd(&iVec, &jVec, ijk) 365 _ijkAdd(ijk, &kVec, ijk) 366 _ijkNormalize(ijk) 367 } 368 369 /** 370 * Find the normalized ijk coordinates of the hex in the specified digit 371 * direction from the specified ijk coordinates. Works in place. 372 * 373 * @param ijk The ijk coordinates. 374 * @param digit The digit direction from the original ijk coordinates. 375 */ 376 func _neighbor(ijk *CoordIJK, digit Direction) { 377 if digit > CENTER_DIGIT && digit < NUM_DIGITS { 378 _ijkAdd(ijk, &UNIT_VECS[digit], ijk) 379 _ijkNormalize(ijk) 380 } 381 } 382 383 /** 384 * Rotates ijk coordinates 60 degrees counter-clockwise. Works in place. 385 * 386 * @param ijk The ijk coordinates. 387 */ 388 func _ijkRotate60ccw(ijk *CoordIJK) { 389 // unit vector rotations 390 iVec := CoordIJK{1, 1, 0} 391 jVec := CoordIJK{0, 1, 1} 392 kVec := CoordIJK{1, 0, 1} 393 _ijkScale(&iVec, ijk.i) 394 _ijkScale(&jVec, ijk.j) 395 _ijkScale(&kVec, ijk.k) 396 _ijkAdd(&iVec, &jVec, ijk) 397 _ijkAdd(ijk, &kVec, ijk) 398 _ijkNormalize(ijk) 399 } 400 401 /** 402 * Rotates ijk coordinates 60 degrees clockwise. Works in place. 403 * 404 * @param ijk The ijk coordinates. 405 */ 406 func _ijkRotate60cw(ijk *CoordIJK) { 407 // unit vector rotations 408 iVec := CoordIJK{1, 0, 1} 409 jVec := CoordIJK{1, 1, 0} 410 kVec := CoordIJK{0, 1, 1} 411 _ijkScale(&iVec, ijk.i) 412 _ijkScale(&jVec, ijk.j) 413 _ijkScale(&kVec, ijk.k) 414 _ijkAdd(&iVec, &jVec, ijk) 415 _ijkAdd(ijk, &kVec, ijk) 416 _ijkNormalize(ijk) 417 } 418 419 /** 420 * Rotates indexing digit 60 degrees counter-clockwise. Returns result. 421 * 422 * @param digit Indexing digit (between 1 and 6 inclusive) 423 */ 424 func _rotate60ccw(digit Direction) Direction { 425 switch digit { 426 case K_AXES_DIGIT: 427 return IK_AXES_DIGIT 428 case IK_AXES_DIGIT: 429 return I_AXES_DIGIT 430 case I_AXES_DIGIT: 431 return IJ_AXES_DIGIT 432 case IJ_AXES_DIGIT: 433 return J_AXES_DIGIT 434 case J_AXES_DIGIT: 435 return JK_AXES_DIGIT 436 case JK_AXES_DIGIT: 437 return K_AXES_DIGIT 438 default: 439 return digit 440 } 441 } 442 443 /** 444 * Rotates indexing digit 60 degrees clockwise. Returns result. 445 * 446 * @param digit Indexing digit (between 1 and 6 inclusive) 447 */ 448 func _rotate60cw(digit Direction) Direction { 449 switch digit { 450 case K_AXES_DIGIT: 451 return JK_AXES_DIGIT 452 case JK_AXES_DIGIT: 453 return J_AXES_DIGIT 454 case J_AXES_DIGIT: 455 return IJ_AXES_DIGIT 456 case IJ_AXES_DIGIT: 457 return I_AXES_DIGIT 458 case I_AXES_DIGIT: 459 return IK_AXES_DIGIT 460 case IK_AXES_DIGIT: 461 return K_AXES_DIGIT 462 default: 463 return digit 464 } 465 } 466 467 /** 468 * Find the normalized ijk coordinates of the hex centered on the indicated 469 * hex at the next finer aperture 3 counter-clockwise resolution. Works in 470 * place. 471 * 472 * @param ijk The ijk coordinates. 473 */ 474 func _downAp3(ijk *CoordIJK) { 475 // res r unit vectors in res r+1 476 iVec := CoordIJK{2, 0, 1} 477 jVec := CoordIJK{1, 2, 0} 478 kVec := CoordIJK{0, 1, 2} 479 _ijkScale(&iVec, ijk.i) 480 _ijkScale(&jVec, ijk.j) 481 _ijkScale(&kVec, ijk.k) 482 _ijkAdd(&iVec, &jVec, ijk) 483 _ijkAdd(ijk, &kVec, ijk) 484 _ijkNormalize(ijk) 485 } 486 487 /** 488 * Find the normalized ijk coordinates of the hex centered on the indicated 489 * hex at the next finer aperture 3 clockwise resolution. Works in place. 490 * 491 * @param ijk The ijk coordinates. 492 */ 493 func _downAp3r(ijk *CoordIJK) { 494 // res r unit vectors in res r+1 495 iVec := CoordIJK{2, 1, 0} 496 jVec := CoordIJK{0, 2, 1} 497 kVec := CoordIJK{1, 0, 2} 498 _ijkScale(&iVec, ijk.i) 499 _ijkScale(&jVec, ijk.j) 500 _ijkScale(&kVec, ijk.k) 501 _ijkAdd(&iVec, &jVec, ijk) 502 _ijkAdd(ijk, &kVec, ijk) 503 _ijkNormalize(ijk) 504 } 505 506 /** 507 * Finds the distance between the two coordinates. Returns result. 508 * 509 * @param c1 The first set of ijk coordinates. 510 * @param c2 The second set of ijk coordinates. 511 */ 512 func ijkDistance(c1 *CoordIJK, c2 *CoordIJK) float64 { 513 diff := CoordIJK{} 514 _ijkSub(c1, c2, &diff) 515 _ijkNormalize(&diff) 516 absDiff := &CoordIJK{int(math.Abs(float64(diff.i))), int(math.Abs(float64(diff.j))), int(math.Abs(float64(diff.k)))} 517 return math.Max(float64(absDiff.i), math.Max(float64(absDiff.j), float64(absDiff.k))) 518 } 519 520 /** 521 * Transforms coordinates from the IJK+ coordinate system to the IJ coordinate 522 * system. 523 * 524 * @param ijk The input IJK+ coordinates 525 * @param ij The output IJ coordinates 526 */ 527 func ijkToIj(ijk *CoordIJK, ij *CoordIJ) { 528 ij.i = ijk.i - ijk.k 529 ij.j = ijk.j - ijk.k 530 } 531 532 /** 533 * Transforms coordinates from the IJ coordinate system to the IJK+ coordinate 534 * system. 535 * 536 * @param ij The input IJ coordinates 537 * @param ijk The output IJK+ coordinates 538 */ 539 func ijToIjk(ij *CoordIJ, ijk *CoordIJK) { 540 ijk.i = ij.i 541 ijk.j = ij.j 542 ijk.k = 0 543 _ijkNormalize(ijk) 544 } 545 546 /** 547 * Convert IJK coordinates to cube coordinates, in place 548 * @param ijk Coordinate to convert 549 */ 550 func ijkToCube(ijk *CoordIJK) { 551 // 552 // * Convert IJK coordinates to cube coordinates, in place 553 // * @param ijk Coordinate to convert 554 // 555 ijk.i = -ijk.i + ijk.k 556 ijk.j = ijk.j - ijk.k 557 ijk.k = -ijk.i - ijk.j 558 } 559 560 /** 561 * Convert cube coordinates to IJK coordinates, in place 562 * @param ijk Coordinate to convert 563 */ 564 func cubeToIjk(ijk *CoordIJK) { 565 // 566 // * Convert cube coordinates to IJK coordinates, in place 567 // * @param ijk Coordinate to convert 568 // 569 ijk.i = -ijk.i 570 ijk.k = 0 571 _ijkNormalize(ijk) 572 } 573 574 func lroundl(x float64) int32 { 575 return int32(math.Round(x)) 576 }