40int32_t computeNumSegments(AngleInterval
const & latitudes, Angle width) {
42 if (width.asRadians() >
PI) {
45 Angle maxAbsLat =
std::max(
abs(latitudes.getA()),
abs(latitudes.getB()));
46 if (maxAbsLat.asRadians() > 0.5 *
PI - 4.85e-6) {
49 double cosWidth =
cos(width);
50 double sinLat =
sin(maxAbsLat);
51 double cosLat =
cos(maxAbsLat);
52 double x = cosWidth - sinLat * sinLat;
53 double u = cosLat * cosLat;
55 return static_cast<int32_t
>(
59constexpr double BOX_EPSILON = 5.0e-12;
65 int32_t numSubStripesPerStripe) :
66 _numStripes(numStripes),
67 _numSubStripesPerStripe(numSubStripesPerStripe),
68 _numSubStripes(numStripes * numSubStripesPerStripe),
69 _maxSubChunksPerSubStripeChunk(0),
70 _subStripeHeight(
Angle(
PI) / _numSubStripes)
72 if (numStripes < 1 || numSubStripesPerStripe < 1) {
74 "per stripe must be positive");
76 if (numStripes * numSubStripesPerStripe > 180*3600) {
81 _subStripes.
reserve(_numSubStripes);
82 for (int32_t s = 0; s < _numStripes; ++s) {
85 (s + 1) * stripeHeight -
Angle(0.5 *
PI));
87 int32_t
const nc = computeNumSegments(sLat, stripeHeight);
88 stripe.chunkWidth =
Angle(2.0 *
PI) / nc;
89 stripe.numChunksPerStripe = nc;
90 int32_t ss = s * _numSubStripesPerStripe;
91 int32_t
const ssEnd = ss + _numSubStripesPerStripe;
92 for (; ss < ssEnd; ++ss) {
95 (ss + 1) * _subStripeHeight -
Angle(0.5 *
PI));
97 int32_t
const nsc = computeNumSegments(ssLat, _subStripeHeight) / nc;
98 stripe.numSubChunksPerChunk += nsc;
99 subStripe.numSubChunksPerChunk = nsc;
100 if (nsc > _maxSubChunksPerSubStripeChunk) {
101 _maxSubChunksPerSubStripeChunk = nsc;
103 subStripe.subChunkWidth =
Angle(2.0 *
PI) / (nsc * nc);
116 int32_t minSS =
std::min(
static_cast<int32_t
>(ya), _numSubStripes - 1);
117 int32_t maxSS =
std::min(
static_cast<int32_t
>(yb), _numSubStripes - 1);
118 int32_t minS = minSS / _numSubStripesPerStripe;
119 int32_t maxS = maxSS / _numSubStripesPerStripe;
120 for (int32_t s = minS; s <= maxS; ++s) {
122 Angle chunkWidth = _stripes[s].chunkWidth;
123 int32_t nc = _stripes[s].numChunksPerStripe;
124 double xa =
std::floor(
b.getLon().getA() / chunkWidth);
125 double xb =
std::floor(
b.getLon().getB() / chunkWidth);
126 int32_t ca =
std::min(
static_cast<int32_t
>(xa), nc - 1);
127 int32_t cb =
std::min(
static_cast<int32_t
>(xb), nc - 1);
128 if (ca == cb &&
b.getLon().wraps()) {
134 for (int32_t c = ca; c <= cb; ++c) {
140 for (int32_t c = 0; c <= cb; ++c) {
145 for (int32_t c = ca; c < nc; ++c) {
163 int32_t minSS =
std::min(
static_cast<int32_t
>(ya), _numSubStripes - 1);
164 int32_t maxSS =
std::min(
static_cast<int32_t
>(yb), _numSubStripes - 1);
165 int32_t minS = minSS / _numSubStripesPerStripe;
166 int32_t maxS = maxSS / _numSubStripesPerStripe;
167 for (int32_t s = minS; s <= maxS; ++s) {
169 Angle chunkWidth = _stripes[s].chunkWidth;
170 int32_t nc = _stripes[s].numChunksPerStripe;
171 double xa =
std::floor(
b.getLon().getA() / chunkWidth);
172 double xb =
std::floor(
b.getLon().getB() / chunkWidth);
173 int32_t ca =
std::min(
static_cast<int32_t
>(xa), nc - 1);
174 int32_t cb =
std::min(
static_cast<int32_t
>(xb), nc - 1);
175 if (ca == cb &&
b.getLon().wraps()) {
181 for (int32_t c = ca; c <= cb; ++c) {
182 _getSubChunks(chunks, r,
b.getLon(), s, c, minSS, maxSS);
185 for (int32_t c = 0; c <= cb; ++c) {
186 _getSubChunks(chunks, r,
b.getLon(), s, c, minSS, maxSS);
188 for (int32_t c = ca; c < nc; ++c) {
189 _getSubChunks(chunks, r,
b.getLon(), s, c, minSS, maxSS);
205 subChunks.
chunkId = _getChunkId(stripe, chunk);
212 minSS =
std::max(minSS, stripe * _numSubStripesPerStripe);
213 maxSS =
std::min(maxSS, (stripe + 1) * _numSubStripesPerStripe - 1);
214 int32_t
const nc = _stripes[stripe].numChunksPerStripe;
215 for (int32_t ss = minSS; ss <= maxSS; ++ss) {
217 Angle subChunkWidth = _subStripes[ss].subChunkWidth;
218 int32_t
const nsc = _subStripes[ss].numSubChunksPerChunk;
221 int32_t sca =
std::min(
static_cast<int32_t
>(xa), nc * nsc - 1);
222 int32_t scb =
std::min(
static_cast<int32_t
>(xb), nc * nsc - 1);
223 if (sca == scb && lon.
wraps()) {
227 int32_t minSC = chunk * nsc;
228 int32_t maxSC = (chunk + 1) * nsc - 1;
233 for (int32_t sc = minSC; sc <= maxSC; ++sc) {
236 _getSubChunkId(stripe, ss, chunk, sc));
242 for (int32_t sc = sca; sc <= maxSC; ++sc) {
245 _getSubChunkId(stripe, ss, chunk, sc));
248 for (int32_t sc = minSC; sc <= scb; ++sc) {
251 _getSubChunkId(stripe, ss, chunk, sc));
261 chunks.
back().swap(subChunks);
267 for (int32_t s = 0; s < _numStripes; ++s) {
268 int32_t nc = _stripes[s].numChunksPerStripe;
269 for (int32_t c = 0; c < nc; ++c) {
279 subChunkIds.
reserve(_stripes.
at(s).numSubChunksPerChunk);
280 int32_t
const ssBeg = s * _numSubStripesPerStripe;
281 int32_t
const ssEnd = ssBeg + _numSubStripesPerStripe;
282 for (int32_t ss = ssBeg; ss < ssEnd; ++ss) {
283 int32_t
const scEnd = _subStripes[ss].numSubChunksPerChunk;
284 int32_t
const subChunkIdBase = _maxSubChunksPerSubStripeChunk * (ss - ssBeg);
285 for (int32_t sc = 0; sc < scEnd; ++sc) {
286 subChunkIds.
push_back(subChunkIdBase + sc);
294 return s >= 0 and s < _numStripes and
295 getChunk(chunkId, s) < _stripes.
at(s).numChunksPerStripe;
299 Angle chunkWidth = _stripes[stripe].chunkWidth;
301 chunkWidth * (chunk + 1));
302 int32_t ss = stripe * _numSubStripesPerStripe;
303 int32_t ssEnd = ss + _numSubStripesPerStripe;
305 ssEnd * _subStripeHeight -
Angle(0.5 *
PI));
310 Angle subChunkWidth = _subStripes[subStripe].subChunkWidth;
312 subChunkWidth * (subChunk + 1));
314 (subStripe + 1) * _subStripeHeight -
Angle(0.5 *
PI));
This file declares a class for partitioning the sky into chunks and sub-chunks.
Angle represents an angle in radians.
AngleInterval represents closed intervals of arbitrary angles.
Box represents a rectangle in spherical coordinate space that contains its boundary.
Box dilatedBy(Angle r) const
std::vector< int32_t > getAllChunks() const
getAllChunks returns the complete set of chunk IDs for the unit sphere.
int32_t getStripe(int32_t chunkId) const
Return the stripe for the specified chunkId.
Box getSubChunkBoundingBox(int32_t subStripe, int32_t subChunk) const
int32_t getChunk(int32_t chunkId, int32_t stripe) const
Return the chunk for the given chunkId and stripe.
Chunker(int32_t numStripes, int32_t numSubStripesPerStripe)
std::vector< int32_t > getAllSubChunks(int32_t chunkId) const
getAllSubChunks returns the complete set of sub-chunk IDs for the given chunk.
std::vector< SubChunks > getSubChunksIntersecting(Region const &r) const
getSubChunksIntersecting returns all the sub-chunks that potentially intersect the given region.
Box getChunkBoundingBox(int32_t stripe, int32_t chunk) const
bool valid(int32_t chunkId) const
Return 'true' if the specified chunk number is valid.
std::vector< int32_t > getChunksIntersecting(Region const &r) const
getChunksIntersecting returns all the chunks that potentially intersect the given region.
NormalizedAngleInterval represents closed intervals of normalized angles, i.e.
bool wraps() const
wraps returns true if the interval "wraps" around the 0/2π angle discontinuity, i....
NormalizedAngle getA() const
getA returns the first endpoint of this interval.
NormalizedAngle getB() const
getB returns the second endpoint of this interval.
Region is a minimal interface for 2-dimensional regions on the unit sphere.
virtual Relationship relate(Region const &) const =0
virtual Box getBoundingBox() const =0
getBoundingBox returns a bounding-box for this region.
Angle abs(Angle const &a)
double sin(Angle const &a)
double cos(Angle const &a)
SubChunks represents a set of sub-chunks of a particular chunk.
std::vector< int32_t > subChunkIds