Skip to content

Commit afd3525

Browse files
committed
Add test for terrain theme + do not use project singleton
1 parent 61cb715 commit afd3525

File tree

7 files changed

+110
-2
lines changed

7 files changed

+110
-2
lines changed

src/3d/qgs3dmapsettings.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
4949
, mSkyboxEnabled( other.mSkyboxEnabled )
5050
, mSkyboxFileBase( other.mSkyboxFileBase )
5151
, mSkyboxFileExtension( other.mSkyboxFileExtension )
52+
, mTransformContext( other.mTransformContext )
53+
, mPathResolver( other.mPathResolver )
54+
, mMapThemes( other.mMapThemes )
5255
{
5356
Q_FOREACH ( QgsAbstract3DRenderer *renderer, other.mRenderers )
5457
{

src/3d/qgs3dmapsettings.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,21 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
126126
*/
127127
void setPathResolver( const QgsPathResolver &resolver ) { mPathResolver = resolver; }
128128

129+
/**
130+
* Returns pointer to the collection of map themes. Normally this would be QgsProject::mapThemeCollection()
131+
* of the currently used project. Without a valid map theme collection object it is not possible
132+
* to resolve map themes from their names.
133+
* \since QGIS 3.6
134+
*/
135+
QgsMapThemeCollection *mapThemeCollection() const { return mMapThemes; }
136+
137+
/**
138+
* Sets pointer to the collection of map themes.
139+
* \see mapThemeCollection()
140+
* \since QGIS 3.6
141+
*/
142+
void setMapThemeCollection( QgsMapThemeCollection *mapThemes ) { mMapThemes = mapThemes; }
143+
129144
//! Sets background color of the 3D map view
130145
void setBackgroundColor( const QColor &color );
131146
//! Returns background color of the 3D map view
@@ -248,6 +263,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
248263
/**
249264
* Returns name of the map theme (from the active project) that will be used for terrain's texture.
250265
* Empty map theme name means that the map theme is not overridden and the current map theme will be used.
266+
* \note Support for map themes only works if mapThemeCollection() is a valid object (otherwise it is not possible to resolve map themes from names)
251267
* \since QGIS 3.6
252268
*/
253269
QString terrainMapTheme() const { return mTerrainMapTheme; }
@@ -387,6 +403,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
387403
//! Coordinate transform context
388404
QgsCoordinateTransformContext mTransformContext;
389405
QgsPathResolver mPathResolver;
406+
QgsMapThemeCollection *mMapThemes = nullptr; //!< Pointer to map themes (e.g. from the current project) to resolve map theme content from the name
390407
};
391408

392409

src/3d/qgslayoutitem3dmap.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,13 @@ bool QgsLayoutItem3DMap::readPropertiesFromElement( const QDomElement &element,
217217
mSettings.reset( new Qgs3DMapSettings );
218218
mSettings->readXml( elemSettings, context );
219219
if ( mLayout->project() )
220+
{
220221
mSettings->resolveReferences( *mLayout->project() );
222+
223+
mSettings->setTransformContext( mLayout->project()->transformContext() );
224+
mSettings->setPathResolver( mLayout->project()->pathResolver() );
225+
mSettings->setMapThemeCollection( mLayout->project()->mapThemeCollection() );
226+
}
221227
}
222228

223229
QDomElement elemCameraPose = element.firstChildElement( QStringLiteral( "camera-pose" ) );

src/3d/terrain/qgsterraintexturegenerator_p.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ QgsMapSettings QgsTerrainTextureGenerator::baseMapSettings()
136136
mapSettings.setTransformContext( mMap.transformContext() );
137137
mapSettings.setPathResolver( mMap.pathResolver() );
138138

139-
QgsMapThemeCollection *mapThemes = QgsProject::instance()->mapThemeCollection();
139+
QgsMapThemeCollection *mapThemes = mMap.mapThemeCollection();
140140
QString mapThemeName = mMap.terrainMapTheme();
141-
if ( mapThemeName.isEmpty() || !mapThemes->hasMapTheme( mapThemeName ) )
141+
if ( mapThemeName.isEmpty() || !mapThemes || !mapThemes->hasMapTheme( mapThemeName ) )
142142
{
143143
mapSettings.setLayers( mMap.layers() );
144144
}

src/app/qgisapp.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11128,8 +11128,10 @@ void QgisApp::new3DMapCanvas()
1112811128
map->setSelectionColor( mMapCanvas->selectionColor() );
1112911129
map->setBackgroundColor( mMapCanvas->canvasColor() );
1113011130
map->setLayers( mMapCanvas->layers() );
11131+
1113111132
map->setTransformContext( QgsProject::instance()->transformContext() );
1113211133
map->setPathResolver( QgsProject::instance()->pathResolver() );
11134+
map->setMapThemeCollection( QgsProject::instance()->mapThemeCollection() );
1113311135
connect( QgsProject::instance(), &QgsProject::transformContextChanged, map, [map]
1113411136
{
1113511137
map->setTransformContext( QgsProject::instance()->transformContext() );
@@ -13544,6 +13546,14 @@ void QgisApp::readProject( const QDomDocument &doc )
1354413546
map->readXml( elem3D, readWriteContext );
1354513547
map->resolveReferences( *QgsProject::instance() );
1354613548

13549+
map->setTransformContext( QgsProject::instance()->transformContext() );
13550+
map->setPathResolver( QgsProject::instance()->pathResolver() );
13551+
map->setMapThemeCollection( QgsProject::instance()->mapThemeCollection() );
13552+
connect( QgsProject::instance(), &QgsProject::transformContextChanged, map, [map]
13553+
{
13554+
map->setTransformContext( QgsProject::instance()->transformContext() );
13555+
} );
13556+
1354713557
// these things are not saved in project
1354813558
map->setSelectionColor( mMapCanvas->selectionColor() );
1354913559
map->setBackgroundColor( mMapCanvas->canvasColor() );

tests/src/3d/testqgs3drendering.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
#include "qgstest.h"
1717
#include "qgsrenderchecker.h"
1818

19+
#include "qgsmaplayerstylemanager.h"
20+
#include "qgsmapthemecollection.h"
1921
#include "qgsproject.h"
2022
#include "qgsrasterlayer.h"
23+
#include "qgsrastershader.h"
24+
#include "qgssinglebandpseudocolorrenderer.h"
2125
#include "qgsvectorlayer.h"
2226

2327
#include "qgs3dmapscene.h"
@@ -43,6 +47,7 @@ class TestQgs3DRendering : public QObject
4347
void testFlatTerrain();
4448
void testDemTerrain();
4549
void testExtrudedPolygons();
50+
void testMapTheme();
4651

4752
private:
4853
bool renderCheck( const QString &testName, QImage &image, int mismatchCount = 0 );
@@ -88,6 +93,39 @@ void TestQgs3DRendering::initTestCase()
8893
mLayerBuildings->setRenderer3D( renderer3d );
8994

9095
mProject->setCrs( mLayerDtm->crs() );
96+
97+
//
98+
// prepare styles for DTM layer
99+
//
100+
101+
mLayerDtm->styleManager()->addStyleFromLayer( "grayscale" );
102+
103+
double vMin = 44, vMax = 198;
104+
QColor cMin = Qt::red, cMax = Qt::yellow;
105+
106+
// change renderer for the new style
107+
std::unique_ptr<QgsColorRampShader> colorRampShader( new QgsColorRampShader( vMin, vMax ) );
108+
colorRampShader->setColorRampItemList( QList<QgsColorRampShader::ColorRampItem>()
109+
<< QgsColorRampShader::ColorRampItem( vMin, cMin )
110+
<< QgsColorRampShader::ColorRampItem( vMax, cMax ) );
111+
std::unique_ptr<QgsRasterShader> shader( new QgsRasterShader( vMin, vMax ) );
112+
shader->setRasterShaderFunction( colorRampShader.release() );
113+
QgsSingleBandPseudoColorRenderer *r = new QgsSingleBandPseudoColorRenderer( mLayerDtm->renderer()->input(), 1, shader.release() );
114+
mLayerDtm->setRenderer( r );
115+
mLayerDtm->styleManager()->addStyleFromLayer( "my_style" );
116+
117+
mLayerDtm->styleManager()->setCurrentStyle( "grayscale" );
118+
119+
//
120+
// add map theme
121+
//
122+
123+
QgsMapThemeCollection::MapThemeLayerRecord layerRecord( mLayerDtm );
124+
layerRecord.usingCurrentStyle = true;
125+
layerRecord.currentStyle = "my_style";
126+
QgsMapThemeCollection::MapThemeRecord record;
127+
record.addLayerRecord( layerRecord );
128+
mProject->mapThemeCollection()->insert( "theme_dtm", record );
91129
}
92130

93131
//runs after all tests
@@ -204,6 +242,40 @@ void TestQgs3DRendering::testExtrudedPolygons()
204242
QVERIFY( renderCheck( "polygon3d_extrusion", img, 40 ) );
205243
}
206244

245+
void TestQgs3DRendering::testMapTheme()
246+
{
247+
QgsRectangle fullExtent = mLayerDtm->extent();
248+
249+
Qgs3DMapSettings *map = new Qgs3DMapSettings;
250+
map->setCrs( mProject->crs() );
251+
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
252+
map->setLayers( QList<QgsMapLayer *>() << mLayerRgb );
253+
254+
// set theme - this should override what we set in setLayers()
255+
map->setMapThemeCollection( mProject->mapThemeCollection() );
256+
map->setTerrainMapTheme( "theme_dtm" );
257+
258+
QgsFlatTerrainGenerator *flatTerrain = new QgsFlatTerrainGenerator;
259+
flatTerrain->setCrs( map->crs() );
260+
flatTerrain->setExtent( fullExtent );
261+
map->setTerrainGenerator( flatTerrain );
262+
263+
QgsOffscreen3DEngine engine;
264+
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
265+
engine.setRootEntity( scene );
266+
267+
// look from the top
268+
scene->cameraController()->setLookingAtPoint( QgsVector3D( 0, 0, 0 ), 2500, 0, 0 );
269+
270+
// When running the test on Travis, it would initially return empty rendered image.
271+
// Capturing the initial image and throwing it away fixes that. Hopefully we will
272+
// find a better fix in the future.
273+
Qgs3DUtils::captureSceneImage( engine, scene );
274+
275+
QImage img = Qgs3DUtils::captureSceneImage( engine, scene );
276+
QVERIFY( renderCheck( "terrain_theme", img, 40 ) );
277+
}
278+
207279

208280
bool TestQgs3DRendering::renderCheck( const QString &testName, QImage &image, int mismatchCount )
209281
{
Loading

0 commit comments

Comments
 (0)