#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { void parse(const rapidjson::Value& value, std::vector& target, const char *name) { if (!value.HasMember(name)) return; const rapidjson::Value& property = value[name]; if (!property.IsArray()) return; for (rapidjson::SizeType i = 0; i < property.Size(); i++) if (!property[i].IsString()) return; for (rapidjson::SizeType i = 0; i < property.Size(); i++) target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength())); } void parse(const rapidjson::Value& value, std::string& target, const char* name) { if (!value.HasMember(name)) return; const rapidjson::Value& property = value[name]; if (!property.IsString()) return; target = { property.GetString(), property.GetStringLength() }; } void parse(const rapidjson::Value& value, uint16_t& target, const char* name) { if (!value.HasMember(name)) return; const rapidjson::Value& property = value[name]; if (!property.IsUint()) return; unsigned int uint = property.GetUint(); if (uint > std::numeric_limits::max()) return; target = uint; } template void parse(const rapidjson::Value& value, std::array& target, const char* name) { if (!value.HasMember(name)) return; const rapidjson::Value& property = value[name]; if (!property.IsArray() || property.Size() != N) return; for (rapidjson::SizeType i = 0; i < property.Size(); i++) if (!property[i].IsNumber()) return; for (rapidjson::SizeType i = 0; i < property.Size(); i++) target[i] = property[i].GetDouble(); } void SourceInfo::parseTileJSONProperties(const rapidjson::Value& value) { parse(value, tiles, "tiles"); parse(value, min_zoom, "minzoom"); parse(value, max_zoom, "maxzoom"); parse(value, attribution, "attribution"); parse(value, center, "center"); parse(value, bounds, "bounds"); } std::string SourceInfo::tileURL(const Tile::ID& id, float pixelRatio) const { std::string result = tiles[(id.x + id.y) % tiles.size()]; result = util::mapbox::normalizeTileURL(result, url, type); result = util::replaceTokens(result, [&](const std::string &token) -> std::string { if (token == "z") return util::toString(id.z); if (token == "x") return util::toString(id.x); if (token == "y") return util::toString(id.y); if (token == "prefix") { std::string prefix { 2 }; prefix[0] = "0123456789abcdef"[id.x % 16]; prefix[1] = "0123456789abcdef"[id.y % 16]; return prefix; } if (token == "ratio") return pixelRatio > 1.0 ? "@2x" : ""; return ""; }); return result; } Source::Source() { } // Note: This is a separate function that must be called exactly once after creation // The reason this isn't part of the constructor is that calling shared_from_this() in // the constructor fails. void Source::load(const std::string& accessToken, Environment& env, std::function callback) { if (info.url.empty()) { loaded = true; return; } util::ptr source = shared_from_this(); const std::string url = util::mapbox::normalizeSourceURL(info.url, accessToken); env.request({ Resource::Kind::JSON, url }, [source, callback](const Response &res) { if (res.status != Response::Successful) { Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str()); return; } rapidjson::Document d; d.Parse<0>(res.data.c_str()); if (d.HasParseError()) { Log::Warning(Event::General, "Invalid source TileJSON; Parse Error at %d: %s", d.GetErrorOffset(), d.GetParseError()); return; } source->info.parseTileJSONProperties(d); source->loaded = true; callback(); }); } void Source::updateClipIDs(const std::map &mapping) { std::for_each(tiles.begin(), tiles.end(), [&mapping](std::pair> &pair) { Tile &tile = *pair.second; auto it = mapping.find(tile.id); if (it != mapping.end()) { tile.clip = it->second; } else { tile.clip = ClipID {}; } }); } void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) { for (const auto& pair : tiles) { Tile &tile = *pair.second; transform.matrixFor(tile.matrix, tile.id); matrix::multiply(tile.matrix, projMatrix, tile.matrix); } } size_t Source::getTileCount() const { return tiles.size(); } void Source::drawClippingMasks(Painter &painter) { for (const auto& pair : tiles) { Tile &tile = *pair.second; gl::group group(std::string { "mask: " } + std::string(tile.id)); painter.drawClippingMask(tile.matrix, tile.clip); } } void Source::render(Painter &painter, const StyleLayer &layer_desc) { gl::group group(std::string { "layer: " } + layer_desc.id); for (const auto& pair : tiles) { Tile &tile = *pair.second; if (tile.data && tile.data->state == TileData::State::parsed) { painter.renderTileLayer(tile, layer_desc, tile.matrix); } } } void Source::finishRender(Painter &painter) { for (const auto& pair : tiles) { Tile &tile = *pair.second; painter.renderTileDebug(tile); } } std::forward_list Source::getIDs() const { std::forward_list ptrs; std::transform(tiles.begin(), tiles.end(), std::front_inserter(ptrs), [](const std::pair> &pair) { Tile &tile = *pair.second; return tile.id; }); return ptrs; } std::forward_list Source::getLoadedTiles() const { std::forward_list ptrs; auto it = ptrs.before_begin(); for (const auto &pair : tiles) { if (pair.second->data->ready()) { it = ptrs.insert_after(it, pair.second.get()); } } return ptrs; } TileData::State Source::hasTile(const Tile::ID& id) { auto it = tiles.find(id); if (it != tiles.end()) { Tile &tile = *it->second; if (tile.id == id && tile.data) { return tile.data->state; } } return TileData::State::invalid; } TileData::State Source::addTile(Map &map, uv::worker &worker, util::ptr