File indexing completed on 2024-09-01 03:41:40
0001 #include "OsmTileClusterRenderer.h" 0002 0003 #include "ReadOnlyMapImage.h" 0004 0005 #include <QDebug> 0006 #include <QTime> 0007 0008 #include <cmath> 0009 0010 OsmTileClusterRenderer::OsmTileClusterRenderer( QObject * const parent ) 0011 : QObject( parent ), 0012 m_osmTileEdgeLengthPixel( 256 ), 0013 m_emptyPixel( qRgba( 0, 0, 0, 255 )), 0014 m_osmBaseDirectory(), 0015 m_osmTileLevel(), 0016 m_osmMapEdgeLengthPixel(), 0017 m_clusterEdgeLengthTiles(), 0018 m_mapSourceDefinitions(), 0019 m_mapSources(), 0020 m_mapSourceCount() 0021 { 0022 } 0023 0024 void OsmTileClusterRenderer::setClusterEdgeLengthTiles( int const clusterEdgeLengthTiles ) 0025 { 0026 m_clusterEdgeLengthTiles = clusterEdgeLengthTiles; 0027 } 0028 0029 void OsmTileClusterRenderer::setMapSources( QVector<ReadOnlyMapDefinition> const & mapSourceDefinitions ) 0030 { 0031 m_mapSourceDefinitions = mapSourceDefinitions; 0032 } 0033 0034 void OsmTileClusterRenderer::setOsmBaseDirectory( QDir const & osmBaseDirectory ) 0035 { 0036 m_osmBaseDirectory = osmBaseDirectory; 0037 } 0038 0039 void OsmTileClusterRenderer::setOsmTileLevel( int const level ) 0040 { 0041 m_osmTileLevel = level; 0042 int const osmMapEdgeLengthTiles = pow( 2, m_osmTileLevel ); 0043 m_osmMapEdgeLengthPixel = osmMapEdgeLengthTiles * m_osmTileEdgeLengthPixel; 0044 qDebug() << "osmTileLevel:" << m_osmTileLevel 0045 << "\nosmMapEdgeLengthTiles:" << osmMapEdgeLengthTiles 0046 << "\nosmMapEdgeLengthPixel:" << m_osmMapEdgeLengthPixel; 0047 } 0048 0049 QDir OsmTileClusterRenderer::checkAndCreateDirectory( int const tileX ) const 0050 { 0051 QDir const tileDirectory( m_osmBaseDirectory.path() + QString("/%1/%2").arg( m_osmTileLevel ).arg( tileX )); 0052 if ( !tileDirectory.exists() ) { 0053 bool const created = tileDirectory.mkpath( tileDirectory.path() ); 0054 if ( !created ) { 0055 // maybe it was created in the meantime by a different thread, then it should be there now 0056 if ( !tileDirectory.exists() ) 0057 qFatal("Unable to create directory '%s'.", tileDirectory.path().toStdString().c_str() ); 0058 } 0059 } 0060 return tileDirectory; 0061 } 0062 0063 void OsmTileClusterRenderer::initMapSources() 0064 { 0065 QVector<ReadOnlyMapDefinition>::const_iterator pos = m_mapSourceDefinitions.constBegin(); 0066 QVector<ReadOnlyMapDefinition>::const_iterator const end = m_mapSourceDefinitions.constEnd(); 0067 for (; pos != end; ++pos ) 0068 { 0069 ReadOnlyMapImage * const mapImage = (*pos).createReadOnlyMap(); 0070 if ( !mapImage ) 0071 qFatal("Invalid map source definition."); 0072 m_mapSources.push_back( mapImage ); 0073 } 0074 m_mapSourceCount = m_mapSources.count(); 0075 } 0076 0077 void OsmTileClusterRenderer::renderOsmTileCluster( int const clusterX, int const clusterY ) 0078 { 0079 qDebug() << objectName() << "rendering clusterX:" << clusterX << ", clusterY:" << clusterY; 0080 int tilesRenderedCount = 0; 0081 QTime t; 0082 t.start(); 0083 int const tileX1 = clusterX * m_clusterEdgeLengthTiles; 0084 int const tileX2 = tileX1 + m_clusterEdgeLengthTiles; 0085 int const tileY1 = clusterY * m_clusterEdgeLengthTiles; 0086 int const tileY2 = tileY1 + m_clusterEdgeLengthTiles; 0087 0088 for ( int tileX = tileX1; tileX < tileX2; ++tileX ) { 0089 QDir const tileDirectory = checkAndCreateDirectory( tileX ); 0090 for ( int tileY = tileY1; tileY < tileY2; ++tileY ) { 0091 QImage const osmTile = renderOsmTile( tileX, tileY ); 0092 0093 // hack 0094 if ( osmTile.isNull() ) 0095 continue; 0096 0097 QString const filename = tileDirectory.path() + QString( "/%1.png" ).arg( tileY ); 0098 bool const saved = osmTile.save( filename ); 0099 if ( saved ) 0100 ++tilesRenderedCount; 0101 else 0102 qFatal("Unable to save tile '%s'.", filename.toStdString().c_str() ); 0103 } 0104 } 0105 int const durationMs = t.elapsed(); 0106 qDebug() << objectName() << "clusterX:" <<clusterX << ", clusterY:" << clusterY 0107 << "rendered:" << tilesRenderedCount << "tiles in" << durationMs << "ms =>" 0108 << static_cast<double>( tilesRenderedCount ) * 1000.0 / static_cast<double>( durationMs ) << "tiles/s"; 0109 emit clusterRendered( this ); 0110 } 0111 0112 QImage OsmTileClusterRenderer::renderOsmTile( int const tileX, int const tileY ) 0113 { 0114 //qDebug() << objectName() << "renderOsmTile tileX:" << tileX << ", tileY:" << tileY; 0115 int const basePixelX = tileX * m_osmTileEdgeLengthPixel; 0116 int const basePixelY = tileY * m_osmTileEdgeLengthPixel; 0117 0118 QSize const tileSize( m_osmTileEdgeLengthPixel, m_osmTileEdgeLengthPixel ); 0119 QImage tile( tileSize, QImage::Format_ARGB32 ); 0120 bool tileEmpty = true; 0121 0122 for ( int y = 0; y < m_osmTileEdgeLengthPixel; ++y ) { 0123 int const pixelY = basePixelY + y; 0124 double const latRad = osmPixelYtoLatRad( pixelY ); 0125 0126 for ( int x = 0; x < m_osmTileEdgeLengthPixel; ++x ) { 0127 int const pixelX = basePixelX + x; 0128 double const lonRad = osmPixelXtoLonRad( pixelX ); 0129 0130 QRgb color = m_emptyPixel; 0131 for (int i = 0; i < m_mapSourceCount; ++i) 0132 { 0133 color = m_mapSources[i]->pixel( lonRad, latRad ); 0134 if ( color != m_emptyPixel ) { 0135 tileEmpty = false; 0136 break; 0137 } 0138 } 0139 0140 tile.setPixel( x, y, color ); 0141 } 0142 } 0143 return tileEmpty ? QImage() : tile; 0144 } 0145 0146 inline double OsmTileClusterRenderer::osmPixelXtoLonRad( int const pixelX ) const 0147 { 0148 double const pixelXd = static_cast<double>( pixelX ); 0149 double const osmMapEdgeLengthPixeld = static_cast<double>( m_osmMapEdgeLengthPixel ); 0150 return pixelXd * 2.0 * M_PI / osmMapEdgeLengthPixeld - M_PI; 0151 } 0152 0153 inline double OsmTileClusterRenderer::osmPixelYtoLatRad( int const pixelY ) const 0154 { 0155 double const pixelYd = static_cast<double>( pixelY ); 0156 double const osmMapEdgeLengthPixeld = static_cast<double>( m_osmMapEdgeLengthPixel ); 0157 return -atan( sinh(( pixelYd - 0.5 * osmMapEdgeLengthPixeld ) * 2.0 * M_PI / osmMapEdgeLengthPixeld )); 0158 } 0159 0160 #include "moc_OsmTileClusterRenderer.cpp"