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

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2016 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "GeoDataDocumentWriter.h"
0007 #include "GeoDataGeometry.h"
0008 #include "GeoDataLatLonAltBox.h"
0009 #include "GeoDataPlacemark.h"
0010 #include "GeoDataPolygon.h"
0011 #include "MarbleDirs.h"
0012 #include "MarbleModel.h"
0013 #include "MbTileWriter.h"
0014 #include "NodeReducer.h"
0015 #include "ParsingRunnerManager.h"
0016 #include "TileDirectory.h"
0017 #include "TileId.h"
0018 #include "VectorClipper.h"
0019 #include "WayConcatenator.h"
0020 #include "TileQueue.h"
0021 
0022 #include <QApplication>
0023 #include <QBuffer>
0024 #include <QCommandLineParser>
0025 #include <QDebug>
0026 #include <QFileInfo>
0027 #include <QRect>
0028 
0029 #include <iostream>
0030 
0031 using namespace Marble;
0032 
0033 GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2)
0034 {
0035     GeoDataDocument* mergedMap = new GeoDataDocument(*map1);
0036 
0037     OsmPlacemarkData marbleLand;
0038     marbleLand.addTag("marble_land","landmass");
0039     for (auto placemark: map2->placemarkList()) {
0040         GeoDataPlacemark* land = new GeoDataPlacemark(*placemark);
0041         if (geodata_cast<GeoDataPolygon>(land->geometry())) {
0042             land->setOsmData(marbleLand);
0043         }
0044         mergedMap->append(land);
0045     }
0046 
0047     return mergedMap;
0048 }
0049 
0050 int main(int argc, char *argv[])
0051 {
0052     QTime timer;
0053     timer.start();
0054 
0055     QCoreApplication app(argc, argv);
0056 
0057     QCoreApplication::setApplicationName("marble-vectorosm-cachetiles");
0058     QCoreApplication::setApplicationVersion("0.1");
0059 
0060     QCommandLineParser parser;
0061     parser.setApplicationDescription("Create a vectorosm tile and its neighborhood");
0062     parser.addHelpOption();
0063     parser.addVersionOption();
0064     parser.addPositionalArgument("tile", "The tile to create (in z/x/y.extension format)");
0065 
0066     parser.addOptions({
0067                       {{"c", "cache-directory"}, "Directory for temporary data.", "cache", "cache"},
0068                       {{"m", "mbtile"}, "Store tiles in a mbtile database.", "mbtile"},
0069                       {"verbose", "Write progress information to standard output."}
0070                       });
0071     parser.process(app);
0072 
0073     const QStringList args = parser.positionalArguments();
0074     if (args.size() != 1) {
0075         parser.showHelp();
0076         return 0;
0077     }
0078 
0079     auto const input = args.first().split('/');
0080     if (input.size() != 3) {
0081         qWarning() << "Tile" << input << "does not match the z/x/y.format convention";
0082         parser.showHelp();
0083         return 1;
0084     }
0085 
0086     bool canParse[] = {false, false, false};
0087     TileId centerTile(0, input[0].toInt(&canParse[0]), input[1].toInt(&canParse[1]), QFileInfo(input[2]).baseName().toInt(&canParse[2]));
0088     if (!canParse[0] || !canParse[1] || !canParse[2]) {
0089         qWarning() << "Tile" << input << "does not consist of digits in the format z/x/y.format";
0090         parser.showHelp();
0091         return 1;
0092     }
0093 
0094     TileQueue tileQueue;
0095     QSet<TileId> dynamicTiles;
0096     tileQueue.read(dynamicTiles);
0097     if (dynamicTiles.contains(centerTile)) {
0098         return 0;
0099     }
0100 
0101     QString const extension = QFileInfo(input[2]).completeSuffix();
0102     QString const mbtile = parser.value("mbtile");
0103     QSharedPointer<MbTileWriter> mbtileWriter = QSharedPointer<MbTileWriter>(new MbTileWriter(mbtile, extension));
0104     mbtileWriter->setReportProgress(false);
0105     mbtileWriter->setCommitInterval(500);
0106 
0107     MarbleModel model;
0108     ParsingRunnerManager manager(model.pluginManager());
0109     QString const cacheDirectory = parser.value("cache-directory");
0110     QDir().mkpath(cacheDirectory);
0111     if (!QFileInfo(cacheDirectory).isWritable()) {
0112         qWarning() << "Cannot write to cache directory" << cacheDirectory;
0113         parser.showHelp(1);
0114     }
0115 
0116     TileDirectory mapTiles(TileDirectory::OpenStreetMap, cacheDirectory, manager, centerTile.zoomLevel());
0117     TileDirectory landTiles(TileDirectory::Landmass, cacheDirectory, manager, centerTile.zoomLevel());
0118 
0119     int const offset = 3;
0120     int const N = pow(2,centerTile.zoomLevel());
0121     QRect boundaries = QRect(0, 0, N-1, N-1) & QRect(QPoint(centerTile.x()-offset, centerTile.y()-offset),
0122                                                      QPoint(centerTile.x()+offset, centerTile.y()+offset));
0123     int count = 0;
0124     int const total = boundaries.width() * boundaries.height();
0125     bool const printProgress = parser.isSet("verbose");
0126     for (int x=boundaries.left(); x<=boundaries.right(); ++x) {
0127         for (int y=boundaries.top(); y<=boundaries.bottom(); ++y) {
0128             auto const tileId = TileId (0, centerTile.zoomLevel(), x, y);
0129             ++count;
0130             if (mbtileWriter->hasTile(x, y, tileId.zoomLevel())) {
0131                 continue;
0132             }
0133 
0134             using GeoDocPtr = QSharedPointer<GeoDataDocument>;
0135             GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y()));
0136             TagsFilter::removeAnnotationTags(tile1.data());
0137             if (tileId.zoomLevel() < 17) {
0138                 WayConcatenator concatenator(tile1.data());
0139             }
0140             NodeReducer nodeReducer(tile1.data(), tileId);
0141             GeoDocPtr tile2 = GeoDocPtr(landTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y()));
0142             GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data()));
0143 
0144             QBuffer buffer;
0145             buffer.open(QBuffer::ReadWrite);
0146             if (GeoDataDocumentWriter::write(&buffer, *combined, extension)) {
0147                 buffer.seek(0);
0148                 mbtileWriter->addTile(&buffer, tileId.x(), tileId.y(), tileId.zoomLevel());
0149             } else {
0150                 qWarning() << "Could not write the tile " << combined->name();
0151             }
0152 
0153             dynamicTiles << tileId;
0154 
0155             if (printProgress) {
0156                 TileDirectory::printProgress(qreal(count) / total);
0157                 std::cout << "  Tile " << count << "/" << total << " (";
0158                 std::cout << combined->name().toStdString() << ").";
0159                 std::cout << std::string(20, ' ') << '\r';
0160                 std::cout.flush();
0161             }
0162         }
0163     }
0164 
0165     tileQueue.write(dynamicTiles);
0166 
0167     if (printProgress) {
0168         TileDirectory::printProgress(1.0);
0169         std::cout << "Vector OSM tiles complete after " << timer.elapsed() << " ms." << std::string(30, ' ') << std::endl;
0170     }
0171 
0172     return 0;
0173 }