File indexing completed on 2024-04-21 14:52:02

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2016 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "MbTileWriter.h"
0007 
0008 #include <QCoreApplication>
0009 #include <QApplication>
0010 #include <QCommandLineParser>
0011 #include <QFileInfo>
0012 #include <QFile>
0013 #include <QDir>
0014 #include <QDirIterator>
0015 #include <QSqlDatabase>
0016 #include <QSqlQuery>
0017 #include <QSqlError>
0018 #include <QDebug>
0019 
0020 using namespace std;
0021 using namespace Marble;
0022 
0023 void importTiles(const QString &tileDirectory, MbTileWriter &tileWriter, const QPair<int, int> &tileLevels)
0024 {
0025     QString const extension = "o5m";
0026     QDir tileDir(tileDirectory);
0027     auto const strip = 1+tileDir.absolutePath().size();
0028     for(const auto &entryInfo: tileDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
0029         bool isNumber;
0030         int const z = entryInfo.baseName().toInt(&isNumber);
0031         if (isNumber && tileLevels.first <= z && z <= tileLevels.second) {
0032             QDirIterator tileIter(entryInfo.absoluteFilePath(), QDirIterator::Subdirectories);
0033             for (; tileIter.hasNext(); tileIter.next()) {
0034                 auto tileInfo = tileIter.fileInfo();
0035                 if (!tileInfo.isFile() || tileInfo.completeSuffix() != extension) {
0036                     continue;
0037                 }
0038 
0039                 QString const tileId = tileInfo.absoluteFilePath().mid(strip);
0040                 QStringList const tileEntries = tileId.split(QLatin1Char('/'));
0041                 if (tileEntries.size() == 3) {
0042                     int const x = tileEntries[1].toInt(&isNumber);
0043                     if (isNumber && x >= 0) {
0044                         int const y = tileInfo.baseName().toInt(&isNumber);
0045                         if (isNumber && y >= 0) {
0046                             tileWriter.addTile(tileInfo, x, y, z);
0047                         }
0048                     }
0049                 }
0050             }
0051         }
0052     }
0053 }
0054 
0055 int main(int argc, char** argv)
0056 {
0057     QCoreApplication app(argc, argv);
0058     QCoreApplication::setApplicationName("mbtile-import");
0059     QCoreApplication::setApplicationVersion("0.1");
0060 
0061     QCommandLineParser parser;
0062     parser.setApplicationDescription("Import tiles from a z/x/y.ext directory structure to a .mbtiles SQLite database.");
0063     auto const helpOption = parser.addHelpOption();
0064     auto const versionOption = parser.addVersionOption();
0065     parser.addPositionalArgument("directory", "Directory with tiles in z/x/y.ext structure");
0066     parser.addPositionalArgument("output", "Destination MBTile database");
0067 
0068     parser.addOptions({
0069                           {{"o", "overwrite"}, "Overwrite existing tiles in the database"},
0070                           {{"q", "quiet"}, "No progress report to stdout"},
0071                           {{"t", "tilelevels"}, "Restrict tile levels to <tilelevels>", "tilelevels", "0-20"},
0072                           {{"i", "interval"}, "Commit each <interval> tiles (0: single transaction)", "interval", "10000"},
0073                       });
0074 
0075     if (!parser.parse(QCoreApplication::arguments())) {
0076         qDebug() << parser.errorText();
0077         parser.showHelp(2);
0078     } else if (parser.isSet(helpOption)) {
0079         parser.showHelp(0);
0080     } else if (parser.isSet(versionOption)) {
0081         parser.showVersion();
0082         return 0;
0083     }
0084 
0085     const QStringList positionalArguments = parser.positionalArguments();
0086     if (positionalArguments.size() != 2) {
0087         parser.showHelp(positionalArguments.size() == 0 ? 0 : 1);
0088     }
0089 
0090     QString const tileDirectory = parser.positionalArguments()[0];
0091     if (!QFileInfo(tileDirectory).isDir()) {
0092         qDebug() << tileDirectory << "is not a directory";
0093         parser.showHelp(3);
0094     }
0095 
0096     QStringList const tileLevels = parser.value("tilelevels").split(QLatin1Char('-'));
0097     QPair<int, int> tileLevelRange = QPair<int, int>(0, 20);
0098     bool haveValidRange = false;
0099     if (tileLevels.size() == 2) {
0100         bool ok;
0101         tileLevelRange.first = tileLevels[0].toInt(&ok);
0102         if (ok) {
0103             tileLevelRange.second = tileLevels[1].toInt(&ok);
0104             if (ok) {
0105                 haveValidRange = tileLevelRange.first >= 0 && tileLevelRange.first <= tileLevelRange.second && tileLevelRange.second <= 30;
0106             }
0107         }
0108     }
0109 
0110     if (!haveValidRange) {
0111         qDebug() << "Cannot parse tile level range. Expecting format 'minLevel-maxLevel', e.g. '3-7'.";
0112         return 4;
0113     }
0114 
0115     QString const mbTilesFile = parser.positionalArguments()[1];
0116     MbTileWriter tileWriter(mbTilesFile);
0117     tileWriter.setOverwriteTiles(parser.isSet("overwrite"));
0118     tileWriter.setReportProgress(!parser.isSet("quiet"));
0119     tileWriter.setCommitInterval(parser.value("interval").toInt());
0120 
0121     importTiles(tileDirectory, tileWriter, tileLevelRange);
0122     return 0;
0123 }