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 | |
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 | |
105 | inline bool CanonicalTileID::operator==(const CanonicalTileID& rhs) const { |
106 | return z == rhs.z && x == rhs.x && y == rhs.y; |
107 | } |
108 | |
109 | inline bool CanonicalTileID::operator!=(const CanonicalTileID& rhs) const { |
110 | return z != rhs.z || x != rhs.x || y != rhs.y; |
111 | } |
112 | |
113 | inline bool CanonicalTileID::operator<(const CanonicalTileID& rhs) const { |
114 | return std::tie(args: z, args: x, args: y) < std::tie(args: rhs.z, args: rhs.x, args: rhs.y); |
115 | } |
116 | |
117 | 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 | |
123 | 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 | |
131 | 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 { ._M_elems: { |
136 | { childZ, childX, childY }, |
137 | { childZ, childX, childY + 1 }, |
138 | { childZ, childX + 1, childY }, |
139 | { childZ, childX + 1, childY + 1 }, |
140 | } }; |
141 | } |
142 | |
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 | |
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 | |
153 | inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) |
154 | : overscaledZ(z), wrap(0), canonical(z, x, y) { |
155 | } |
156 | |
157 | inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) |
158 | : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) { |
159 | assert(overscaledZ >= canonical.z); |
160 | } |
161 | |
162 | inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) |
163 | : overscaledZ(canonical_.z), wrap(0), canonical(std::forward<CanonicalTileID>(t&: canonical_)) { |
164 | assert(overscaledZ >= canonical.z); |
165 | } |
166 | |
167 | inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { |
168 | return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical; |
169 | } |
170 | |
171 | inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { |
172 | return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical; |
173 | } |
174 | |
175 | inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { |
176 | return std::tie(args: overscaledZ, args: wrap, args: canonical) < std::tie(args: rhs.overscaledZ, args: rhs.wrap, args: rhs.canonical); |
177 | } |
178 | |
179 | inline uint32_t OverscaledTileID::overscaleFactor() const { |
180 | return 1u << (overscaledZ - canonical.z); |
181 | } |
182 | |
183 | inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { |
184 | return overscaledZ > rhs.overscaledZ && |
185 | (canonical == rhs.canonical || canonical.isChildOf(parent: rhs.canonical)); |
186 | } |
187 | |
188 | inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { |
189 | return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(targetZ: z) }; |
190 | } |
191 | |
192 | inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { |
193 | return { wrap, canonical }; |
194 | } |
195 | |
196 | inline OverscaledTileID OverscaledTileID::unwrapTo(int16_t newWrap) { |
197 | return { overscaledZ, newWrap, canonical }; |
198 | } |
199 | |
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(a: static_cast<uint32_t>(y_), b: static_cast<uint32_t>(1ull << z_) - 1)) { |
206 | } |
207 | |
208 | inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_) |
209 | : wrap(wrap_), canonical(std::move(canonical_)) { |
210 | } |
211 | |
212 | inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const { |
213 | return wrap == rhs.wrap && canonical == rhs.canonical; |
214 | } |
215 | |
216 | inline bool UnwrappedTileID::operator!=(const UnwrappedTileID& rhs) const { |
217 | return wrap != rhs.wrap || canonical != rhs.canonical; |
218 | } |
219 | |
220 | inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const { |
221 | return std::tie(args: wrap, args: canonical) < std::tie(args: rhs.wrap, args: rhs.canonical); |
222 | } |
223 | |
224 | inline UnwrappedTileID UnwrappedTileID::unwrapTo(int16_t newWrap) { |
225 | return { newWrap, canonical }; |
226 | } |
227 | |
228 | inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const { |
229 | return wrap == parent.wrap && canonical.isChildOf(parent: parent.canonical); |
230 | } |
231 | |
232 | 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 { ._M_elems: { |
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 | |
244 | inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { |
245 | assert(overscaledZ >= canonical.z); |
246 | return { overscaledZ, wrap, canonical }; |
247 | } |
248 | |
249 | inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { |
250 | return pixelValue * (util::EXTENT / (util::tileSize * std::pow(x: 2, y: 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 | |