#pragma once #include #include #include namespace remap { // there are some more efficient ways in // http://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableObvious // but I was too lazy to understand them // some templates dealing with sizes // clang-format off template struct unsigned_size {}; template <> struct unsigned_size { using twice = uint16_t; /* 4 bits */ }; template <> struct unsigned_size { using twice = uint32_t; using half = uint8_t; }; template <> struct unsigned_size { using twice = uint64_t; using half = uint16_t; }; template <> struct unsigned_size { /* 128 bits */ using half = uint32_t; }; // clang-format on // shortcuts template using twice = typename unsigned_size::twice; template using half = typename unsigned_size::half; // converts x,y coordinates to z order template twice to_z_order(const T xin, const T yin) { const twice x = xin; const twice y = yin; twice z = 0; for (int i = 0; i < sizeof(T) * CHAR_BIT; i++) { z |= (x & (1U << i)) << i | (y & (1U << i)) << (i + 1); } return z; } // converts z to x,y template std::pair, half> from_z_order(const T z) { half x = 0; half y = 0; for (int i = 0; i < sizeof(T) * CHAR_BIT; i += 2) { x |= (z & (1U << i)) >> (i / 2); y |= (z & (1U << (i + 1))) >> (i / 2 + 1); } return {x, y}; } // from wikipedia // rotate/flip a quadrant appropriately template void hilbert_rot(T n, T * x, T * y, T rx, T ry) { if (ry == 0) { if (rx == 1) { *x = n - 1 - *x; *y = n - 1 - *y; } // Swap x and y int t = *x; *x = *y; *y = t; } } template twice to_hilbert(twice n, T xin, T yin) { twice x = xin; twice y = yin; twice d = 0; for (twice s = n / 2; s > 0; s /= 2) { twice rx = (x & s) > 0; twice ry = (y & s) > 0; d += s * s * ((3 * rx) ^ ry); hilbert_rot(s, &x, &y, rx, ry); } return d; } // convert d to (x,y) template std::pair, half> from_hilbert(T n, T d) { T t = d; T x = 0; T y = 0; for (T s = 1; s < n; s *= 2) { T rx = 1 & (t / 2); T ry = 1 & (t ^ rx); hilbert_rot(s, &x, &y, rx, ry); x += s * rx; y += s * ry; t /= 4; } return {half(x), half(y)}; } }