File indexing completed on 2024-04-21 14:51:52

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 }
0131 
0132 #include "moc_thumbnailer.cpp"