QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgsterraintexturegenerator_p.cpp
Go to the documentation of this file.
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
17#include "moc_qgsterraintexturegenerator_p.cpp"
18
21#include <qgsmapsettings.h>
23#include <qgsproject.h>
24
25#include "qgs3dmapsettings.h"
26
27#include "qgseventtracing.h"
28
30
31QgsTerrainTextureGenerator::QgsTerrainTextureGenerator( const Qgs3DMapSettings &map )
32 : mMap( map )
33 , mLastJobId( 0 )
34 , mTextureSize( QSize( mMap.mapTileResolution(), mMap.mapTileResolution() ) )
35{
36}
37
38int QgsTerrainTextureGenerator::render( const QgsRectangle &extent, QgsChunkNodeId tileId, const QString &debugText )
39{
40 QgsMapSettings mapSettings( baseMapSettings() );
41 mapSettings.setExtent( extent );
42 QSize size = QSize( mTextureSize );
43
44 QgsRectangle clippedExtent = extent;
45 if ( mMap.terrainGenerator()->type() == QgsTerrainGenerator::Flat )
46 {
47 // The flat terrain generator might have non-square tiles, clipped at the scene's extent.
48 // We need to produce non-square textures for those cases.
49 clippedExtent = extent.intersect( mMap.extent() );
50 mapSettings.setExtent( clippedExtent );
51 }
52 if ( !qgsDoubleNear( clippedExtent.width(), clippedExtent.height() ) )
53 {
54 if ( clippedExtent.height() > clippedExtent.width() )
55 size.setWidth( std::round( size.width() * clippedExtent.width() / clippedExtent.height() ) );
56 else if ( clippedExtent.height() < clippedExtent.width() )
57 size.setHeight( std::round( size.height() * clippedExtent.height() / clippedExtent.width() ) );
58 }
59 mapSettings.setOutputSize( size );
60
61 QgsEventTracing::addEvent( QgsEventTracing::AsyncBegin, QStringLiteral( "3D" ), QStringLiteral( "Texture" ), tileId.text() );
62
64 connect( job, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
65
66 JobData jobData;
67 jobData.jobId = ++mLastJobId;
68 jobData.tileId = tileId;
69 jobData.job = job;
70 jobData.extent = extent;
71 jobData.debugText = debugText;
72
73 mJobs.insert( job, jobData ); //store job data just before launching the job
74 job->start();
75
76 // QgsDebugMsgLevel( QStringLiteral("added job: %1 .... in queue: %2").arg( jobData.jobId ).arg( jobs.count() ), 2);
77 return jobData.jobId;
78}
79
80void QgsTerrainTextureGenerator::cancelJob( int jobId )
81{
82 for ( const JobData &jd : std::as_const( mJobs ) )
83 {
84 if ( jd.jobId == jobId )
85 {
86 // QgsDebugMsgLevel( QStringLiteral("canceling job %1").arg( jobId ), 2 );
87 jd.job->cancelWithoutBlocking();
88 disconnect( jd.job, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
89 jd.job->deleteLater();
90 mJobs.remove( jd.job );
91 return;
92 }
93 }
94 Q_ASSERT( false && "requested job ID does not exist!" );
95}
96
97void QgsTerrainTextureGenerator::waitForFinished()
98{
99 for ( auto it = mJobs.keyBegin(); it != mJobs.keyEnd(); it++ )
100 disconnect( *it, &QgsMapRendererJob::finished, this, &QgsTerrainTextureGenerator::onRenderingFinished );
101 QVector<QgsMapRendererSequentialJob *> toBeDeleted;
102 for ( auto it = mJobs.constBegin(); it != mJobs.constEnd(); it++ )
103 {
104 QgsMapRendererSequentialJob *mapJob = it.key();
105 mapJob->waitForFinished();
106 JobData jobData = it.value();
107 toBeDeleted.push_back( mapJob );
108
109 QImage img = mapJob->renderedImage();
110
111 if ( mMap.showTerrainTilesInfo() )
112 {
113 // extra tile information for debugging
114 QPainter p( &img );
115 p.setPen( Qt::red );
116 p.setBackgroundMode( Qt::OpaqueMode );
117 QFont font = p.font();
118 font.setPixelSize( std::max( 30, mMap.mapTileResolution() / 6 ) );
119 p.setFont( font );
120 p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
121 p.drawText( img.rect(), jobData.debugText, QTextOption( Qt::AlignCenter ) );
122 p.end();
123 }
124
125 // pass QImage further
126 emit tileReady( jobData.jobId, img );
127 }
128
129 for ( QgsMapRendererSequentialJob *mapJob : toBeDeleted )
130 {
131 mJobs.remove( mapJob );
132 mapJob->deleteLater();
133 }
134}
135
136void QgsTerrainTextureGenerator::onRenderingFinished()
137{
138 QgsMapRendererSequentialJob *mapJob = static_cast<QgsMapRendererSequentialJob *>( sender() );
139
140 Q_ASSERT( mJobs.contains( mapJob ) );
141 JobData jobData = mJobs.value( mapJob );
142
143 QImage img = mapJob->renderedImage();
144
145 if ( mMap.showTerrainTilesInfo() )
146 {
147 // extra tile information for debugging
148 QPainter p( &img );
149 p.setPen( Qt::red );
150 p.setBackgroundMode( Qt::OpaqueMode );
151 QFont font = p.font();
152 font.setPixelSize( std::max( 30, mMap.mapTileResolution() / 6 ) );
153 p.setFont( font );
154 p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
155 p.drawText( img.rect(), jobData.debugText, QTextOption( Qt::AlignCenter ) );
156 p.end();
157 }
158
159 mapJob->deleteLater();
160 mJobs.remove( mapJob );
161
162 // QgsDebugMsgLevel( QStringLiteral("finished job %1 ... in queue: %2").arg( jobData.jobId).arg( jobs.count() ), 2 );
163
164 QgsEventTracing::addEvent( QgsEventTracing::AsyncEnd, QStringLiteral( "3D" ), QStringLiteral( "Texture" ), jobData.tileId.text() );
165
166 // pass QImage further
167 emit tileReady( jobData.jobId, img );
168}
169
170QgsMapSettings QgsTerrainTextureGenerator::baseMapSettings()
171{
172 QgsMapSettings mapSettings;
173
174 mapSettings.setOutputSize( mTextureSize );
175 mapSettings.setDestinationCrs( mMap.crs() );
176 mapSettings.setBackgroundColor( mMap.backgroundColor() );
177 mapSettings.setFlag( Qgis::MapSettingsFlag::DrawLabeling, mMap.showLabels() );
179 mapSettings.setTransformContext( mMap.transformContext() );
180 mapSettings.setPathResolver( mMap.pathResolver() );
181 mapSettings.setRendererUsage( mMap.rendererUsage() );
182
183 QList<QgsMapLayer *> layers;
184 QgsMapThemeCollection *mapThemes = mMap.mapThemeCollection();
185 QString mapThemeName = mMap.terrainMapTheme();
186 if ( mapThemeName.isEmpty() || !mapThemes || !mapThemes->hasMapTheme( mapThemeName ) )
187 {
188 layers = mMap.layers();
189 }
190 else
191 {
192 layers = mapThemes->mapThemeVisibleLayers( mapThemeName );
193 mapSettings.setLayerStyleOverrides( mapThemes->mapThemeStyleOverrides( mapThemeName ) );
194 }
195 layers.erase( std::remove_if( layers.begin(),
196 layers.end(),
197 []( const QgsMapLayer * layer ) { return layer->renderer3D(); } ),
198 layers.end() );
199 mapSettings.setLayers( layers );
200
201 return mapSettings;
202}
203
@ DrawLabeling
Enable drawing of labels on top of the map.
@ Render3DMap
Render is for a 3D map.
Base class for all map layer types.
Definition qgsmaplayer.h:76
void finished()
emitted when asynchronous rendering is finished (or canceled).
void start()
Start the rendering job and immediately return.
Job implementation that renders everything sequentially in one thread.
QImage renderedImage() override
Gets a preview/resulting image.
void waitForFinished() override
Block until the job has finished.
The QgsMapSettings class contains configuration for rendering of the map.
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of layers to render in the map.
void setRendererUsage(Qgis::RendererUsage rendererUsage)
Sets the rendering usage.
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Sets the map of map layer style overrides (key: layer ID, value: style name) where a different style ...
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
void setPathResolver(const QgsPathResolver &resolver)
Sets the path resolver for conversion between relative and absolute paths during rendering operations...
void setOutputSize(QSize size)
Sets the size of the resulting map image, in pixels.
void setBackgroundColor(const QColor &color)
Sets the background color of the map.
void setFlag(Qgis::MapSettingsFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination crs (coordinate reference system) for the map render.
Container class that allows storage of map themes consisting of visible map layers and layer styles.
bool hasMapTheme(const QString &name) const
Returns whether a map theme with a matching name exists.
QList< QgsMapLayer * > mapThemeVisibleLayers(const QString &name) const
Returns the list of layers that are visible for the specified map theme.
QMap< QString, QString > mapThemeStyleOverrides(const QString &name)
Gets layer style overrides (for QgsMapSettings) of the visible layers for given map theme.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
@ Flat
The whole terrain is flat area.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5958