Antkeeper  0.0.1
morton.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 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 
20 #ifndef ANTKEEPER_GEOM_MORTON_HPP
21 #define ANTKEEPER_GEOM_MORTON_HPP
22 
23 #include <concepts>
24 
25 namespace geom {
26 
35 template <std::unsigned_integral T>
36 constexpr T morton_encode(T x, T y) noexcept
37 {
38  auto expand = [](T x) -> T
39  {
40  x &= (1 << (sizeof(T) << 2)) - 1;
41 
42  if constexpr(sizeof(T) >= 8)
43  {
44  x = (x ^ (x << 16)) & T(0x0000ffff0000ffff);
45  }
46  if constexpr(sizeof(T) >= 4)
47  {
48  x = (x ^ (x << 8)) & T(0x00ff00ff00ff00ff);
49  }
50  if constexpr(sizeof(T) >= 2)
51  {
52  x = (x ^ (x << 4)) & T(0x0f0f0f0f0f0f0f0f);
53  }
54 
55  x = (x ^ (x << 2)) & T(0x3333333333333333);
56  x = (x ^ (x << 1)) & T(0x5555555555555555);
57 
58  return x;
59  };
60 
61  return expand(x) | (expand(y) << 1);
62 }
63 
73 template <std::unsigned_integral T>
74 constexpr T morton_encode(T x, T y, T z) noexcept
75 {
76  auto expand = [](T x) -> T
77  {
78  if constexpr(sizeof(T) == 1)
79  {
80  x &= T(0x3);
81  x = (x | x << 2) & T(0x9);
82  }
83  else if constexpr(sizeof(T) == 2)
84  {
85  x &= T(0x001f);
86  x = (x | x << 8) & T(0x100f);
87  x = (x | x << 4) & T(0x10c3);
88  x = (x | x << 2) & T(0x1249);
89  }
90  else if constexpr(sizeof(T) == 4)
91  {
92  x &= T(0x00003ff);
93  x = (x | x << 16) & T(0x30000ff);
94  x = (x | x << 8) & T(0x300f00f);
95  x = (x | x << 4) & T(0x30c30c3);
96  x = (x | x << 2) & T(0x9249249);
97  }
98  else if constexpr(sizeof(T) == 8)
99  {
100  x &= T(0x00000000001fffff);
101  x = (x | x << 32) & T(0x001f00000000ffff);
102  x = (x | x << 16) & T(0x001f0000ff0000ff);
103  x = (x | x << 8) & T(0x100f00f00f00f00f);
104  x = (x | x << 4) & T(0x10c30c30c30c30c3);
105  x = (x | x << 2) & T(0x1249249249249249);
106  }
107 
108  return x;
109  };
110 
111  return expand(x) | (expand(y) << 1) | (expand(z) << 2);
112 }
113 
121 template <std::unsigned_integral T>
122 void morton_decode(T code, T& x, T& y) noexcept
123 {
124  auto compress = [](T x) -> T
125  {
126  x &= T(0x5555555555555555);
127  x = (x ^ (x >> 1)) & T(0x3333333333333333);
128  x = (x ^ (x >> 2)) & T(0x0f0f0f0f0f0f0f0f);
129 
130  if constexpr(sizeof(T) >= 2)
131  {
132  x = (x ^ (x >> 4)) & T(0x00ff00ff00ff00ff);
133  }
134  if constexpr(sizeof(T) >= 4)
135  {
136  x = (x ^ (x >> 8)) & T(0x0000ffff0000ffff);
137  }
138  if constexpr(sizeof(T) >= 8)
139  {
140  x = (x ^ (x >> 16)) & T(0x00000000ffffffff);
141  }
142 
143  return x;
144  };
145 
146  x = compress(code);
147  y = compress(code >> 1);
148 }
149 
158 template <std::unsigned_integral T>
159 void morton_decode(T code, T& x, T& y, T& z) noexcept
160 {
161  auto compress = [](T x) -> T
162  {
163  if constexpr(sizeof(T) == 1)
164  {
165  x &= T(0x9);
166  x = (x ^ x >> 2) & T(0x3);
167  }
168  else if constexpr(sizeof(T) == 2)
169  {
170  x &= T(0x1249);
171  x = (x ^ x >> 2) & T(0x10c3);
172  x = (x ^ x >> 4) & T(0x100f);
173  x = (x ^ x >> 8) & T(0x001f);
174  }
175  else if constexpr(sizeof(T) == 4)
176  {
177  x &= T(0x9249249);
178  x = (x ^ x >> 2) & T(0x30c30c3);
179  x = (x ^ x >> 4) & T(0x300f00f);
180  x = (x ^ x >> 8) & T(0x30000ff);
181  x = (x ^ x >> 16) & T(0x00003ff);
182  }
183  else if constexpr(sizeof(T) == 8)
184  {
185  x &= T(0x1249249249249249);
186  x = (x ^ x >> 2) & T(0x10c30c30c30c30c3);
187  x = (x ^ x >> 4) & T(0x100f00f00f00f00f);
188  x = (x ^ x >> 8) & T(0x001f0000ff0000ff);
189  x = (x ^ x >> 16) & T(0x001f00000000ffff);
190  x = (x ^ x >> 32) & T(0x00000000001fffff);
191  }
192 
193  return x;
194  };
195 
196  x = compress(code);
197  y = compress(code >> 1);
198  z = compress(code >> 2);
199 }
200 
201 } // namespace geom
202 
203 #endif // ANTKEEPER_GEOM_MORTON_HPP
constexpr T compress(T x) noexcept
Compresses the even bits of a value into the lower half, then clears the upper half.
Definition: bit-math.hpp:193
constexpr T expand(T x) noexcept
Moves bits from the lower half of a value to occupy all even bits, and clears all odd bits.
Definition: bit-math.hpp:247
Geometric algorithms.
constexpr T morton_encode(T x, T y) noexcept
Encodes 2D coordinates as a Morton location code.
Definition: morton.hpp:36
void morton_decode(T code, T &x, T &y) noexcept
Decodes 2D coordinates from a Morton location code.
Definition: morton.hpp:122