File indexing completed on 2023-09-24 07:56:30
0001 #include "NwwMapImage.h" 0002 0003 #include "InterpolationMethod.h" 0004 0005 #include <QDebug> 0006 #include <cmath> 0007 0008 NwwMapImage::NwwMapImage( QDir const & baseDirectory, int const tileLevel ) 0009 : m_tileEdgeLengthPixel( 512 ), 0010 m_emptyPixel( qRgba( 0, 0, 0, 255 )), 0011 m_baseDirectory( baseDirectory ), 0012 m_tileLevel( tileLevel ), 0013 m_mapWidthTiles( 10 * pow( 2, m_tileLevel )), 0014 m_mapHeightTiles( 5 * pow( 2, m_tileLevel )), 0015 m_mapWidthPixel( m_mapWidthTiles * m_tileEdgeLengthPixel ), 0016 m_mapHeightPixel( m_mapHeightTiles * m_tileEdgeLengthPixel ), 0017 m_interpolationMethod(), 0018 m_tileCache( DefaultCacheSizeBytes ) 0019 { 0020 if ( !m_baseDirectory.exists() ) 0021 qFatal( "Base directory '%s' does not exist.", m_baseDirectory.path().toStdString().c_str() ); 0022 0023 qDebug() << "tileLevel:" << m_tileLevel 0024 << "\nmapWidthTiles:" << m_mapWidthTiles 0025 << "\nmapHeightTiles:" << m_mapHeightTiles 0026 << "\nmapWidthPixel:" << m_mapWidthPixel 0027 << "\nmapHeightPixel:" << m_mapHeightPixel; 0028 } 0029 0030 QRgb NwwMapImage::pixel( double const lonRad, double const latRad ) 0031 { 0032 double const x = lonRadToPixelX( lonRad ); 0033 double const y = latRadToPixelY( latRad ); 0034 return m_interpolationMethod->interpolate( x, y ); 0035 } 0036 0037 QRgb NwwMapImage::pixel( int const x, int const y ) 0038 { 0039 int const tileX = x / m_tileEdgeLengthPixel; 0040 int const tileY = y / m_tileEdgeLengthPixel; 0041 0042 // fast check if tile is missing 0043 int const tileKey = tileId( tileX, tileY ); 0044 if ( m_tileMissing.contains( tileKey )) 0045 return m_emptyPixel; 0046 0047 QPair<QImage, bool> potentialTile = tile( tileX, tileY ); 0048 if ( !potentialTile.second ) 0049 return m_emptyPixel; 0050 else 0051 return potentialTile.first.pixel( x % m_tileEdgeLengthPixel, 0052 m_tileEdgeLengthPixel - y % m_tileEdgeLengthPixel - 1 ); 0053 } 0054 0055 void NwwMapImage::setBaseDirectory( QDir const & baseDirectory ) 0056 { 0057 m_baseDirectory = baseDirectory; 0058 } 0059 0060 void NwwMapImage::setCacheSizeBytes(const int cacheSizeBytes) 0061 { 0062 m_tileCache.setMaxCost( cacheSizeBytes ); 0063 } 0064 0065 void NwwMapImage::setInterpolationMethod( InterpolationMethod * const method ) 0066 { 0067 m_interpolationMethod = method; 0068 m_interpolationMethod->setMapImage( this ); 0069 } 0070 0071 void NwwMapImage::setTileLevel( int const tileLevel ) 0072 { 0073 m_tileLevel = tileLevel; 0074 m_mapWidthTiles = 10 * pow( 2, m_tileLevel ); 0075 m_mapHeightTiles = 5 * pow( 2, m_tileLevel ); 0076 m_mapWidthPixel = m_mapWidthTiles * m_tileEdgeLengthPixel; 0077 m_mapHeightPixel = m_mapHeightTiles * m_tileEdgeLengthPixel; 0078 } 0079 0080 inline int NwwMapImage::tileId( int const tileX, int const tileY ) 0081 { 0082 return (tileX << 16) + tileY; 0083 } 0084 0085 QPair<QImage, bool> NwwMapImage::tile( int const tileX, int const tileY ) 0086 { 0087 int const tileKey = tileId( tileX, tileY ); 0088 0089 // first check cache 0090 QImage * const cachedTile = m_tileCache.object( tileKey ); 0091 if ( cachedTile ) 0092 return QPair<QImage, bool>( *cachedTile, true ); 0093 0094 QString const filename = QString("%1/%2/%2_%3.jpg") 0095 .arg( m_baseDirectory.path() ) 0096 .arg( tileY, 4, 10, QLatin1Char('0')) 0097 .arg( tileX, 4, 10, QLatin1Char('0')); 0098 QImage tile; 0099 bool const loaded = tile.load( filename ); 0100 if ( !loaded ) { 0101 m_tileMissing.insert( tileKey ); 0102 //qDebug() << "Tile" << filename << "not found"; 0103 } else { 0104 m_tileCache.insert( tileKey, new QImage( tile ), tile.byteCount() ); 0105 //qDebug() << "Tile" << filename << "loaded and inserted in cache"; 0106 } 0107 return QPair<QImage, bool>( tile, loaded ); 0108 } 0109 0110 inline double NwwMapImage::lonRadToPixelX( double const lonRad ) const 0111 { 0112 return static_cast<double>( m_mapWidthPixel ) / ( 2.0 * M_PI ) * lonRad 0113 + 0.5 * static_cast<double>( m_mapWidthPixel ); 0114 } 0115 0116 inline double NwwMapImage::latRadToPixelY( double const latRad ) const 0117 { 0118 return static_cast<double>( m_mapHeightPixel ) / M_PI * latRad 0119 + 0.5 * static_cast<double>( m_mapHeightPixel ); 0120 } 0121 0122 QRgb NwwMapImage::nearestNeighbor( double const x, double const y ) 0123 { 0124 int const xr = round( x ); 0125 int const yr = round( y ); 0126 return pixel( xr, yr ); 0127 } 0128 0129 QRgb NwwMapImage::bilinearInterpolation( double const x, double const y ) 0130 { 0131 int const x1 = x; 0132 int const x2 = x1 + 1; 0133 int const y1 = y; 0134 int const y2 = y1 + 1; 0135 0136 QRgb const lowerLeftPixel = pixel( x1, y1 ); 0137 QRgb const lowerRightPixel = pixel( x2, y1 ); 0138 QRgb const upperLeftPixel = pixel( x1, y2 ); 0139 QRgb const upperRightPixel = pixel( x2, y2 ); 0140 0141 // interpolate horizontically 0142 // 0143 // x2 - x x2 - x 0144 // ------- = ------ = x1 + 1 - x = 1 - fractionX 0145 // x2 - x1 1 0146 // 0147 // x - x1 x - x1 0148 // ------- = ------ = fractionX 0149 // x2 - x1 1 0150 0151 double const fractionX = x - x1; 0152 double const lowerMidRed = ( 1.0 - fractionX ) * qRed( lowerLeftPixel ) + fractionX * qRed( lowerRightPixel ); 0153 double const lowerMidGreen = ( 1.0 - fractionX ) * qGreen( lowerLeftPixel ) + fractionX * qGreen( lowerRightPixel ); 0154 double const lowerMidBlue = ( 1.0 - fractionX ) * qBlue( lowerLeftPixel ) + fractionX * qBlue( lowerRightPixel ); 0155 double const lowerMidAlpha = ( 1.0 - fractionX ) * qAlpha( lowerLeftPixel ) + fractionX * qAlpha( lowerRightPixel ); 0156 0157 double const upperMidRed = ( 1.0 - fractionX ) * qRed( upperLeftPixel ) + fractionX * qRed( upperRightPixel ); 0158 double const upperMidGreen = ( 1.0 - fractionX ) * qGreen( upperLeftPixel ) + fractionX * qGreen( upperRightPixel ); 0159 double const upperMidBlue = ( 1.0 - fractionX ) * qBlue( upperLeftPixel ) + fractionX * qBlue( upperRightPixel ); 0160 double const upperMidAlpha = ( 1.0 - fractionX ) * qAlpha( upperLeftPixel ) + fractionX * qAlpha( upperRightPixel ); 0161 0162 // interpolate vertically 0163 // 0164 // y2 - y y2 - y 0165 // ------- = ------ = y1 + 1 - y = 1 - fractionY 0166 // y2 - y1 1 0167 // 0168 // y - y1 y - y1 0169 // ------- = ------ = fractionY 0170 // y2 - y1 1 0171 0172 double const fractionY = y - y1; 0173 double const red = ( 1.0 - fractionY ) * lowerMidRed + fractionY * upperMidRed; 0174 double const green = ( 1.0 - fractionY ) * lowerMidGreen + fractionY * upperMidGreen; 0175 double const blue = ( 1.0 - fractionY ) * lowerMidBlue + fractionY * upperMidBlue; 0176 double const alpha = ( 1.0 - fractionY ) * lowerMidAlpha + fractionY * upperMidAlpha; 0177 0178 return qRgba( round( red ), round( green ), round( blue ), round( alpha )); 0179 }