Warning, file /education/marble/tools/vectorosm-tilecreator/vectorosm-tirex-backend.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2016 Dennis Nienhüser <nienhueser@kde.org>
0003     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "TirexBackend.h"
0009 
0010 #include "GeoDataDocumentWriter.h"
0011 #include "GeoDataPolygon.h"
0012 #include "MarbleModel.h"
0013 #include "NodeReducer.h"
0014 #include "ParsingRunnerManager.h"
0015 #include "TileDirectory.h"
0016 #include "TileId.h"
0017 #include "VectorClipper.h"
0018 #include "WayConcatenator.h"
0019 #ifdef STATIC_BUILD
0020 #include "src/plugins/runner/osm/translators/O5mWriter.h"
0021 #endif
0022 
0023 #include <QCommandLineParser>
0024 #include <QCoreApplication>
0025 #include <QDebug>
0026 #include <QFile>
0027 #include <QSaveFile>
0028 #include <QtPlugin>
0029 
0030 #ifdef STATIC_BUILD
0031 Q_IMPORT_PLUGIN(OsmPlugin)
0032 Q_IMPORT_PLUGIN(ShpPlugin)
0033 #endif
0034 
0035 using namespace Marble;
0036 
0037 GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2)
0038 {
0039     GeoDataDocument* mergedMap = new GeoDataDocument(*map1);
0040     if (!map2) {
0041         return mergedMap;
0042     }
0043 
0044     OsmPlacemarkData marbleLand;
0045     marbleLand.addTag("marble_land","landmass");
0046     for (auto placemark: map2->placemarkList()) {
0047         GeoDataPlacemark* land = new GeoDataPlacemark(*placemark);
0048         if (geodata_cast<GeoDataPolygon>(land->geometry())) {
0049             land->setOsmData(marbleLand);
0050         }
0051         mergedMap->append(land);
0052     }
0053 
0054     return mergedMap;
0055 }
0056 
0057 int main(int argc, char **argv)
0058 {
0059     setenv("QT_LOGGING_TO_CONSOLE", "0", true); // redirects qDebug to syslog
0060 
0061     QCoreApplication app(argc, argv);
0062 
0063     // for stand-alone testing only, in normal operation this is entirely controlled via the Tirex command socket
0064     QCommandLineParser parser;
0065     parser.addOptions({
0066                       {{"c", "cache-directory"}, "Directory for temporary data.", "cache"},
0067                       {"x", "x coordinate of the requested tile", "x"},
0068                       {"y", "y coordinate of the requested tile", "y"},
0069                       {"z", "zoom level of the requested tile", "z"},
0070                       });
0071     parser.process(app);
0072 
0073     // work around MARBLE_ADD_WRITER not working for static builds
0074 #ifdef STATIC_BUILD
0075     GeoDataDocumentWriter::registerWriter(new O5mWriter, QStringLiteral("o5m"));
0076 #endif
0077 
0078     TirexBackend backend;
0079 
0080     MarbleModel model;
0081     ParsingRunnerManager manager(model.pluginManager());
0082     auto cacheDirectory = backend.configValue(QStringLiteral("cache-directory")).toString();
0083     if (cacheDirectory.isEmpty()) {
0084         cacheDirectory = parser.value("cache-directory");
0085     }
0086 
0087     QObject::connect(&backend, &TirexBackend::tileRequested, &app, [&](const TirexMetatileRequest &req) {
0088         // assuming the requested meta tile is a square power of two, we break that down into square power-of-two blocks
0089         // for high zoom levels using few (or even just one block is most efficient), for lower zoom levels we need to use
0090         // more blocks to reduce memory use
0091         // to avoid TileDirectory reloading the same block multiple times, we need to do the below processing in the proper order
0092         int loadZ = req.tile.z;
0093         if (backend.metatileColumns() == backend.metatileRows() && backend.metatileRows() == 8) {
0094             loadZ = req.tile.z - 3;
0095             loadZ = std::max(11, loadZ);
0096             loadZ = std::min(req.tile.z, loadZ);
0097         }
0098         const int blockSize = 1 << (req.tile.z - loadZ);
0099         const int blockColumns = backend.metatileColumns() / blockSize;
0100         const int blockRows = backend.metatileRows() / blockSize;
0101 
0102         TileDirectory mapTiles(cacheDirectory, QStringLiteral("planet.osmx"), manager, req.tile.z, loadZ);
0103         TileDirectory landTiles(TileDirectory::Landmass, cacheDirectory, manager, req.tile.z);
0104 
0105         QSaveFile f(backend.metatileFileName(req));
0106         if (!f.open(QFile::WriteOnly)) {
0107             backend.tileError(req, f.errorString());
0108             return;
0109         }
0110 
0111         backend.writeMetatileHeader(&f, req.tile);
0112         for (int blockX = 0; blockX < blockColumns; ++blockX) {
0113             for (int blockY = 0; blockY < blockRows; ++blockY) {
0114                 for (int tileX = 0; tileX < blockSize; ++tileX) {
0115                     for (int tileY = 0; tileY < blockSize; ++tileY) {
0116                         const auto x = blockX * blockSize + tileX;
0117                         const auto y = blockY * blockSize + tileY;
0118 
0119                         auto const tileId = TileId (0, req.tile.z, x + req.tile.x, y + req.tile.y);
0120                         using GeoDocPtr = QSharedPointer<GeoDataDocument>;
0121                         GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y()));
0122                         TagsFilter::removeAnnotationTags(tile1.data());
0123                         if (tileId.zoomLevel() < 17) {
0124                             WayConcatenator concatenator(tile1.data());
0125                         }
0126                         NodeReducer nodeReducer(tile1.data(), tileId);
0127                         GeoDocPtr tile2 = GeoDocPtr(landTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y()));
0128                         GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data()));
0129 
0130                         const auto offset = f.pos();
0131                         if (GeoDataDocumentWriter::write(&f, *combined, QStringLiteral("o5m"))) {
0132                             backend.writeMetatileEntry(&f, x * backend.metatileColumns() + y, offset, f.pos() - offset);
0133                         } else {
0134                             qWarning() << "Could not write the tile " << combined->name();
0135                         }
0136                     }
0137                 }
0138             }
0139         }
0140 
0141         f.commit();
0142         backend.tileDone(req);
0143     });
0144 
0145     if (parser.isSet("x") && parser.isSet("y") && parser.isSet("z")) {
0146         TirexMetatileRequest req;
0147         req.tile.x = parser.value("x").toInt();
0148         req.tile.y = parser.value("y").toInt();
0149         req.tile.z = parser.value("z").toInt();
0150         emit backend.tileRequested(req);
0151         return 0;
0152     }
0153 
0154     return app.exec();
0155 }