File indexing completed on 2024-09-15 11:53:27
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 <QDebug> 0009 #include <QSqlDatabase> 0010 #include <QSqlError> 0011 0012 #include <iostream> 0013 #include <iomanip> 0014 0015 namespace Marble 0016 { 0017 0018 MbTileWriter::MbTileWriter(const QString &filename, const QString &extension) : 0019 m_overwriteTiles(true), 0020 m_reportProgress(true), 0021 m_tileCounter(0), 0022 m_commitInterval(10000) 0023 { 0024 bool const exists = QFileInfo(filename).exists(); 0025 0026 QSqlDatabase database = QSqlDatabase::addDatabase( "QSQLITE" ); 0027 database.setDatabaseName( filename ); 0028 if ( !database.open() ) { 0029 qCritical() << "Failed to connect to database"; 0030 return; 0031 } 0032 0033 if (!exists) { 0034 execQuery("PRAGMA application_id = 0x4d504258"); // MBTiles tileset, see https://www.sqlite.org/src/artifact?ci=trunk&filename=magic.txt 0035 execQuery("CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob);"); 0036 execQuery("CREATE UNIQUE INDEX tile_index ON tiles(zoom_level, tile_column, tile_row);"); 0037 0038 execQuery("CREATE TABLE metadata (name text, value text);"); 0039 setMetaData("name", "Marble Vector OSM"); 0040 setMetaData("type", "baselayer"); 0041 setMetaData("version", "1.0"); 0042 setMetaData("description", "A global roadmap created by the OpenStreetMap (OSM) project"); 0043 setMetaData("format", extension); 0044 setMetaData("attribution", "Data from <a href=\"https://openstreetmap.org/\">OpenStreetMap</a> and <a href=\"https://www.naturalearthdata.com/\">Natural Earth</a> contributors"); 0045 } 0046 execQuery("BEGIN TRANSACTION"); 0047 } 0048 0049 MbTileWriter::~MbTileWriter() 0050 { 0051 execQuery("END TRANSACTION"); 0052 if (m_reportProgress) { 0053 std::cout << std::endl; 0054 } 0055 } 0056 0057 void MbTileWriter::setOverwriteTiles(bool overwrite) 0058 { 0059 m_overwriteTiles = overwrite; 0060 } 0061 0062 void MbTileWriter::setReportProgress(bool report) 0063 { 0064 m_reportProgress = report; 0065 } 0066 0067 void MbTileWriter::setCommitInterval(int interval) 0068 { 0069 m_commitInterval = interval; 0070 } 0071 0072 void MbTileWriter::addTile(const QFileInfo &file, qint32 x, qint32 y, qint32 z) 0073 { 0074 if (!m_overwriteTiles && hasTile(x, y, z)) { 0075 if (m_reportProgress) { 0076 std::cout << " Skipping existing " << z << '/' << x << '/' << y << '\r'; 0077 std::cout.flush(); 0078 } 0079 return; 0080 } 0081 0082 if (m_reportProgress && m_tileCounter % 500 == 0) { 0083 std::cout << "Tile " << std::right << std::setw(10) << m_tileCounter << ": "; 0084 std::cout << "Adding " << z << '/' << x << '/' << y << '\r'; 0085 std::cout.flush(); 0086 } 0087 0088 QFile tileContent(file.absoluteFilePath()); 0089 tileContent.open(QFile::ReadOnly); 0090 addTile(&tileContent, x, y, z); 0091 } 0092 0093 void MbTileWriter::addTile(QIODevice *device, qint32 x, qint32 y, qint32 z) 0094 { 0095 ++m_tileCounter; 0096 if (m_commitInterval > 0 && m_tileCounter % m_commitInterval == 0) { 0097 execQuery("END TRANSACTION"); 0098 execQuery("BEGIN TRANSACTION"); 0099 } 0100 0101 QSqlQuery query; 0102 query.prepare( "INSERT OR REPLACE INTO tiles" 0103 " (zoom_level, tile_column, tile_row, tile_data)" 0104 " VALUES (?, ?, ?, ?)" ); 0105 query.addBindValue(z); 0106 query.addBindValue(x); 0107 query.addBindValue(y); 0108 query.addBindValue(device->readAll()); 0109 execQuery(query); 0110 } 0111 0112 bool MbTileWriter::hasTile(qint32 x, qint32 y, qint32 z) const 0113 { 0114 QSqlQuery query; 0115 query.prepare( "SELECT EXISTS(SELECT 1 FROM tiles" 0116 " WHERE zoom_level=? AND tile_column=? AND tile_row=?);"); 0117 query.addBindValue(z); 0118 query.addBindValue(x); 0119 query.addBindValue(y); 0120 query.exec(); 0121 if (query.lastError().isValid()) { 0122 qCritical() << "Problems occurred when executing the query" << query.executedQuery(); 0123 qCritical() << "SQL error: " << query.lastError(); 0124 } else { 0125 if (query.next()) { 0126 return query.value(0).toBool(); 0127 } 0128 } 0129 return false; 0130 } 0131 0132 void MbTileWriter::execQuery( const QString &query ) const 0133 { 0134 QSqlQuery sqlQuery( query ); 0135 if ( sqlQuery.lastError().isValid() ) { 0136 qCritical() << "Problems occurred when executing the query" << query; 0137 qCritical() << "SQL error: " << sqlQuery.lastError(); 0138 } 0139 } 0140 0141 void MbTileWriter::execQuery( QSqlQuery &query ) const 0142 { 0143 query.exec(); 0144 if ( query.lastError().isValid() ) { 0145 qCritical() << "Problems occurred when executing the query" << query.executedQuery(); 0146 qCritical() << "SQL error: " << query.lastError(); 0147 } 0148 } 0149 0150 void MbTileWriter::setMetaData(const QString &name, const QString &value) 0151 { 0152 QSqlQuery query; 0153 query.prepare("INSERT INTO metadata (name, value) VALUES (?, ?)"); 0154 query.addBindValue(name); 0155 query.addBindValue(value); 0156 execQuery(query); 0157 } 0158 0159 }