1 #pragma once
2 
3 #include <mbgl/util/constants.hpp>
4 
5 #include <cstdint>
6 #include <array>
7 #include <tuple>
8 #include <forward_list>
9 #include <algorithm>
10 #include <iosfwd>
11 #include <cassert>
12 
13 namespace mbgl {
14 
15 class OverscaledTileID;
16 class CanonicalTileID;
17 class UnwrappedTileID;
18 
19 // Has integer z/x/y coordinates
20 // All tiles must be derived from 0/0/0 (=no tiles outside of the main tile pyramid)
21 // Used for requesting data; represents data tiles that exist out there.
22 // z is never larger than the source's maxzoom
23 class CanonicalTileID {
24 public:
25     CanonicalTileID(uint8_t z, uint32_t x, uint32_t y);
26     bool operator==(const CanonicalTileID&) const;
27     bool operator!=(const CanonicalTileID&) const;
28     bool operator<(const CanonicalTileID&) const;
29     bool isChildOf(const CanonicalTileID&) const;
30     CanonicalTileID scaledTo(uint8_t z) const;
31     std::array<CanonicalTileID, 4> children() const;
32 
33     uint8_t z;
34     uint32_t x;
35     uint32_t y;
36 };
37 
38 ::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs);
39 namespace util {
40 std::string toString(const CanonicalTileID&);
41 } // namespace util
42 
43 // Has integer z/x/y coordinates
44 // overscaledZ describes the zoom level this tile is intented to represent, e.g. when parsing data
45 // z is never larger than the source's maxzoom
46 // z/x/y describe the
47 class OverscaledTileID {
48 public:
49     OverscaledTileID(uint8_t overscaledZ, int16_t wrap, CanonicalTileID);
50     OverscaledTileID(uint8_t overscaledZ, int16_t wrap, uint8_t z, uint32_t x, uint32_t y);
51     OverscaledTileID(uint8_t z, uint32_t x, uint32_t y);
52     explicit OverscaledTileID(const CanonicalTileID&);
53     explicit OverscaledTileID(CanonicalTileID&&);
54     bool operator==(const OverscaledTileID&) const;
55     bool operator!=(const OverscaledTileID&) const;
56     bool operator<(const OverscaledTileID&) const;
57     bool isChildOf(const OverscaledTileID&) const;
58     uint32_t overscaleFactor() const;
59     OverscaledTileID scaledTo(uint8_t z) const;
60     UnwrappedTileID toUnwrapped() const;
61     OverscaledTileID unwrapTo(int16_t wrap);
62 
63     uint8_t overscaledZ;
64     int16_t wrap;
65     CanonicalTileID canonical;
66 };
67 
68 ::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs);
69 namespace util {
70 std::string toString(const OverscaledTileID&);
71 } // namespace util
72 
73 // Has integer z/x/y coordinates
74 // wrap describes tiles that are left/right of the main tile pyramid, e.g. when wrapping the world
75 // Used for describing what position tiles are getting rendered at (= calc the matrix)
76 // z is never larger than the source's maxzoom
77 class UnwrappedTileID {
78 public:
79     UnwrappedTileID(uint8_t z, int64_t x, int64_t y);
80     UnwrappedTileID(int16_t wrap, CanonicalTileID);
81     bool operator==(const UnwrappedTileID&) const;
82     bool operator!=(const UnwrappedTileID&) const;
83     bool operator<(const UnwrappedTileID&) const;
84     bool isChildOf(const UnwrappedTileID&) const;
85     std::array<UnwrappedTileID, 4> children() const;
86     OverscaledTileID overscaleTo(uint8_t z) const;
87     float pixelsToTileUnits(float pixelValue, float zoom) const;
88     UnwrappedTileID unwrapTo(int16_t wrap);
89 
90     int16_t wrap;
91     CanonicalTileID canonical;
92 };
93 
94 ::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs);
95 namespace util {
96 std::string toString(const UnwrappedTileID&);
97 } // namespace util
98 
CanonicalTileID(uint8_t z_,uint32_t x_,uint32_t y_)99 inline CanonicalTileID::CanonicalTileID(uint8_t z_, uint32_t x_, uint32_t y_) : z(z_), x(x_), y(y_) {
100     assert(z <= 32);
101     assert(x < (1ull << z));
102     assert(y < (1ull << z));
103 }
104 
operator ==(const CanonicalTileID & rhs) const105 inline bool CanonicalTileID::operator==(const CanonicalTileID& rhs) const {
106     return z == rhs.z && x == rhs.x && y == rhs.y;
107 }
108 
operator !=(const CanonicalTileID & rhs) const109 inline bool CanonicalTileID::operator!=(const CanonicalTileID& rhs) const {
110     return z != rhs.z || x != rhs.x || y != rhs.y;
111 }
112 
operator <(const CanonicalTileID & rhs) const113 inline bool CanonicalTileID::operator<(const CanonicalTileID& rhs) const {
114     return std::tie(z, x, y) < std::tie(rhs.z, rhs.x, rhs.y);
115 }
116 
isChildOf(const CanonicalTileID & parent) const117 inline bool CanonicalTileID::isChildOf(const CanonicalTileID& parent) const {
118     // We're first testing for z == 0, to avoid a 32 bit shift, which is undefined.
119     return parent.z == 0 ||
120            (parent.z < z && parent.x == (x >> (z - parent.z)) && parent.y == (y >> (z - parent.z)));
121 }
122 
scaledTo(uint8_t targetZ) const123 inline CanonicalTileID CanonicalTileID::scaledTo(uint8_t targetZ) const {
124     if (targetZ <= z) {
125         return { targetZ, x >> (z - targetZ), y >> (z - targetZ) }; // parent or same
126     } else {
127         return { targetZ, x << (targetZ - z), y << (targetZ - z) }; // child
128     }
129 }
130 
children() const131 inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const {
132     const uint8_t childZ = z + 1;
133     const uint32_t childX = x * 2;
134     const uint32_t childY = y * 2;
135     return { {
136         { childZ, childX, childY },
137         { childZ, childX, childY + 1 },
138         { childZ, childX + 1, childY },
139         { childZ, childX + 1, childY + 1 },
140     } };
141 }
142 
OverscaledTileID(uint8_t overscaledZ_,int16_t wrap_,CanonicalTileID canonical_)143 inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, CanonicalTileID canonical_)
144     : overscaledZ(overscaledZ_), wrap(wrap_), canonical(std::move(canonical_)) {
145     assert(overscaledZ >= canonical.z);
146 }
147 
OverscaledTileID(uint8_t overscaledZ_,int16_t wrap_,uint8_t z,uint32_t x,uint32_t y)148 inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, uint8_t z, uint32_t x, uint32_t y)
149     : overscaledZ(overscaledZ_), wrap(wrap_), canonical(z, x, y) {
150     assert(overscaledZ >= canonical.z);
151 }
152 
OverscaledTileID(uint8_t z,uint32_t x,uint32_t y)153 inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y)
154     : overscaledZ(z), wrap(0), canonical(z, x, y) {
155 }
156 
OverscaledTileID(const CanonicalTileID & canonical_)157 inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_)
158     : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) {
159     assert(overscaledZ >= canonical.z);
160 }
161 
OverscaledTileID(CanonicalTileID && canonical_)162 inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_)
163     : overscaledZ(canonical_.z), wrap(0), canonical(std::forward<CanonicalTileID>(canonical_)) {
164     assert(overscaledZ >= canonical.z);
165 }
166 
operator ==(const OverscaledTileID & rhs) const167 inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const {
168     return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical;
169 }
170 
operator !=(const OverscaledTileID & rhs) const171 inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const {
172     return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical;
173 }
174 
operator <(const OverscaledTileID & rhs) const175 inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const {
176     return std::tie(overscaledZ, wrap, canonical) < std::tie(rhs.overscaledZ, rhs.wrap, rhs.canonical);
177 }
178 
overscaleFactor() const179 inline uint32_t OverscaledTileID::overscaleFactor() const {
180     return 1u << (overscaledZ - canonical.z);
181 }
182 
isChildOf(const OverscaledTileID & rhs) const183 inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const {
184     return overscaledZ > rhs.overscaledZ &&
185            (canonical == rhs.canonical || canonical.isChildOf(rhs.canonical));
186 }
187 
scaledTo(uint8_t z) const188 inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const {
189     return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(z) };
190 }
191 
toUnwrapped() const192 inline UnwrappedTileID OverscaledTileID::toUnwrapped() const {
193     return { wrap, canonical };
194 }
195 
unwrapTo(int16_t newWrap)196 inline OverscaledTileID OverscaledTileID::unwrapTo(int16_t newWrap) {
197     return { overscaledZ, newWrap, canonical };
198 }
199 
UnwrappedTileID(uint8_t z_,int64_t x_,int64_t y_)200 inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_)
201     : wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)),
202       canonical(
203           z_,
204           static_cast<uint32_t>(x_ - wrap * (1ll << z_)),
205           y_ < 0 ? 0 : std::min(static_cast<uint32_t>(y_), static_cast<uint32_t>(1ull << z_) - 1)) {
206 }
207 
UnwrappedTileID(int16_t wrap_,CanonicalTileID canonical_)208 inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_)
209     : wrap(wrap_), canonical(std::move(canonical_)) {
210 }
211 
operator ==(const UnwrappedTileID & rhs) const212 inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const {
213     return wrap == rhs.wrap && canonical == rhs.canonical;
214 }
215 
operator !=(const UnwrappedTileID & rhs) const216 inline bool UnwrappedTileID::operator!=(const UnwrappedTileID& rhs) const {
217     return wrap != rhs.wrap || canonical != rhs.canonical;
218 }
219 
operator <(const UnwrappedTileID & rhs) const220 inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const {
221     return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical);
222 }
223 
unwrapTo(int16_t newWrap)224 inline UnwrappedTileID UnwrappedTileID::unwrapTo(int16_t newWrap) {
225     return { newWrap, canonical };
226 }
227 
isChildOf(const UnwrappedTileID & parent) const228 inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const {
229     return wrap == parent.wrap && canonical.isChildOf(parent.canonical);
230 }
231 
children() const232 inline std::array<UnwrappedTileID, 4> UnwrappedTileID::children() const {
233     const uint8_t childZ = canonical.z + 1;
234     const uint32_t childX = canonical.x * 2;
235     const uint32_t childY = canonical.y * 2;
236     return { {
237         { wrap, { childZ, childX, childY } },
238         { wrap, { childZ, childX, childY + 1 } },
239         { wrap, { childZ, childX + 1, childY } },
240         { wrap, { childZ, childX + 1, childY + 1 } },
241     } };
242 }
243 
overscaleTo(const uint8_t overscaledZ) const244 inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const {
245     assert(overscaledZ >= canonical.z);
246     return { overscaledZ, wrap, canonical };
247 }
248 
pixelsToTileUnits(const float pixelValue,const float zoom) const249 inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const {
250     return pixelValue * (util::EXTENT / (util::tileSize * std::pow(2, zoom - canonical.z)));
251 }
252 
253 } // namespace mbgl
254 
255 namespace std {
256 
257 template <>
258 struct hash<mbgl::CanonicalTileID> {
259     size_t operator()(const mbgl::CanonicalTileID& id) const;
260 };
261 
262 template <>
263 struct hash<mbgl::UnwrappedTileID> {
264     size_t operator()(const mbgl::UnwrappedTileID& id) const;
265 };
266 
267 template <>
268 struct hash<mbgl::OverscaledTileID> {
269     size_t operator()(const mbgl::OverscaledTileID& id) const;
270 };
271 
272 } // namespace std
273 
274