46 constexpr uint8_t UNUSED = 255;
 
   48 alignas(64) uint8_t 
const FACE_NUM[64] = {
 
   49          4,      4,      4,      4, UNUSED,      3, UNUSED, UNUSED,
 
   50     UNUSED, UNUSED,      0, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
 
   51     UNUSED, UNUSED, UNUSED,      2, UNUSED,      3, UNUSED,      2,
 
   52     UNUSED, UNUSED,      0,      2, UNUSED, UNUSED, UNUSED,      2,
 
   53          5, UNUSED, UNUSED, UNUSED,      5,      3, UNUSED, UNUSED,
 
   54          5, UNUSED,      0, UNUSED,      5, UNUSED, UNUSED, UNUSED,
 
   55     UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,      3, UNUSED, UNUSED,
 
   56     UNUSED, UNUSED,      0, UNUSED,      1,      1,      1,      1
 
   59 uint8_t 
const FACE_COMP[6][4] = {
 
   60     {0, 1, 2, UNUSED}, {1, 2, 0, UNUSED}, {2, 0, 1, UNUSED},
 
   61     {0, 1, 2, UNUSED}, {1, 2, 0, UNUSED}, {2, 0, 1, UNUSED}
 
   64 double const FACE_CONST[6][4] = {
 
   65     { 1.0,  1.0, -1.0, 0.0},
 
   66     { 1.0,  1.0,  1.0, 0.0},
 
   67     { 1.0, -1.0,  1.0, 0.0},
 
   68     {-1.0, -1.0,  1.0, 0.0},
 
   69     {-1.0, -1.0, -1.0, 0.0},
 
   70     {-1.0,  1.0, -1.0, 0.0}
 
   74 constexpr 
double DILATION = 1.0e-15;
 
   79 uint64_t wrapIndex(
int level,
 
   84     uint32_t 
const stMax = (
static_cast<uint32_t
>(1) << level) - 1;
 
   87         if (s == 
static_cast<uint32_t
>(-1)) {
 
   88             face = (face + 4) % 6;
 
   92         } 
else if (s > stMax) {
 
   93             face = (face + 1) % 6;
 
   97         } 
else if (t == 
static_cast<uint32_t
>(-1)) {
 
   98             face = (face + 5) % 6;
 
  102         } 
else if (t > stMax) {
 
  103             face = (face + 2) % 6;
 
  110     return (
static_cast<uint64_t
>(face + 10) << (2 * level)) |
 
  114 int findNeighborhood(
int level, uint64_t i, uint64_t * dst) {
 
  115     int const face = 
static_cast<int>(i >> (2 * level)) - 10;
 
  118     dst[0] = wrapIndex(level, face, s - 1, t - 1);
 
  119     dst[1] = wrapIndex(level, face, s    , t - 1);
 
  120     dst[2] = wrapIndex(level, face, s + 1, t - 1);
 
  121     dst[3] = wrapIndex(level, face, s - 1, t);
 
  123     dst[5] = wrapIndex(level, face, s + 1, t);
 
  124     dst[6] = wrapIndex(level, face, s - 1, t + 1);
 
  125     dst[7] = wrapIndex(level, face, s    , t + 1);
 
  126     dst[8] = wrapIndex(level, face, s + 1, t + 1);
 
  128     return static_cast<int>(
std::unique(dst, dst + 9) - dst);
 
  131 #if defined(NO_SIMD) || !defined(__x86_64__) 
  132     void makeQuad(uint64_t i, 
int level, UnitVector3d * verts) {
 
  133         int const face = 
static_cast<int>(i >> (2 * level)) - 10;
 
  134         double const faceScale = FACE_SCALE[level];
 
  139             level, 
static_cast<int32_t
>(s), 
static_cast<int32_t
>(t));
 
  140         double u1 = (u0 + faceScale) + DILATION;
 
  141         double v1 = (v0 + faceScale) + DILATION;
 
  144         std::tie(u0, v0) = atanApproxInverse(u0, v0);
 
  145         std::tie(u1, v1) = atanApproxInverse(u1, v1);
 
  146         verts[0] = faceToSphere(face, u0, v0, FACE_COMP, FACE_CONST);
 
  147         verts[1] = faceToSphere(face, u1, v0, FACE_COMP, FACE_CONST);
 
  148         verts[2] = faceToSphere(face, u1, v1, FACE_COMP, FACE_CONST);
 
  149         verts[3] = faceToSphere(face, u0, v1, FACE_COMP, FACE_CONST);
 
  154         if ((face & 1) == 0) {
 
  159     void makeQuad(uint64_t i, 
int level, UnitVector3d * verts) {
 
  160         int const face = 
static_cast<int>(i >> (2 * level)) - 10;
 
  161         __m128d faceScale = _mm_set1_pd(FACE_SCALE[level]);
 
  162         __m128d dilation = _mm_set1_pd(DILATION);
 
  163         __m128d u0v0 = gridToFace(level, hilbertIndexInverseSimd(i, level));
 
  164         __m128d u1v1 = _mm_add_pd(u0v0, faceScale);
 
  165         u0v0 = atanApproxInverse(_mm_sub_pd(u0v0, dilation));
 
  166         u1v1 = atanApproxInverse(_mm_add_pd(u1v1, dilation));
 
  167         verts[0] = faceToSphere(face, u0v0, FACE_COMP, FACE_CONST);
 
  168         verts[1] = faceToSphere(face, _mm_shuffle_pd(u1v1, u0v0, 2),
 
  169                                 FACE_COMP, FACE_CONST);
 
  170         verts[2] = faceToSphere(face, u1v1, FACE_COMP, FACE_CONST);
 
  171         verts[3] = faceToSphere(face, _mm_shuffle_pd(u0v0, u1v1, 2),
 
  172                                 FACE_COMP, FACE_CONST);
 
  173         if ((face & 1) == 0) {
 
  197 template <
typename RegionType, 
bool InteriorOnly>
 
  198 class Mq3cPixelFinder: 
public detail::PixelFinder<
 
  199     Mq3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>
 
  202     using Base = detail::PixelFinder<
 
  203         Mq3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>;
 
  207     Mq3cPixelFinder(RangeSet & ranges,
 
  208                     RegionType 
const & region,
 
  211         Base(ranges, region, level, maxRanges)
 
  215         UnitVector3d 
pixel[4];
 
  217         for (uint64_t f = 10; f < 16; ++f) {
 
  218             makeQuad(f, 0, 
pixel);
 
  223     void subdivide(UnitVector3d 
const *, uint64_t i, 
int level) {
 
  224         UnitVector3d 
pixel[4];
 
  226         for (uint64_t c = i * 4; c != i * 4 + 4; ++c) {
 
  227             makeQuad(c, level, 
pixel);
 
  244     if ((j & 1) == 0 || (j == 1) || ((i >> (j - 3)) < 10)) {
 
  256     makeQuad(i, l, verts);
 
  257     return ConvexPolygon(verts[0], verts[1], verts[2], verts[3]);
 
  266     int n = findNeighborhood(l, i, indexes);
 
  271     static char const FACE_NORM[6][2] = {
 
  272         {
'-', 
'Z'}, {
'+', 
'X'}, {
'+', 
'Y'},
 
  273         {
'+', 
'Z'}, {
'-', 
'X'}, {
'-', 
'Y'},
 
  281     char * p = s + (
sizeof(s) - 1);
 
  282     for (; l > 0; --l, --p, i >>= 2) {
 
  287     p[0] = FACE_NORM[i - 10][0];
 
  288     p[1] = FACE_NORM[i - 10][1];
 
  289     return std::string(p, 
sizeof(s) - 
static_cast<size_t>(p - s));
 
  293     if (level < 0 || level > MAX_LEVEL) {
 
  295             "Modified-Q3C subdivision level not in [0, 30]");
 
  300     uint64_t f = i >> (2 * _level);
 
  301     if (f < 10 || f > 15) {
 
  305     makeQuad(i, _level, verts);
 
  310 #if defined(NO_SIMD) || !defined(__x86_64__) 
  312         int face = faceNumber(p, FACE_NUM);
 
  314         double u = (p(FACE_COMP[face][0]) / 
w) * FACE_CONST[face][0];
 
  315         double v = (p(FACE_COMP[face][1]) / 
w) * FACE_CONST[face][1];
 
  318         uint64_t h = 
hilbertIndex(
static_cast<uint32_t
>(std::get<0>(g)),
 
  319                                   static_cast<uint32_t
>(std::get<1>(g)),
 
  321         return (
static_cast<uint64_t
>(face + 10) << (2 * _level)) | h;
 
  325         int face = faceNumber(p, FACE_NUM);
 
  326         __m128d ww = _mm_set1_pd(p(FACE_COMP[face][2]));
 
  327         __m128d uv = _mm_set_pd(p(FACE_COMP[face][1]), p(FACE_COMP[face][0]));
 
  329             _mm_div_pd(uv, _mm_andnot_pd(_mm_set_pd(-0.0, -0.0), ww)),
 
  330             _mm_set_pd(FACE_CONST[face][1], FACE_CONST[face][0])
 
  332         __m128i st = faceToGrid(_level, atanApprox(uv));
 
  334         return (
static_cast<uint64_t
>(face + 10) << (2 * _level)) | h;
 
  338 RangeSet Mq3cPixelization::_envelope(Region 
const & r, 
size_t maxRanges)
 const {
 
  339     return detail::findPixels<Mq3cPixelFinder, false>(r, maxRanges, _level);
 
  342 RangeSet Mq3cPixelization::_interior(Region 
const & r, 
size_t maxRanges)
 const {
 
  343     return detail::findPixels<Mq3cPixelFinder, true>(r, maxRanges, _level);