46 constexpr uint8_t UNUSED = 255;
 
   48 alignas(64) uint8_t 
const FACE_NUM[64] = {
 
   49          3,      3,      3,      3, UNUSED,      0, UNUSED, UNUSED,
 
   50     UNUSED, UNUSED,      5, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
 
   51     UNUSED, UNUSED, UNUSED,      2, UNUSED,      0, UNUSED,      2,
 
   52     UNUSED, UNUSED,      5,      2, UNUSED, UNUSED, UNUSED,      2,
 
   53          4, UNUSED, UNUSED, UNUSED,      4,      0, UNUSED, UNUSED,
 
   54          4, UNUSED,      5, UNUSED,      4, UNUSED, UNUSED, UNUSED,
 
   55     UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,      0, UNUSED, UNUSED,
 
   56     UNUSED, UNUSED,      5, UNUSED,      1,      1,      1,      1
 
   59 uint8_t 
const FACE_COMP[6][4] = {
 
   60     {1, 0, 2, UNUSED}, {1, 2, 0, UNUSED}, {0, 2, 1, UNUSED},
 
   61     {1, 2, 0, UNUSED}, {0, 2, 1, UNUSED}, {1, 0, 2, UNUSED}
 
   64 alignas(16) 
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}
 
   80 constexpr 
double DILATION = 1.0e-15;
 
   85 uint64_t wrapIndex(
int level,
 
   90     uint32_t 
const stMax = (
static_cast<uint32_t
>(1) << level) - 1;
 
   93         if (s == 
static_cast<uint32_t
>(-1)) {
 
   95                 case 0: face = 4; s = stMax - t; t = stMax; 
break;
 
   96                 case 1: face = 4; s = stMax; 
break;
 
   97                 case 2: face = 1; s = stMax; 
break;
 
   98                 case 3: face = 2; s = stMax; 
break;
 
   99                 case 4: face = 3; s = stMax; 
break;
 
  100                 case 5: face = 4; s = t; t = 0; 
break;
 
  104         } 
else if (s > stMax) {
 
  106                 case 0: face = 2; s = t; t = stMax; 
break;
 
  107                 case 1: face = 2; s = 0; 
break;
 
  108                 case 2: face = 3; s = 0; 
break;
 
  109                 case 3: face = 4; s = 0; 
break;
 
  110                 case 4: face = 1; s = 0; 
break;
 
  111                 case 5: face = 2; s = stMax - t; t = 0; 
break;
 
  115         } 
else if (t == 
static_cast<uint32_t
>(-1)) {
 
  117                 case 0: face = 1; t = stMax; 
break;
 
  118                 case 1: face = 5; t = stMax; 
break;
 
  119                 case 2: face = 5; t = stMax - s; s = stMax; 
break;
 
  120                 case 3: face = 5; t = 0; s = stMax - s; 
break;
 
  121                 case 4: face = 5; t = s; s = 0; 
break;
 
  122                 case 5: face = 3; t = 0; s = stMax - s; 
break;
 
  126         } 
else if (t > stMax) {
 
  128                 case 0: face = 3; t = stMax; s = stMax - s; 
break;
 
  129                 case 1: face = 0; t = 0; 
break;
 
  130                 case 2: face = 0; t = s; s = stMax; 
break;
 
  131                 case 3: face = 0; t = stMax; s = stMax - s; 
break;
 
  132                 case 4: face = 0; t = stMax - s; s = 0; 
break;
 
  133                 case 5: face = 1; t = 0; 
break;
 
  140     return (
static_cast<uint64_t
>(face) << (2 * level)) | 
mortonIndex(s, t);
 
  143 int findNeighborhood(
int level, uint64_t i, uint64_t * dst) {
 
  144     uint64_t 
const mask = (
static_cast<uint64_t
>(1) << (2 * level)) - 1;
 
  145     int const face = 
static_cast<int>(i >> (2 * level));
 
  148     dst[0] = wrapIndex(level, face, s - 1, t - 1);
 
  149     dst[1] = wrapIndex(level, face, s    , t - 1);
 
  150     dst[2] = wrapIndex(level, face, s + 1, t - 1);
 
  151     dst[3] = wrapIndex(level, face, s - 1, t);
 
  153     dst[5] = wrapIndex(level, face, s + 1, t);
 
  154     dst[6] = wrapIndex(level, face, s - 1, t + 1);
 
  155     dst[7] = wrapIndex(level, face, s    , t + 1);
 
  156     dst[8] = wrapIndex(level, face, s + 1, t + 1);
 
  158     return static_cast<int>(
std::unique(dst, dst + 9) - dst);
 
  161 #if defined(NO_SIMD) || !defined(__x86_64__) 
  162     void makeQuad(uint64_t i, 
int level, UnitVector3d * verts) {
 
  163         uint64_t 
const mask = (
static_cast<uint64_t
>(1) << (2 * level)) - 1;
 
  164         int const face = 
static_cast<int>(i >> (2 * level));
 
  165         double const faceScale = FACE_SCALE[level];
 
  170             level, 
static_cast<int32_t
>(s), 
static_cast<int32_t
>(t));
 
  171         double u1 = (u0 + faceScale) + DILATION;
 
  172         double v1 = (v0 + faceScale) + DILATION;
 
  175         verts[0] = faceToSphere(face, u0, v0, FACE_COMP, FACE_CONST);
 
  176         verts[1] = faceToSphere(face, u1, v0, FACE_COMP, FACE_CONST);
 
  177         verts[2] = faceToSphere(face, u1, v1, FACE_COMP, FACE_CONST);
 
  178         verts[3] = faceToSphere(face, u0, v1, FACE_COMP, FACE_CONST);
 
  181     void makeQuad(uint64_t i, 
int level, UnitVector3d * verts) {
 
  182         uint64_t 
const mask = (
static_cast<uint64_t
>(1) << (2 * level)) - 1;
 
  183         int const face = 
static_cast<int>(i >> (2 * level));
 
  184         __m128d faceScale = _mm_set1_pd(FACE_SCALE[level]);
 
  185         __m128d dilation = _mm_set1_pd(DILATION);
 
  186         __m128d u0v0 = gridToFace(level, mortonIndexInverseSimd(i & 
mask));
 
  187         __m128d u1v1 = _mm_add_pd(u0v0, faceScale);
 
  188         u0v0 = _mm_sub_pd(u0v0, dilation);
 
  189         u1v1 = _mm_add_pd(u1v1, dilation);
 
  190         verts[0] = faceToSphere(face, u0v0, FACE_COMP, FACE_CONST);
 
  191         verts[1] = faceToSphere(face, _mm_shuffle_pd(u1v1, u0v0, 2),
 
  192                                 FACE_COMP, FACE_CONST);
 
  193         verts[2] = faceToSphere(face, u1v1, FACE_COMP, FACE_CONST);
 
  194         verts[3] = faceToSphere(face, _mm_shuffle_pd(u0v0, u1v1, 2),
 
  195                                 FACE_COMP, FACE_CONST);
 
  217 template <
typename RegionType, 
bool InteriorOnly>
 
  218 class Q3cPixelFinder: 
public detail::PixelFinder<
 
  219     Q3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>
 
  222     using Base = detail::PixelFinder<
 
  223         Q3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>;
 
  227     Q3cPixelFinder(RangeSet & ranges,
 
  228                    RegionType 
const & region,
 
  231         Base(ranges, region, level, maxRanges)
 
  235         UnitVector3d 
pixel[4];
 
  237         for (uint64_t f = 0; f < 6; ++f) {
 
  238             makeQuad(f, 0, 
pixel);
 
  243     void subdivide(UnitVector3d 
const *, uint64_t i, 
int level) {
 
  244         UnitVector3d 
pixel[4];
 
  246         for (uint64_t c = i * 4; c != i * 4 + 4; ++c) {
 
  247             makeQuad(c, level, 
pixel);
 
  257     if (level < 0 || level > MAX_LEVEL) {
 
  263     if (i >= 
static_cast<uint64_t
>(6) << (2 * _level)) {
 
  267     makeQuad(i, _level, verts);
 
  268     return ConvexPolygon(verts[0], verts[1], verts[2], verts[3]);
 
  272     if (i >= 
static_cast<uint64_t
>(6) << (2 * _level)) {
 
  276     int n = findNeighborhood(_level, i, indexes);
 
  281     static char const FACE_NORM[6][2] = {
 
  282         {
'+', 
'Z'}, {
'+', 
'X'}, {
'+', 
'Y'},
 
  283         {
'-', 
'X'}, {
'-', 
'Y'}, {
'-', 
'Z'},
 
  286     if (i >= 
static_cast<uint64_t
>(6) << (2 * _level)) {
 
  290     char * p = s + (
sizeof(s) - 1);
 
  291     for (
int l = _level; l > 0; --l, --p, i >>= 2) {
 
  296     p[0] = FACE_NORM[i][0];
 
  297     p[1] = FACE_NORM[i][1];
 
  298     return std::string(p, 
sizeof(s) - 
static_cast<size_t>(p - s));
 
  302     if (i >= 
static_cast<uint64_t
>(6) << (2 * _level)) {
 
  306     makeQuad(i, _level, verts);
 
  311 #if defined(NO_SIMD) || !defined(__x86_64__) 
  313         int face = faceNumber(p, FACE_NUM);
 
  315         double u = (p(FACE_COMP[face][0]) / 
w) * FACE_CONST[face][0];
 
  316         double v = (p(FACE_COMP[face][1]) / 
w) * FACE_CONST[face][1];
 
  318         uint64_t 
z = 
mortonIndex(
static_cast<uint32_t
>(std::get<0>(g)),
 
  319                                  static_cast<uint32_t
>(std::get<1>(g)));
 
  320         return (
static_cast<uint64_t
>(face) << (2 * _level)) | 
z;
 
  324         int face = faceNumber(p, FACE_NUM);
 
  325         __m128d ww = _mm_set1_pd(p(FACE_COMP[face][2]));
 
  326         __m128d uv = _mm_set_pd(p(FACE_COMP[face][1]), p(FACE_COMP[face][0]));
 
  328             _mm_div_pd(uv, _mm_andnot_pd(_mm_set_pd(-0.0, -0.0), ww)),
 
  329             _mm_set_pd(FACE_CONST[face][1], FACE_CONST[face][0])
 
  331         __m128i st = faceToGrid(_level, uv);
 
  332         return (
static_cast<uint64_t
>(face) << (2 * _level)) | 
mortonIndex(st);
 
  336 RangeSet Q3cPixelization::_envelope(Region 
const & r, 
size_t maxRanges)
 const {
 
  337     return detail::findPixels<Q3cPixelFinder, false>(r, maxRanges, _level);
 
  340 RangeSet Q3cPixelization::_interior(Region 
const & r, 
size_t maxRanges)
 const {
 
  341     return detail::findPixels<Q3cPixelFinder, true>(r, maxRanges, _level);