File indexing completed on 2024-07-07 03:46:50

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 }