File indexing completed on 2023-09-24 07:56:22
0001 // SPDX-FileCopyrightText: 2014 Friedrich W. H. Kossebau <kossebau@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.1-or-later 0003 0004 #include "thumbnailer.h" 0005 0006 // Marble 0007 #include <MarbleModel.h> 0008 #include <FileManager.h> 0009 #include <GeoDataDocument.h> 0010 #include <GeoPainter.h> 0011 #include <GeoDataLatLonAltBox.h> 0012 #include <ViewportParams.h> 0013 #include <RenderPlugin.h> 0014 #include <GeoDataTreeModel.h> 0015 0016 static const int timeoutTime = 5000; // in msec 0017 0018 namespace Marble { 0019 0020 GeoDataThumbnailer::GeoDataThumbnailer() 0021 : ThumbCreator() 0022 , m_marbleMap() 0023 { 0024 m_marbleMap.setMapThemeId(QStringLiteral("earth/openstreetmap/openstreetmap.dgml")); 0025 m_marbleMap.setProjection(Equirectangular); 0026 m_marbleMap.setMapQualityForViewContext( PrintQuality, Still ); 0027 m_marbleMap.setViewContext( Still ); 0028 for( RenderPlugin* plugin: m_marbleMap.renderPlugins() ) { 0029 plugin->setEnabled( false ); 0030 } 0031 0032 m_outtimer.setInterval(timeoutTime); 0033 m_outtimer.setSingleShot(true); 0034 connect(&m_outtimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); 0035 0036 MarbleModel *const model = m_marbleMap.model(); 0037 connect(model->treeModel(), &GeoDataTreeModel::added, this, &GeoDataThumbnailer::onGeoDataObjectAdded); 0038 connect(model->fileManager(), &FileManager::fileError, this, 0039 [this](const QString& path, const QString& error) { 0040 m_hadErrors = true; 0041 m_outtimer.stop(); 0042 m_eventLoop.quit(); 0043 }); 0044 } 0045 0046 0047 GeoDataThumbnailer::~GeoDataThumbnailer() 0048 { 0049 } 0050 0051 bool GeoDataThumbnailer::create(const QString &path, int width, int height, QImage &image) 0052 { 0053 m_marbleMap.setSize(width, height); 0054 0055 MarbleModel *const model = m_marbleMap.model(); 0056 0057 // load the document content 0058 m_loadingCompleted = false; 0059 m_hadErrors = false; 0060 0061 m_currentFilename = path; 0062 model->addGeoDataFile(path); 0063 0064 if ((!m_loadingCompleted) && (!m_hadErrors)) { 0065 // loading is done async, so wait here for a while 0066 // Using a QEventLoop here seems fine, thumbnailers are only used inside the 0067 // thumbnail protocol slave, it seems 0068 m_outtimer.start(); 0069 m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); 0070 } 0071 0072 if (m_loadingCompleted) { 0073 // TODO: limit to shown map, if full earth is used 0074 image = QImage(width, height, QImage::Format_ARGB32); 0075 image.fill(qRgba(0, 0, 0, 0)); 0076 0077 // Create a painter that will do the painting. 0078 GeoPainter geoPainter( &image, m_marbleMap.viewport(), 0079 m_marbleMap.mapQuality() ); 0080 0081 m_marbleMap.paint( geoPainter, QRect() ); // TODO: dirtyRect seems currently unused, make sure it is 0082 } 0083 0084 model->removeGeoData(path); 0085 m_currentFilename.clear(); 0086 0087 return m_loadingCompleted; 0088 } 0089 0090 static qreal radius(qreal zoom) 0091 { 0092 return pow(M_E, (zoom / 200.0)); 0093 } 0094 0095 void GeoDataThumbnailer::onGeoDataObjectAdded( GeoDataObject* object ) 0096 { 0097 const auto document = geodata_cast<GeoDataDocument>(object); 0098 0099 if (!document) { 0100 return; 0101 } 0102 0103 if (document->fileName() != m_currentFilename) { 0104 return; 0105 } 0106 0107 const GeoDataLatLonAltBox latLonAltBox = document->latLonAltBox(); 0108 const GeoDataCoordinates center = latLonAltBox.center(); 0109 0110 int newRadius = m_marbleMap.radius(); 0111 //prevent divide by zero 0112 if( latLonAltBox.height() && latLonAltBox.width() ) { 0113 const ViewportParams* viewparams = m_marbleMap.viewport(); 0114 //work out the needed zoom level 0115 const int horizontalRadius = ( 0.25 * M_PI ) * ( viewparams->height() / latLonAltBox.height() ); 0116 const int verticalRadius = ( 0.25 * M_PI ) * ( viewparams->width() / latLonAltBox.width() ); 0117 newRadius = qMin<int>( horizontalRadius, verticalRadius ); 0118 newRadius = qMax<int>(radius(m_marbleMap.minimumZoom()), qMin<int>(newRadius, radius(m_marbleMap.maximumZoom()))); 0119 } 0120 0121 m_marbleMap.centerOn( center.longitude(GeoDataCoordinates::Degree), center.latitude(GeoDataCoordinates::Degree) ); 0122 0123 m_marbleMap.setRadius( newRadius ); 0124 0125 m_loadingCompleted = true; 0126 m_outtimer.stop(); 0127 m_eventLoop.quit(); 0128 } 0129 0130 }