| 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 | |