💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
4.9 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_GEOM_MORTON_HPP
  20. #define ANTKEEPER_GEOM_MORTON_HPP
  21. #include <array>
  22. #include <cstdlib>
  23. namespace geom {
  24. /// Morton location code encoding and decoding functions.
  25. namespace morton {
  26. /**
  27. * Encodes 2D coordinates as a Morton location code.
  28. *
  29. * @param[in] x X-coordinate to encode.
  30. * @param[in] y Y-coordinate to encode.
  31. * @return Morton location code.
  32. */
  33. template <typename T>
  34. T encode(T x, T y);
  35. /**
  36. * Encodes 3D coordinates as a Morton location code.
  37. *
  38. * @param[in] x X-coordinate to encode.
  39. * @param[in] y Y-coordinate to encode.
  40. * @param[in] z Z-coordinate to encode.
  41. * @return Morton location code.
  42. */
  43. template <typename T>
  44. T encode(T x, T y, T z);
  45. /**
  46. * Decodes 2D coordinates from a Morton location code.
  47. *
  48. * @param[in] code Morton location code to decode.
  49. * @param[out] x Decoded x-coordinate.
  50. * @param[out] y Decoded y-coordinate.
  51. */
  52. template <typename T>
  53. void decode(T code, T& x, T& y);
  54. /**
  55. * Decodes 3D coordinates from a Morton location code.
  56. *
  57. * @param[in] code Morton location code to decode.
  58. * @param[out] x Decoded x-coordinate.
  59. * @param[out] y Decoded y-coordinate.
  60. * @param[out] z Decoded z-coordinate.
  61. */
  62. template <typename T>
  63. void decode(T code, T& x, T& y, T& z);
  64. template <typename T>
  65. T encode(T x, T y)
  66. {
  67. auto expand = [](T x) -> T
  68. {
  69. x &= (1 << (sizeof(T) << 2)) - 1;
  70. if constexpr(sizeof(T) >= 8)
  71. x = (x ^ (x << 16)) & T(0x0000ffff0000ffff);
  72. if constexpr(sizeof(T) >= 4)
  73. x = (x ^ (x << 8)) & T(0x00ff00ff00ff00ff);
  74. if constexpr(sizeof(T) >= 2)
  75. x = (x ^ (x << 4)) & T(0x0f0f0f0f0f0f0f0f);
  76. x = (x ^ (x << 2)) & T(0x3333333333333333);
  77. x = (x ^ (x << 1)) & T(0x5555555555555555);
  78. return x;
  79. };
  80. return expand(x) | (expand(y) << 1);
  81. }
  82. template <typename T>
  83. T encode(T x, T y, T z)
  84. {
  85. auto expand = [](T x) -> T
  86. {
  87. if constexpr(sizeof(T) == 1)
  88. {
  89. x &= 0x3;
  90. x = (x | x << 2) & 0x9;
  91. }
  92. else if constexpr(sizeof(T) == 2)
  93. {
  94. x &= 0x001f;
  95. x = (x | x << 8) & 0x100f;
  96. x = (x | x << 4) & 0x10c3;
  97. x = (x | x << 2) & 0x1249;
  98. }
  99. else if constexpr(sizeof(T) == 4)
  100. {
  101. x &= 0x00003ff;
  102. x = (x | x << 16) & 0x30000ff;
  103. x = (x | x << 8) & 0x300f00f;
  104. x = (x | x << 4) & 0x30c30c3;
  105. x = (x | x << 2) & 0x9249249;
  106. }
  107. else if constexpr(sizeof(T) == 8)
  108. {
  109. x &= 0x00000000001fffff;
  110. x = (x | x << 32) & 0x001f00000000ffff;
  111. x = (x | x << 16) & 0x001f0000ff0000ff;
  112. x = (x | x << 8) & 0x100f00f00f00f00f;
  113. x = (x | x << 4) & 0x10c30c30c30c30c3;
  114. x = (x | x << 2) & 0x1249249249249249;
  115. }
  116. return x;
  117. };
  118. return expand(x) | (expand(y) << 1) | (expand(z) << 2);
  119. }
  120. template <typename T>
  121. void decode(T code, T& x, T& y)
  122. {
  123. auto compress = [](T x) -> T
  124. {
  125. x &= T(0x5555555555555555);
  126. x = (x ^ (x >> 1)) & T(0x3333333333333333);
  127. x = (x ^ (x >> 2)) & T(0x0f0f0f0f0f0f0f0f);
  128. if constexpr(sizeof(T) >= 2)
  129. x = (x ^ (x >> 4)) & T(0x00ff00ff00ff00ff);
  130. if constexpr(sizeof(T) >= 4)
  131. x = (x ^ (x >> 8)) & T(0x0000ffff0000ffff);
  132. if constexpr(sizeof(T) >= 8)
  133. x = (x ^ (x >> 16)) & T(0x00000000ffffffff);
  134. return x;
  135. };
  136. x = compress(code);
  137. y = compress(code >> 1);
  138. }
  139. template <typename T>
  140. void decode(T code, T& x, T& y, T& z)
  141. {
  142. auto compress = [](T x) -> T
  143. {
  144. if constexpr(sizeof(T) == 1)
  145. {
  146. x &= 0x9;
  147. x = (x ^ x >> 2) & 0x3;
  148. }
  149. else if constexpr(sizeof(T) == 2)
  150. {
  151. x &= 0x1249;
  152. x = (x ^ x >> 2) & 0x10c3;
  153. x = (x ^ x >> 4) & 0x100f;
  154. x = (x ^ x >> 8) & 0x001f;
  155. }
  156. else if constexpr(sizeof(T) == 4)
  157. {
  158. x &= 0x9249249;
  159. x = (x ^ x >> 2) & 0x30c30c3;
  160. x = (x ^ x >> 4) & 0x300f00f;
  161. x = (x ^ x >> 8) & 0x30000ff;
  162. x = (x ^ x >> 16) & 0x00003ff;
  163. }
  164. else if constexpr(sizeof(T) == 8)
  165. {
  166. x &= 0x1249249249249249;
  167. x = (x ^ x >> 2) & 0x10c30c30c30c30c3;
  168. x = (x ^ x >> 4) & 0x100f00f00f00f00f;
  169. x = (x ^ x >> 8) & 0x001f0000ff0000ff;
  170. x = (x ^ x >> 16) & 0x001f00000000ffff;
  171. x = (x ^ x >> 32) & 0x00000000001fffff;
  172. }
  173. return x;
  174. };
  175. x = compress(code);
  176. y = compress(code >> 1);
  177. z = compress(code >> 2);
  178. }
  179. } // namespace morton
  180. } // namespace geom
  181. #endif // ANTKEEPER_GEOM_MORTON_HPP