Skip to content

File morton_hash.h

File List > ext > geo > spatial_hash > morton_hash.h

Go to the documentation of this file

#pragma once
#include <muda/muda_def.h>
#include <cinttypes>
#include <muda/ext/eigen/eigen_core_cxx20.h>

namespace muda::spatial_hash
{
template <typename T>
class Morton
{
    static_assert("Morton not implemented for this type.");
};

template <>
class Morton<uint32_t>
{
  public:
    using Vector3u = Eigen::Vector3<uint32_t>;

    MUDA_GENERIC uint32_t operator()(const Vector3u& p) const
    {
        return (*this)(p.x(), p.y(), p.z());
    }

    constexpr MUDA_GENERIC uint32_t operator()(uint32_t x, uint32_t y, uint32_t z) const
    {
        x = expand_bits(x);
        y = expand_bits(y);
        z = expand_bits(z);
        return x | y << 1 | z << 2;
    }

  private:
    // Expands a 10-bit integer into 30 bits
    // by inserting 2 zeros after each bit.
    constexpr MUDA_GENERIC static uint32_t expand_bits(uint32_t v)
    {
        //v = (v * 0x00010001u) & 0xFF0000FFu;
        //v = (v * 0x00000101u) & 0x0F00F00Fu;
        //v = (v * 0x00000011u) & 0xC30C30C3u;
        //v = (v * 0x00000005u) & 0x49249249u;

        v &= 0x3ff;
        v = (v | v << 16) & 0x30000ff;
        v = (v | v << 8) & 0x300f00f;
        v = (v | v << 4) & 0x30c30c3;
        v = (v | v << 2) & 0x9249249;
        return (uint32_t)v;
    }
};

template <>
class Morton<uint64_t>
{
  public:
    using Vector3u = Eigen::Vector3<uint32_t>;

    MUDA_GENERIC uint64_t operator()(const Vector3u& p) const
    {
        return (*this)(p.x(), p.y(), p.z());
    }

    constexpr MUDA_GENERIC uint64_t operator()(uint32_t x, uint32_t y, uint32_t z) const
    {
        x = expand_bits(x);
        y = expand_bits(y);
        z = expand_bits(z);
        return x | y << 1 | z << 2;
    }

  private:
    // Expands a 21-bit integer into 63 bits
    // by inserting 2 zeros after each bit.
    constexpr MUDA_GENERIC static uint64_t expand_bits(uint64_t v)
    {
        v &= 0x1fffff;
        v = (v | v << 32) & 0x1f00000000ffff;
        v = (v | v << 16) & 0x1f0000ff0000ff;
        v = (v | v << 8) & 0x100f00f00f00f00f;
        v = (v | v << 4) & 0x10c30c30c30c30c3;
        v = (v | v << 2) & 0x1249249249249249;
        return v;
    }
};
}  // namespace muda::spatial_hash