1 /***************************************************************************
2 qgsterraintexturegenerator_p.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgsterraintexturegenerator_p.h"
17
18 #include <qgsmaprenderercustompainterjob.h>
19 #include <qgsmaprenderersequentialjob.h>
20 #include <qgsmapsettings.h>
21 #include <qgsmapthemecollection.h>
22 #include <qgsproject.h>
23
24 #include "qgs3dmapsettings.h"
25
26 #include "qgseventtracing.h"
27
28 ///@cond PRIVATE
29
QgsTerrainTextureGenerator(const Qgs3DMapSettings & map)30 QgsTerrainTextureGenerator::QgsTerrainTextureGenerator( const Qgs3DMapSettings &map )
31 : mMap( map )
32 , mLastJobId( 0 )
33 , mTextureSize( QSize( mMap.mapTileResolution(), mMap.mapTileResolution() ) )
34 {
35 }
36
render(const QgsRectangle & extent,QgsChunkNodeId tileId,const QString & debugText)37 int QgsTerrainTextureGenerator::render( const QgsRectangle &extent, QgsChunkNodeId tileId, const QString &debugText )
38 {
39 QgsMapSettings mapSettings( baseMapSettings() );
40 mapSettings.setExtent( extent );
41
42 QgsEventTracing::addEvent( QgsEventTracing::AsyncBegin, QStringLiteral( "3D" ), QStringLiteral( "Texture" ), tileId.text() );
43
44 QgsMapRendererSequentialJob *job = new QgsMapRendererSequentialJob( mapSettings );
45 connect( job, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
46 job->start();
47
48 JobData jobData;
49 jobData.jobId = ++mLastJobId;
50 jobData.tileId = tileId;
51 jobData.job = job;
52 jobData.extent = extent;
53 jobData.debugText = debugText;
54
55 mJobs.insert( job, jobData );
56 //qDebug() << "added job: " << jobData.jobId << " .... in queue: " << jobs.count();
57 return jobData.jobId;
58 }
59
cancelJob(int jobId)60 void QgsTerrainTextureGenerator::cancelJob( int jobId )
61 {
62 Q_FOREACH ( const JobData &jd, mJobs )
63 {
64 if ( jd.jobId == jobId )
65 {
66 //qDebug() << "canceling job " << jobId;
67 jd.job->cancelWithoutBlocking();
68 disconnect( jd.job, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
69 jd.job->deleteLater();
70 mJobs.remove( jd.job );
71 return;
72 }
73 }
74 Q_ASSERT( false && "requested job ID does not exist!" );
75 }
76
waitForFinished()77 void QgsTerrainTextureGenerator::waitForFinished()
78 {
79 for ( QgsMapRendererSequentialJob *job : mJobs.keys() )
80 disconnect( job, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
81 QVector<QgsMapRendererSequentialJob *> toBeDeleted;
82 for ( QgsMapRendererSequentialJob *mapJob : mJobs.keys() )
83 {
84 mapJob->waitForFinished();
85 JobData jobData = mJobs.value( mapJob );
86 toBeDeleted.push_back( mapJob );
87
88 QImage img = mapJob->renderedImage();
89
90 if ( mMap.showTerrainTilesInfo() )
91 {
92 // extra tile information for debugging
93 QPainter p( &img );
94 p.setPen( Qt::white );
95 p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
96 p.drawText( img.rect(), jobData.debugText, QTextOption( Qt::AlignCenter ) );
97 p.end();
98 }
99
100 // pass QImage further
101 emit tileReady( jobData.jobId, img );
102 }
103
104 for ( QgsMapRendererSequentialJob *mapJob : toBeDeleted )
105 {
106 mJobs.remove( mapJob );
107 mapJob->deleteLater();
108 }
109 }
110
onRenderingFinished()111 void QgsTerrainTextureGenerator::onRenderingFinished()
112 {
113 QgsMapRendererSequentialJob *mapJob = static_cast<QgsMapRendererSequentialJob *>( sender() );
114
115 Q_ASSERT( mJobs.contains( mapJob ) );
116 JobData jobData = mJobs.value( mapJob );
117
118 QImage img = mapJob->renderedImage();
119
120 if ( mMap.showTerrainTilesInfo() )
121 {
122 // extra tile information for debugging
123 QPainter p( &img );
124 p.setPen( Qt::white );
125 p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
126 p.drawText( img.rect(), jobData.debugText, QTextOption( Qt::AlignCenter ) );
127 p.end();
128 }
129
130 mapJob->deleteLater();
131 mJobs.remove( mapJob );
132
133 //qDebug() << "finished job " << jobData.jobId << " ... in queue: " << jobs.count();
134
135 QgsEventTracing::addEvent( QgsEventTracing::AsyncEnd, QStringLiteral( "3D" ), QStringLiteral( "Texture" ), jobData.tileId.text() );
136
137 // pass QImage further
138 emit tileReady( jobData.jobId, img );
139 }
140
baseMapSettings()141 QgsMapSettings QgsTerrainTextureGenerator::baseMapSettings()
142 {
143 QgsMapSettings mapSettings;
144
145 mapSettings.setOutputSize( mTextureSize );
146 mapSettings.setDestinationCrs( mMap.crs() );
147 mapSettings.setBackgroundColor( mMap.backgroundColor() );
148 mapSettings.setFlag( QgsMapSettings::DrawLabeling, mMap.showLabels() );
149 mapSettings.setFlag( QgsMapSettings::Render3DMap );
150 mapSettings.setTransformContext( mMap.transformContext() );
151 mapSettings.setPathResolver( mMap.pathResolver() );
152
153 QgsMapThemeCollection *mapThemes = mMap.mapThemeCollection();
154 QString mapThemeName = mMap.terrainMapTheme();
155 if ( mapThemeName.isEmpty() || !mapThemes || !mapThemes->hasMapTheme( mapThemeName ) )
156 {
157 mapSettings.setLayers( mMap.terrainLayers() );
158 }
159 else
160 {
161 mapSettings.setLayers( mapThemes->mapThemeVisibleLayers( mapThemeName ) );
162 mapSettings.setLayerStyleOverrides( mapThemes->mapThemeStyleOverrides( mapThemeName ) );
163 }
164
165 return mapSettings;
166 }
167
168 /// @endcond
169