HilbertOrder.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import Check from "./Check.js";
  2. import DeveloperError from "./DeveloperError.js";
  3. /**
  4. * Hilbert Order helper functions.
  5. *
  6. * @namespace HilbertOrder
  7. */
  8. const HilbertOrder = {};
  9. /**
  10. * Computes the Hilbert index at the given level from 2D coordinates.
  11. *
  12. * @param {Number} level The level of the curve
  13. * @param {Number} x The X coordinate
  14. * @param {Number} y The Y coordinate
  15. * @returns {Number} The Hilbert index.
  16. * @private
  17. */
  18. HilbertOrder.encode2D = function (level, x, y) {
  19. const n = Math.pow(2, level);
  20. //>>includeStart('debug', pragmas.debug);
  21. Check.typeOf.number("level", level);
  22. Check.typeOf.number("x", x);
  23. Check.typeOf.number("y", y);
  24. if (level < 1) {
  25. throw new DeveloperError("Hilbert level cannot be less than 1.");
  26. }
  27. if (x < 0 || x >= n || y < 0 || y >= n) {
  28. throw new DeveloperError("Invalid coordinates for given level.");
  29. }
  30. //>>includeEnd('debug');
  31. const p = {
  32. x: x,
  33. y: y,
  34. };
  35. let rx,
  36. ry,
  37. s,
  38. // eslint-disable-next-line no-undef
  39. index = BigInt(0);
  40. for (s = n / 2; s > 0; s /= 2) {
  41. rx = (p.x & s) > 0 ? 1 : 0;
  42. ry = (p.y & s) > 0 ? 1 : 0;
  43. // eslint-disable-next-line no-undef
  44. index += BigInt(((3 * rx) ^ ry) * s * s);
  45. rotate(n, p, rx, ry);
  46. }
  47. return index;
  48. };
  49. /**
  50. * Computes the 2D coordinates from the Hilbert index at the given level.
  51. *
  52. * @param {Number} level The level of the curve
  53. * @param {BigInt} index The Hilbert index
  54. * @returns {Number[]} An array containing the 2D coordinates ([x, y]) corresponding to the Morton index.
  55. * @private
  56. */
  57. HilbertOrder.decode2D = function (level, index) {
  58. //>>includeStart('debug', pragmas.debug);
  59. Check.typeOf.number("level", level);
  60. Check.typeOf.bigint("index", index);
  61. if (level < 1) {
  62. throw new DeveloperError("Hilbert level cannot be less than 1.");
  63. }
  64. // eslint-disable-next-line no-undef
  65. if (index < BigInt(0) || index >= BigInt(Math.pow(4, level))) {
  66. throw new DeveloperError(
  67. "Hilbert index exceeds valid maximum for given level."
  68. );
  69. }
  70. //>>includeEnd('debug');
  71. const n = Math.pow(2, level);
  72. const p = {
  73. x: 0,
  74. y: 0,
  75. };
  76. let rx, ry, s, t;
  77. for (s = 1, t = index; s < n; s *= 2) {
  78. // eslint-disable-next-line no-undef
  79. rx = 1 & Number(t / BigInt(2));
  80. // eslint-disable-next-line no-undef
  81. ry = 1 & Number(t ^ BigInt(rx));
  82. rotate(s, p, rx, ry);
  83. p.x += s * rx;
  84. p.y += s * ry;
  85. // eslint-disable-next-line no-undef
  86. t /= BigInt(4);
  87. }
  88. return [p.x, p.y];
  89. };
  90. /**
  91. * @private
  92. */
  93. function rotate(n, p, rx, ry) {
  94. if (ry !== 0) {
  95. return;
  96. }
  97. if (rx === 1) {
  98. p.x = n - 1 - p.x;
  99. p.y = n - 1 - p.y;
  100. }
  101. const t = p.x;
  102. p.x = p.y;
  103. p.y = t;
  104. }
  105. export default HilbertOrder;