#include "map.h" #include #define _USE_MATH_DEFINES #include "common/utils.h" #include #include #include "logger.h" tileMap::tileMap(std::string url, std::string path, int expiry) { tileServerURL = url; tileSaveDir = path; expiryTime = expiry; } std::pair tileMap::coorToTile(std::pair coor, int zoom) { logger->debug("Calculating tile coordinates!"); int x, y; int n = std::pow(2, zoom); x = n * ((coor.second + 180) / 360); y = n * (1 - (log(tan(coor.first * (M_PI / 180)) + 1 / cos(coor.first * (M_PI / 180))) / M_PI)) / 2; return {x, y}; } std::pair tileMap::coorToTileF(std::pair coor, int zoom) { logger->debug("Calculating tile coordinates (float)!"); float x, y; float n = std::pow(2, zoom); x = n * ((coor.second + 180.0) / 360.0); y = n * (1.0 - (log(tan(coor.first * (M_PI / 180.0)) + 1 / cos(coor.first * (M_PI / 180.0))) / M_PI)) / 2.0; return {x, y}; } int widthToZoom(float deg, int width) { logger->debug("Calculating possible width!"); return round(log2(360 * width / (deg * TILE_SIZE))); } mapTile tileMap::downloadTile(std::pair t1, int zoom) { logger->debug("Downloading tile (" + std::to_string(t1.first) + ", " + std::to_string(t1.second) + ")"); image::Image img; if (t1.first >= pow(2, zoom)) t1.first -= ((t1.first / (int)pow(2, zoom)) * pow(2, zoom)); if (t1.second >= pow(2, zoom)) { logger->debug("Invalid tile, returning blank"); img = image::Image(TILE_SIZE, TILE_SIZE, 3); img.fill(120); return {t1.first, t1.second, img}; } std::string filename = tileSaveDir + std::to_string(zoom) + "/" + std::to_string(t1.first) + "/" + std::to_string(t1.second) + ".png"; bool old = false; if (std::filesystem::exists(filename)) { std::filesystem::file_time_type file = std::filesystem::last_write_time(filename); std::filesystem::file_time_type system = std::filesystem::file_time_type::clock::now(); std::chrono::duration dur = system.time_since_epoch() - file.time_since_epoch(); old = dur.count()/86400000000000 > expiryTime; } if (!std::filesystem::exists(filename) || old) { logger->debug("Tile not found or is outdated, downloading from: " + tileServerURL); std::string res; std::string url = tileServerURL + std::to_string(zoom) + "/" + std::to_string(t1.first) + "/" + std::to_string(t1.second) + ".png"; perform_http_request(url, res); img.load_png((uint8_t *)res.data(), res.size()); std::filesystem::create_directories(tileSaveDir + std::to_string(zoom) + "/" + std::to_string(t1.first) + "/"); std::ofstream of(filename); of << res; of.close(); logger->debug("Saving tile to: " + filename); } else { logger->debug("Tile found, loading from disk"); img.load_png(filename); } return mapTile(t1.first, t1.second, img); } mapTile::mapTile(int x1, int y1, image::Image tileImage) { x = x1; y = y1; data = tileImage; } image::Image tileMap::getMapImage(std::pair coor, int zoom, std::pair dim) { logger->debug("Creating map image"); image::Image img(dim.first, dim.second, 3); int xtiles = ceill(dim.first / (float)TILE_SIZE) + 1; int ytiles = ceill(dim.second / (float)TILE_SIZE) + 1; std::pair ft = coorToTile(coor, zoom); std::pair cf = coorToTileF(coor, zoom); int offX = TILE_SIZE * (cf.first - (int)cf.first); int offY = TILE_SIZE * (cf.second - (int)cf.second); for (int x = 0; x < xtiles; x++) for (int y = 0; y < ytiles; y++) img.draw_image(0, downloadTile({ft.first + x, ft.second + y}, zoom).data, x * TILE_SIZE - offX, y * TILE_SIZE - offY); return img; } image::Image tileMap::getMapImage(std::pair coor, std::pair coor1, int zoom) { logger->debug("Creating map image"); std::pair cf, cf1; int xtiles, ytiles; do { cf = coorToTileF(coor, zoom); cf1 = coorToTileF(coor1, zoom); xtiles = ceil(abs(cf.first - cf1.first)) + 1; ytiles = ceil(abs(cf.second - cf1.second)) + 1; if (xtiles * ytiles > TILE_DL_LIMIT && zoom >= 13){ logger->warn("Requested area is over 250 tiles with zoom > 13, lowering zoom level."); zoom--; } } while (xtiles * ytiles > TILE_DL_LIMIT && zoom >= 13); int offX = TILE_SIZE * (cf.first - (int)cf.first); int offY = TILE_SIZE * (cf.second - (int)cf.second); image::Image img(abs(cf.first - cf1.first) * TILE_SIZE, abs(cf.second - cf1.second) * TILE_SIZE, 3); for (int x = 0; x < xtiles; x++) for (int y = 0; y < ytiles; y++) img.draw_image(0, downloadTile({std::min(cf.first, cf1.first) + x, std::min(cf.second, cf1.second) + y}, zoom).data, x * TILE_SIZE - offX, y * TILE_SIZE - offY); return img; }