HilbertCode.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import Coordinate from '../../geom/Coordinate'
  2. import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException'
  3. export default class HilbertCode {
  4. static deinterleave(x) {
  5. x = x & 0x55555555
  6. x = (x | x >> 1) & 0x33333333
  7. x = (x | x >> 2) & 0x0F0F0F0F
  8. x = (x | x >> 4) & 0x00FF00FF
  9. x = (x | x >> 8) & 0x0000FFFF
  10. return x
  11. }
  12. static encode(level, x, y) {
  13. const lvl = HilbertCode.levelClamp(level)
  14. x = x << 16 - lvl
  15. y = y << 16 - lvl
  16. let a = x ^ y
  17. let b = 0xFFFF ^ a
  18. let c = 0xFFFF ^ (x | y)
  19. let d = x & (y ^ 0xFFFF)
  20. let A = a | b >> 1
  21. let B = a >> 1 ^ a
  22. let C = c >> 1 ^ b & d >> 1 ^ c
  23. let D = a & c >> 1 ^ d >> 1 ^ d
  24. a = A
  25. b = B
  26. c = C
  27. d = D
  28. A = a & a >> 2 ^ b & b >> 2
  29. B = a & b >> 2 ^ b & (a ^ b) >> 2
  30. C ^= a & c >> 2 ^ b & d >> 2
  31. D ^= b & c >> 2 ^ (a ^ b) & d >> 2
  32. a = A
  33. b = B
  34. c = C
  35. d = D
  36. A = a & a >> 4 ^ b & b >> 4
  37. B = a & b >> 4 ^ b & (a ^ b) >> 4
  38. C ^= a & c >> 4 ^ b & d >> 4
  39. D ^= b & c >> 4 ^ (a ^ b) & d >> 4
  40. a = A
  41. b = B
  42. c = C
  43. d = D
  44. C ^= a & c >> 8 ^ b & d >> 8
  45. D ^= b & c >> 8 ^ (a ^ b) & d >> 8
  46. a = C ^ C >> 1
  47. b = D ^ D >> 1
  48. let i0 = x ^ y
  49. let i1 = b | 0xFFFF ^ (i0 | a)
  50. i0 = (i0 | i0 << 8) & 0x00FF00FF
  51. i0 = (i0 | i0 << 4) & 0x0F0F0F0F
  52. i0 = (i0 | i0 << 2) & 0x33333333
  53. i0 = (i0 | i0 << 1) & 0x55555555
  54. i1 = (i1 | i1 << 8) & 0x00FF00FF
  55. i1 = (i1 | i1 << 4) & 0x0F0F0F0F
  56. i1 = (i1 | i1 << 2) & 0x33333333
  57. i1 = (i1 | i1 << 1) & 0x55555555
  58. const index = (i1 << 1 | i0) >> 32 - 2 * lvl
  59. return Math.trunc(index)
  60. }
  61. static checkLevel(level) {
  62. if (level > HilbertCode.MAX_LEVEL)
  63. throw new IllegalArgumentException('Level must be in range 0 to ' + HilbertCode.MAX_LEVEL)
  64. }
  65. static size(level) {
  66. HilbertCode.checkLevel(level)
  67. return Math.trunc(Math.pow(2, 2 * level))
  68. }
  69. static maxOrdinate(level) {
  70. HilbertCode.checkLevel(level)
  71. return Math.trunc(Math.pow(2, level)) - 1
  72. }
  73. static prefixScan(x) {
  74. x = x >> 8 ^ x
  75. x = x >> 4 ^ x
  76. x = x >> 2 ^ x
  77. x = x >> 1 ^ x
  78. return x
  79. }
  80. static decode(level, index) {
  81. HilbertCode.checkLevel(level)
  82. const lvl = HilbertCode.levelClamp(level)
  83. index = index << 32 - 2 * lvl
  84. const i0 = HilbertCode.deinterleave(index)
  85. const i1 = HilbertCode.deinterleave(index >> 1)
  86. const t0 = (i0 | i1) ^ 0xFFFF
  87. const t1 = i0 & i1
  88. const prefixT0 = HilbertCode.prefixScan(t0)
  89. const prefixT1 = HilbertCode.prefixScan(t1)
  90. const a = (i0 ^ 0xFFFF) & prefixT1 | i0 & prefixT0
  91. const x = (a ^ i1) >> 16 - lvl
  92. const y = (a ^ i0 ^ i1) >> 16 - lvl
  93. return new Coordinate(x, y)
  94. }
  95. static levelClamp(level) {
  96. let lvl = level < 1 ? 1 : level
  97. lvl = lvl > HilbertCode.MAX_LEVEL ? HilbertCode.MAX_LEVEL : lvl
  98. return lvl
  99. }
  100. static level(numPoints) {
  101. const pow2 = Math.trunc(Math.log(numPoints) / Math.log(2))
  102. let level = Math.trunc(pow2 / 2)
  103. const size = HilbertCode.size(level)
  104. if (size < numPoints) level += 1
  105. return level
  106. }
  107. }
  108. HilbertCode.MAX_LEVEL = 16