56 3, 3, 3, 3, UNUSED, 0, UNUSED, UNUSED,
57 UNUSED, UNUSED, 5, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
58 UNUSED, UNUSED, UNUSED, 2, UNUSED, 0, UNUSED, 2,
59 UNUSED, UNUSED, 5, 2, UNUSED, UNUSED, UNUSED, 2,
60 4, UNUSED, UNUSED, UNUSED, 4, 0, UNUSED, UNUSED,
61 4, UNUSED, 5, UNUSED, 4, UNUSED, UNUSED, UNUSED,
62 UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, 0, UNUSED, UNUSED,
63 UNUSED, UNUSED, 5, UNUSED, 1, 1, 1, 1
67 {1, 0, 2, UNUSED}, {1, 2, 0, UNUSED}, {0, 2, 1, UNUSED},
68 {1, 2, 0, UNUSED}, {0, 2, 1, UNUSED}, {1, 0, 2, UNUSED}
71alignas(16)
double const FACE_CONST[6][4] = {
72 { 1.0, -1.0, 1.0, 0.0},
73 { 1.0, 1.0, 1.0, 0.0},
74 {-1.0, 1.0, 1.0, 0.0},
75 {-1.0, 1.0, -1.0, 0.0},
76 { 1.0, 1.0, -1.0, 0.0},
77 { 1.0, 1.0, -1.0, 0.0}
87constexpr double DILATION = 1.0e-15;
102 case 0: face = 4; s = stMax - t; t = stMax;
break;
103 case 1: face = 4; s = stMax;
break;
104 case 2: face = 1; s = stMax;
break;
105 case 3: face = 2; s = stMax;
break;
106 case 4: face = 3; s = stMax;
break;
107 case 5: face = 4; s = t; t = 0;
break;
111 }
else if (s > stMax) {
113 case 0: face = 2; s = t; t = stMax;
break;
114 case 1: face = 2; s = 0;
break;
115 case 2: face = 3; s = 0;
break;
116 case 3: face = 4; s = 0;
break;
117 case 4: face = 1; s = 0;
break;
118 case 5: face = 2; s = stMax - t; t = 0;
break;
124 case 0: face = 1; t = stMax;
break;
125 case 1: face = 5; t = stMax;
break;
126 case 2: face = 5; t = stMax - s; s = stMax;
break;
127 case 3: face = 5; t = 0; s = stMax - s;
break;
128 case 4: face = 5; t = s; s = 0;
break;
129 case 5: face = 3; t = 0; s = stMax - s;
break;
133 }
else if (t > stMax) {
135 case 0: face = 3; t = stMax; s = stMax - s;
break;
136 case 1: face = 0; t = 0;
break;
137 case 2: face = 0; t = s; s = stMax;
break;
138 case 3: face = 0; t = stMax; s = stMax - s;
break;
139 case 4: face = 0; t = stMax - s; s = 0;
break;
140 case 5: face = 1; t = 0;
break;
152 int const face =
static_cast<int>(i >> (2 *
level));
155 dst[0] = wrapIndex(level, face, s - 1, t - 1);
156 dst[1] = wrapIndex(level, face, s , t - 1);
157 dst[2] = wrapIndex(level, face, s + 1, t - 1);
158 dst[3] = wrapIndex(level, face, s - 1, t);
160 dst[5] = wrapIndex(level, face, s + 1, t);
161 dst[6] = wrapIndex(level, face, s - 1, t + 1);
162 dst[7] = wrapIndex(level, face, s , t + 1);
163 dst[8] = wrapIndex(level, face, s + 1, t + 1);
165 return static_cast<int>(
std::unique(dst, dst + 9) - dst);
168#if defined(NO_SIMD) || !defined(__x86_64__)
169 void makeQuad(
std::uint64_t i,
int level, UnitVector3d * verts) {
171 int const face =
static_cast<int>(i >> (2 *
level));
172 double const faceScale = FACE_SCALE[
level];
178 double u1 = (u0 + faceScale) + DILATION;
179 double v1 = (v0 + faceScale) + DILATION;
182 verts[0] = faceToSphere(face, u0, v0, FACE_COMP, FACE_CONST);
183 verts[1] = faceToSphere(face, u1, v0, FACE_COMP, FACE_CONST);
184 verts[2] = faceToSphere(face, u1, v1, FACE_COMP, FACE_CONST);
185 verts[3] = faceToSphere(face, u0, v1, FACE_COMP, FACE_CONST);
188 void makeQuad(
std::uint64_t i,
int level, UnitVector3d * verts) {
190 int const face =
static_cast<int>(i >> (2 *
level));
191 __m128d faceScale = _mm_set1_pd(FACE_SCALE[level]);
192 __m128d dilation = _mm_set1_pd(DILATION);
193 __m128d u0v0 = gridToFace(level, mortonIndexInverseSimd(i &
mask));
194 __m128d u1v1 = _mm_add_pd(u0v0, faceScale);
195 u0v0 = _mm_sub_pd(u0v0, dilation);
196 u1v1 = _mm_add_pd(u1v1, dilation);
197 verts[0] = faceToSphere(face, u0v0, FACE_COMP, FACE_CONST);
198 verts[1] = faceToSphere(face, _mm_shuffle_pd(u1v1, u0v0, 2),
199 FACE_COMP, FACE_CONST);
200 verts[2] = faceToSphere(face, u1v1, FACE_COMP, FACE_CONST);
201 verts[3] = faceToSphere(face, _mm_shuffle_pd(u0v0, u1v1, 2),
202 FACE_COMP, FACE_CONST);
224template <
typename RegionType,
bool InteriorOnly>
225class Q3cPixelFinder:
public detail::PixelFinder<
226 Q3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>
229 using Base = detail::PixelFinder<
230 Q3cPixelFinder<RegionType, InteriorOnly>, RegionType, InteriorOnly, 4>;
234 Q3cPixelFinder(RangeSet & ranges,
235 RegionType
const & region,
238 Base(ranges, region,
level, maxRanges)
242 UnitVector3d pixel[4];
245 makeQuad(f, 0, pixel);
250 void subdivide(UnitVector3d
const *,
std::uint64_t i,
int level) {
251 UnitVector3d pixel[4];
254 makeQuad(c, level, pixel);
255 visit(pixel, c, level);
274 makeQuad(i, _level, verts);
275 return ConvexPolygon(verts[0], verts[1], verts[2], verts[3]);
283 int n = findNeighborhood(_level, i, indexes);
288 static char const FACE_NORM[6][2] = {
289 {
'+',
'Z'}, {
'+',
'X'}, {
'+',
'Y'},
290 {
'-',
'X'}, {
'-',
'Y'}, {
'-',
'Z'},
297 char * p = s + (
sizeof(s) - 1);
298 for (
int l = _level; l > 0; --l, --p, i >>= 2) {
303 p[0] = FACE_NORM[i][0];
304 p[1] = FACE_NORM[i][1];
305 return std::string(p,
sizeof(s) -
static_cast<size_t>(p - s));
313 makeQuad(i, _level, verts);
318#if defined(NO_SIMD) || !defined(__x86_64__)
320 int face = faceNumber(p, FACE_NUM);
322 double u = (p(FACE_COMP[face][0]) /
w) * FACE_CONST[face][0];
323 double v = (p(FACE_COMP[face][1]) /
w) * FACE_CONST[face][1];
331 int face = faceNumber(p, FACE_NUM);
332 __m128d ww = _mm_set1_pd(p(FACE_COMP[face][2]));
333 __m128d uv = _mm_set_pd(p(FACE_COMP[face][1]), p(FACE_COMP[face][0]));
335 _mm_div_pd(uv, _mm_andnot_pd(_mm_set_pd(-0.0, -0.0), ww)),
336 _mm_set_pd(FACE_CONST[face][1], FACE_CONST[face][0])
338 __m128i st = faceToGrid(_level, uv);
344 return detail::findPixels<Q3cPixelFinder, false>(r, maxRanges, _level,
universe());
348 return detail::findPixels<Q3cPixelFinder, true>(r, maxRanges, _level,
universe());
This file declares a class for representing convex polygons with great circle edges on the unit spher...
This file provides a base class for pixel finders.
This file declares a Pixelization subclass for the Q3C indexing scheme.
This file contains functions used by Q3C pixelization implementations.
This file declares a class for representing unit vectors in ℝ³.
ConvexPolygon is a closed convex polygon on the unit sphere.
std::uint64_t index(UnitVector3d const &v) const override
index computes the index of the pixel for v.
ConvexPolygon quad(std::uint64_t i) const
quad returns the quadrilateral corresponding to the Q3C pixel with index i.
RangeSet _interior(Region const &r, size_t maxRanges) const override
RangeSet universe() const override
universe returns the set of all pixel indexes for this pixelization.
std::string toString(std::uint64_t i) const override
toString converts the given Q3C index to a human readable string.
Q3cPixelization(int level)
This constructor creates a Q3C pixelization of the sphere with the given subdivision level.
std::unique_ptr< Region > pixel(std::uint64_t i) const override
pixel returns the spherical region corresponding to the pixel with index i.
static constexpr int MAX_LEVEL
The maximum supported cube-face grid resolution is 2^30 by 2^30.
std::vector< std::uint64_t > neighborhood(std::uint64_t i) const
neighborhood returns the indexes of all pixels that share a vertex with pixel i (including i itself).
RangeSet _envelope(Region const &r, size_t maxRanges) const override
A RangeSet is a set of unsigned 64 bit integers.
Region is a minimal interface for 2-dimensional regions on the unit sphere.
UnitVector3d is a unit vector in ℝ³ with components stored in double precision.
void visit(UnitVector3d const *pixel, uint64_t index, int level)
This file contains functions for space-filling curves.
std::uint64_t mortonIndex(std::uint32_t x, std::uint32_t y)
mortonIndex interleaves the bits of x and y.
std::tuple< std::uint32_t, std::uint32_t > mortonIndexInverse(std::uint64_t z)
mortonIndexInverse separates the even and odd bits of z.