File indexing completed on 2024-10-06 12:15:02
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2011 Niko Sams <niko.sams@gmail.com> 0004 // 0005 0006 #include "tccore.h" 0007 #include <MarbleGlobal.h> 0008 #include <TileLoaderHelper.h> 0009 #include <QFile> 0010 #include <cmath> 0011 #include <QPainter> 0012 #include <QProcess> 0013 #include <QFileInfo> 0014 #include <QDir> 0015 #include <QCache> 0016 0017 using namespace Marble; 0018 0019 class TileCreatorSourceSrtm : public TileCreatorSource 0020 { 0021 public: 0022 TileCreatorSourceSrtm( const QString &sourceDir ) 0023 : m_sourceDir( sourceDir ) 0024 { 0025 } 0026 0027 QSize fullImageSize() const override 0028 { 0029 return QSize( 512*c_defaultTileSize*2, 512*c_defaultTileSize ); //512: 2**9 (9 zoom levels) 0030 } 0031 0032 QImage tile( int n, int m, int maxTileLevel ) override 0033 { 0034 Q_ASSERT( maxTileLevel == 9 ); 0035 0036 int nmax = TileLoaderHelper::levelToRow( defaultLevelZeroRows, maxTileLevel ); 0037 Q_ASSERT( nmax == 512 ); 0038 int mmax = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, maxTileLevel ); 0039 0040 qreal startLat = ( ( ( (qreal)n * 180 ) / nmax ) - 90 ) * -1; 0041 qreal startLng = ( ( (qreal)m * 360 ) / mmax ) - 180; 0042 0043 int startLngPxResized = c_defaultTileSize * m; 0044 int startLatPxResized = c_defaultTileSize * n; 0045 0046 0047 if (hgtFileName(std::floor(startLng), std::floor(startLat)).isNull() 0048 && hgtFileName(std::floor(startLng)+1, std::floor(startLat)).isNull() 0049 && hgtFileName(std::floor(startLng), std::floor(startLat)-1).isNull() 0050 && hgtFileName(std::floor(startLng)+1, std::floor(startLat)-1).isNull() 0051 ) { 0052 QImage ret( c_defaultTileSize, c_defaultTileSize, QImage::Format_ARGB32 ); 0053 QPainter painter( &ret ); 0054 painter.fillRect( 0, 0, c_defaultTileSize, c_defaultTileSize, QColor( Qt::black ) ); 0055 return ret; 0056 } 0057 0058 QImage image( 2400, 2400, QImage::Format_ARGB32 ); 0059 { 0060 QPainter painter( &image ); 0061 painter.fillRect( 0, 0, 2400, 2400, QColor( Qt::black ) ); 0062 QImage i = readHgt(std::floor(startLng), std::floor(startLat)); 0063 painter.drawImage( 0, 0, i ); 0064 painter.drawImage( 1200, 0, readHgt( std::floor(startLng)+1, std::floor(startLat) ) ); 0065 painter.drawImage( 0, 1200, readHgt( std::floor(startLng), std::floor(startLat)-1 ) ); 0066 painter.drawImage( 1200, 1200, readHgt( std::floor(startLng)+1, std::floor(startLat)-1 ) ); 0067 } 0068 0069 int imageSizeResized = 2400 * (512 * c_defaultTileSize) / (1200 * 180); 0070 0071 // Pick the current row and smooth scale it 0072 // to make it match the expected size 0073 image = image.scaled( QSize(imageSizeResized, imageSizeResized), 0074 Qt::IgnoreAspectRatio ); 0075 0076 0077 //startL??Px: position in px of what we are looking for 0078 int startLngPx = startLng * 1200; 0079 startLngPx = ( 180 * 1200 ) + startLngPx; 0080 //qDebug() << "startLngPx(/1200)" << (qreal)startLngPx / 1200; 0081 0082 int startLatPx = startLat * 1200; 0083 startLatPx = ( 90 * 1200 ) - startLatPx; 0084 //qDebug() << "startLatPx(/1200)" << (qreal)startLatPx / 1200; 0085 0086 0087 //imageL??Px: position in px of image 0088 int imageLngPx = std::floor(startLng); 0089 imageLngPx = 180 + imageLngPx; 0090 //qDebug() << "imageLngPx(/1200)" << imageLngPx << "*1200" << imageLngPx*1200; 0091 imageLngPx *= 1200; 0092 0093 int imageLatPx = std::floor(90 - startLat); 0094 //qDebug() << "imageLatPx(/1200)" << imageLatPx; 0095 imageLatPx *= 1200; 0096 0097 //qDebug() << "lng" << imageLngPx << startLngPx << "offset" << startLngPx - imageLngPx; 0098 //qDebug() << "lat" << imageLatPx << startLatPx << "offset" << startLatPx - imageLatPx; 0099 Q_ASSERT(1200*2 - (startLngPx - imageLngPx) >= 675); 0100 Q_ASSERT(1200*2 - (startLatPx - imageLatPx) >= 675); 0101 Q_ASSERT(startLngPx - imageLngPx >= 0); 0102 Q_ASSERT(startLatPx - imageLatPx >= 0); 0103 0104 int imageLngPxResized = imageLngPx * 1.6; //(512 * c_defaultTileSize) / (1200 * 180); 0105 int imageLatPxResized = imageLatPx * 1.6; //(512 * c_defaultTileSize) / (1200 * 180); 0106 //qDebug() << "lng(m)" << startLngPxResized << imageLngPxResized << "diff" << startLngPxResized - imageLngPxResized; 0107 //qDebug() << "lat(n)" << startLatPxResized << imageLngPxResized << "diff" << startLatPxResized - imageLatPxResized; 0108 Q_ASSERT(startLngPxResized - imageLngPxResized < imageSizeResized); 0109 Q_ASSERT(startLatPxResized - imageLatPxResized < imageSizeResized); 0110 Q_ASSERT(startLngPxResized - imageLngPxResized >= 0); 0111 Q_ASSERT(startLatPxResized - imageLatPxResized >= 0); 0112 0113 QImage croppedImage = image.copy(startLngPx - imageLngPx, startLatPx - imageLatPx, 675, 675); 0114 QImage ret = image.copy(startLngPxResized - imageLngPxResized, startLatPxResized - imageLatPxResized, c_defaultTileSize, c_defaultTileSize); 0115 //qDebug() << image.size() << ret.size(); 0116 return ret; 0117 } 0118 0119 private: 0120 QString hgtFileName( int lng, int lat ) const 0121 { 0122 QChar EW(QLatin1Char(lng >= 0 ? 'E' : 'W')); 0123 QChar NS(QLatin1Char(lat >= 0 ? 'N' : 'S')); 0124 0125 QStringList dirs; 0126 dirs << "Africa" << "Australia" << "Eurasia" << "Silands" << "North_America" << "South_America"; 0127 for( const QString &dir: dirs) { 0128 QString fileName = m_sourceDir + QLatin1Char('/') + dir + QLatin1Char('/'); 0129 if ( lat < 0 ) lat *= -1; 0130 fileName += QString( "%1%2%3%4.hgt" ).arg( NS ).arg( lat<0 ? lat*-1 : lat, 2, 10, QLatin1Char('0') ) 0131 .arg( EW ).arg( lng<0 ? lng*-1 : lng, 3, 10, QLatin1Char('0' ) ); 0132 //qDebug() << fileName; 0133 0134 if (!QFile::exists(fileName) && QFile::exists(fileName + QLatin1String(".zip"))) { 0135 qDebug() << "zip found, unzipping"; 0136 QProcess p; 0137 p.execute("unzip", QStringList() << fileName + QLatin1String(".zip")); 0138 p.waitForFinished(); 0139 QFile(QDir::currentPath() + QLatin1Char('/') + QFileInfo(fileName).fileName()).rename(fileName); 0140 } 0141 if ( QFile::exists( fileName ) ) { 0142 return fileName; 0143 } 0144 } 0145 0146 return QString(); 0147 } 0148 0149 QImage readHgt( int lng, int lat ) 0150 { 0151 static QCache<QPair<int, int>, QImage > cache( 10 ); 0152 if ( cache.contains( qMakePair( lng, lat ) ) ) { 0153 return *cache[ qMakePair( lng, lat ) ]; 0154 } 0155 QString fileName = hgtFileName( lng, lat ); 0156 if ( fileName.isNull() ) { 0157 //qDebug() << lng << lat << "hgt file does not exist, returning null image"; 0158 return QImage(); 0159 } else { 0160 //qDebug() << lng << lat << "reading hgt file" << fileName; 0161 } 0162 0163 QFile file( fileName ); 0164 0165 file.open( QIODevice::ReadOnly ); 0166 int iLat = 0; 0167 int iLng = 0; 0168 0169 //hgt file is 1201px large, but the last px is overlapping 0170 QImage image( 1200, 1200, QImage::Format_ARGB32 ); 0171 while(true) { 0172 QByteArray data = file.read( 2 ); 0173 0174 if ( iLng < 1200 ) { 0175 unsigned short height = *(unsigned short*)data.data(); 0176 height = ( height << 8 | height >> 8 ); 0177 unsigned int pixel; 0178 pixel = height; 0179 pixel += 0xFF000000; //fully opaque 0180 image.setPixel( iLng, iLat, pixel ); 0181 } 0182 0183 if ( iLat >= 1199 && iLng >= 1199 ) break; 0184 0185 iLng++; 0186 if ( iLng > 1200 ) { //here not 1199 but one more, because of overlapping px at the end of the line 0187 iLng = 0; 0188 iLat++; 0189 } 0190 } 0191 file.close(); 0192 0193 cache.insert( qMakePair( lng, lat ), new QImage( image ) ); 0194 0195 return image; 0196 } 0197 0198 QString m_sourceDir; 0199 }; 0200 0201 TCCoreApplication::TCCoreApplication( int argc, char ** argv ) : QCoreApplication( argc, argv ) 0202 { 0203 0204 if( !(argc < 2) ) 0205 { 0206 TileCreatorSource *source = new TileCreatorSourceSrtm( argv[1] ); 0207 m_tilecreator = new TileCreator( source, "false", argv[2] ); 0208 m_tilecreator->setTileFormat( "png" ); 0209 m_tilecreator->setTileQuality( 25 ); 0210 m_tilecreator->setResume( true ); 0211 m_tilecreator->setVerifyExactResult( true ); 0212 connect( m_tilecreator, SIGNAL(finished()), this, SLOT(quit()) ); 0213 m_tilecreator->start(); 0214 } 0215 }