QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgs3dmapsettings.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgs3dmapsettings.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 "qgs3dmapsettings.h"
17 
18 #include "qgs3dutils.h"
20 #include "qgsdemterraingenerator.h"
21 //#include "quantizedmeshterraingenerator.h"
23 
24 #include <QDomDocument>
25 #include <QDomElement>
26 
27 #include "qgssymbollayerutils.h"
28 #include "qgsrasterlayer.h"
29 
31  : QObject( nullptr )
32  , mOrigin( other.mOrigin )
33  , mCrs( other.mCrs )
34  , mBackgroundColor( other.mBackgroundColor )
35  , mTerrainVerticalScale( other.mTerrainVerticalScale )
36  , mTerrainGenerator( other.mTerrainGenerator ? other.mTerrainGenerator->clone() : nullptr )
37  , mMapTileResolution( other.mMapTileResolution )
38  , mMaxTerrainScreenError( other.mMaxTerrainScreenError )
39  , mMaxTerrainGroundError( other.mMaxTerrainGroundError )
40  , mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes )
41  , mShowTerrainTileInfo( other.mShowTerrainTileInfo )
42  , mShowCameraViewCenter( other.mShowCameraViewCenter )
43  , mLayers( other.mLayers )
44  , mSkyboxEnabled( other.mSkyboxEnabled )
45  , mSkyboxFileBase( other.mSkyboxFileBase )
46  , mSkyboxFileExtension( other.mSkyboxFileExtension )
47 {
48  Q_FOREACH ( QgsAbstract3DRenderer *renderer, other.mRenderers )
49  {
50  mRenderers << renderer->clone();
51  }
52 }
53 
55 {
56  qDeleteAll( mRenderers );
57 }
58 
59 void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
60 {
61  QDomElement elemOrigin = elem.firstChildElement( QStringLiteral( "origin" ) );
62  mOrigin = QgsVector3D(
63  elemOrigin.attribute( QStringLiteral( "x" ) ).toDouble(),
64  elemOrigin.attribute( QStringLiteral( "y" ) ).toDouble(),
65  elemOrigin.attribute( QStringLiteral( "z" ) ).toDouble() );
66 
67  QDomElement elemColor = elem.firstChildElement( QStringLiteral( "color" ) );
68  if ( !elemColor.isNull() )
69  {
70  mBackgroundColor = QgsSymbolLayerUtils::decodeColor( elemColor.attribute( QStringLiteral( "background" ) ) );
71  mSelectionColor = QgsSymbolLayerUtils::decodeColor( elemColor.attribute( QStringLiteral( "selection" ) ) );
72  }
73 
74  QDomElement elemCrs = elem.firstChildElement( QStringLiteral( "crs" ) );
75  mCrs.readXml( elemCrs );
76 
77  QDomElement elemTerrain = elem.firstChildElement( QStringLiteral( "terrain" ) );
78  mTerrainVerticalScale = elemTerrain.attribute( QStringLiteral( "exaggeration" ), QStringLiteral( "1" ) ).toFloat();
79  mMapTileResolution = elemTerrain.attribute( QStringLiteral( "texture-size" ), QStringLiteral( "512" ) ).toInt();
80  mMaxTerrainScreenError = elemTerrain.attribute( QStringLiteral( "max-terrain-error" ), QStringLiteral( "3" ) ).toFloat();
81  mMaxTerrainGroundError = elemTerrain.attribute( QStringLiteral( "max-ground-error" ), QStringLiteral( "1" ) ).toFloat();
82  mShowLabels = elemTerrain.attribute( QStringLiteral( "show-labels" ), QStringLiteral( "0" ) ).toInt();
83  QDomElement elemMapLayers = elemTerrain.firstChildElement( QStringLiteral( "layers" ) );
84  QDomElement elemMapLayer = elemMapLayers.firstChildElement( QStringLiteral( "layer" ) );
85  QList<QgsMapLayerRef> mapLayers;
86  while ( !elemMapLayer.isNull() )
87  {
88  mapLayers << QgsMapLayerRef( elemMapLayer.attribute( QStringLiteral( "id" ) ) );
89  elemMapLayer = elemMapLayer.nextSiblingElement( QStringLiteral( "layer" ) );
90  }
91  mLayers = mapLayers; // needs to resolve refs afterwards
92  QDomElement elemTerrainGenerator = elemTerrain.firstChildElement( QStringLiteral( "generator" ) );
93  QString terrainGenType = elemTerrainGenerator.attribute( QStringLiteral( "type" ) );
94  if ( terrainGenType == QLatin1String( "dem" ) )
95  {
96  QgsDemTerrainGenerator *demTerrainGenerator = new QgsDemTerrainGenerator;
97  demTerrainGenerator->setCrs( mCrs, mTransformContext );
98  mTerrainGenerator.reset( demTerrainGenerator );
99  }
100  else if ( terrainGenType == QLatin1String( "quantized-mesh" ) )
101  {
102 #if 0
104 #endif
105  Q_ASSERT( false ); // currently disabled
106  }
107  else // "flat"
108  {
110  flatGen->setCrs( mCrs );
111  mTerrainGenerator.reset( flatGen );
112  }
113  mTerrainGenerator->readXml( elemTerrainGenerator );
114 
115  qDeleteAll( mRenderers );
116  mRenderers.clear();
117 
118  QDomElement elemRenderers = elem.firstChildElement( QStringLiteral( "renderers" ) );
119  QDomElement elemRenderer = elemRenderers.firstChildElement( QStringLiteral( "renderer" ) );
120  while ( !elemRenderer.isNull() )
121  {
122  QgsAbstract3DRenderer *renderer = nullptr;
123  QString type = elemRenderer.attribute( QStringLiteral( "type" ) );
124  if ( type == QLatin1String( "vector" ) )
125  {
126  renderer = new QgsVectorLayer3DRenderer;
127  }
128 
129  if ( renderer )
130  {
131  renderer->readXml( elemRenderer, context );
132  mRenderers.append( renderer );
133  }
134  elemRenderer = elemRenderer.nextSiblingElement( QStringLiteral( "renderer" ) );
135  }
136 
137  QDomElement elemSkybox = elem.firstChildElement( QStringLiteral( "skybox" ) );
138  mSkyboxEnabled = elemSkybox.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
139  mSkyboxFileBase = elemSkybox.attribute( QStringLiteral( "file-base" ) );
140  mSkyboxFileExtension = elemSkybox.attribute( QStringLiteral( "file-ext" ) );
141 
142  QDomElement elemDebug = elem.firstChildElement( QStringLiteral( "debug" ) );
143  mShowTerrainBoundingBoxes = elemDebug.attribute( QStringLiteral( "bounding-boxes" ), QStringLiteral( "0" ) ).toInt();
144  mShowTerrainTileInfo = elemDebug.attribute( QStringLiteral( "terrain-tile-info" ), QStringLiteral( "0" ) ).toInt();
145  mShowCameraViewCenter = elemDebug.attribute( QStringLiteral( "camera-view-center" ), QStringLiteral( "0" ) ).toInt();
146 }
147 
148 QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
149 {
150  QDomElement elem = doc.createElement( QStringLiteral( "qgis3d" ) );
151 
152  QDomElement elemOrigin = doc.createElement( QStringLiteral( "origin" ) );
153  elemOrigin.setAttribute( QStringLiteral( "x" ), QString::number( mOrigin.x() ) );
154  elemOrigin.setAttribute( QStringLiteral( "y" ), QString::number( mOrigin.y() ) );
155  elemOrigin.setAttribute( QStringLiteral( "z" ), QString::number( mOrigin.z() ) );
156  elem.appendChild( elemOrigin );
157 
158  QDomElement elemColor = doc.createElement( QStringLiteral( "color" ) );
159  elemColor.setAttribute( QStringLiteral( "background" ), QgsSymbolLayerUtils::encodeColor( mBackgroundColor ) );
160  elemColor.setAttribute( QStringLiteral( "selection" ), QgsSymbolLayerUtils::encodeColor( mSelectionColor ) );
161  elem.appendChild( elemColor );
162 
163  QDomElement elemCrs = doc.createElement( QStringLiteral( "crs" ) );
164  mCrs.writeXml( elemCrs, doc );
165  elem.appendChild( elemCrs );
166 
167  QDomElement elemTerrain = doc.createElement( QStringLiteral( "terrain" ) );
168  elemTerrain.setAttribute( QStringLiteral( "exaggeration" ), QString::number( mTerrainVerticalScale ) );
169  elemTerrain.setAttribute( QStringLiteral( "texture-size" ), mMapTileResolution );
170  elemTerrain.setAttribute( QStringLiteral( "max-terrain-error" ), QString::number( mMaxTerrainScreenError ) );
171  elemTerrain.setAttribute( QStringLiteral( "max-ground-error" ), QString::number( mMaxTerrainGroundError ) );
172  elemTerrain.setAttribute( QStringLiteral( "show-labels" ), mShowLabels ? 1 : 0 );
173  QDomElement elemMapLayers = doc.createElement( QStringLiteral( "layers" ) );
174  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
175  {
176  QDomElement elemMapLayer = doc.createElement( QStringLiteral( "layer" ) );
177  elemMapLayer.setAttribute( QStringLiteral( "id" ), layerRef.layerId );
178  elemMapLayers.appendChild( elemMapLayer );
179  }
180  elemTerrain.appendChild( elemMapLayers );
181  QDomElement elemTerrainGenerator = doc.createElement( QStringLiteral( "generator" ) );
182  elemTerrainGenerator.setAttribute( QStringLiteral( "type" ), QgsTerrainGenerator::typeToString( mTerrainGenerator->type() ) );
183  mTerrainGenerator->writeXml( elemTerrainGenerator );
184  elemTerrain.appendChild( elemTerrainGenerator );
185  elem.appendChild( elemTerrain );
186 
187  QDomElement elemRenderers = doc.createElement( QStringLiteral( "renderers" ) );
188  Q_FOREACH ( const QgsAbstract3DRenderer *renderer, mRenderers )
189  {
190  QDomElement elemRenderer = doc.createElement( QStringLiteral( "renderer" ) );
191  elemRenderer.setAttribute( QStringLiteral( "type" ), renderer->type() );
192  renderer->writeXml( elemRenderer, context );
193  elemRenderers.appendChild( elemRenderer );
194  }
195  elem.appendChild( elemRenderers );
196 
197  QDomElement elemSkybox = doc.createElement( QStringLiteral( "skybox" ) );
198  elemSkybox.setAttribute( QStringLiteral( "enabled" ), mSkyboxEnabled ? 1 : 0 );
199  // TODO: use context for relative paths, maybe explicitly list all files(?)
200  elemSkybox.setAttribute( QStringLiteral( "file-base" ), mSkyboxFileBase );
201  elemSkybox.setAttribute( QStringLiteral( "file-ext" ), mSkyboxFileExtension );
202  elem.appendChild( elemSkybox );
203 
204  QDomElement elemDebug = doc.createElement( QStringLiteral( "debug" ) );
205  elemDebug.setAttribute( QStringLiteral( "bounding-boxes" ), mShowTerrainBoundingBoxes ? 1 : 0 );
206  elemDebug.setAttribute( QStringLiteral( "terrain-tile-info" ), mShowTerrainTileInfo ? 1 : 0 );
207  elemDebug.setAttribute( QStringLiteral( "camera-view-center" ), mShowCameraViewCenter ? 1 : 0 );
208  elem.appendChild( elemDebug );
209 
210  return elem;
211 }
212 
214 {
215  for ( int i = 0; i < mLayers.count(); ++i )
216  {
217  QgsMapLayerRef &layerRef = mLayers[i];
218  layerRef.setLayer( project.mapLayer( layerRef.layerId ) );
219  }
220 
221  mTerrainGenerator->resolveReferences( project );
222 
223  for ( int i = 0; i < mRenderers.count(); ++i )
224  {
225  QgsAbstract3DRenderer *renderer = mRenderers[i];
226  renderer->resolveReferences( project );
227  }
228 }
229 
231 {
232  return Qgs3DUtils::mapToWorldCoordinates( mapCoords, mOrigin );
233 }
234 
236 {
237  return Qgs3DUtils::worldToMapCoordinates( worldCoords, mOrigin );
238 }
239 
241 {
242  mCrs = crs;
243 }
244 
246 {
247  return mTransformContext;
248 }
249 
251 {
252  mTransformContext = context;
253 }
254 
255 void Qgs3DMapSettings::setBackgroundColor( const QColor &color )
256 {
257  if ( color == mBackgroundColor )
258  return;
259 
260  mBackgroundColor = color;
261  emit backgroundColorChanged();
262 }
263 
265 {
266  return mBackgroundColor;
267 }
268 
269 void Qgs3DMapSettings::setSelectionColor( const QColor &color )
270 {
271  if ( color == mSelectionColor )
272  return;
273 
274  mSelectionColor = color;
275  emit selectionColorChanged();
276 }
277 
279 {
280  return mSelectionColor;
281 }
282 
284 {
285  if ( zScale == mTerrainVerticalScale )
286  return;
287 
288  mTerrainVerticalScale = zScale;
290 }
291 
293 {
294  return mTerrainVerticalScale;
295 }
296 
297 void Qgs3DMapSettings::setLayers( const QList<QgsMapLayer *> &layers )
298 {
299  QList<QgsMapLayerRef> lst;
300  lst.reserve( layers.count() );
301  Q_FOREACH ( QgsMapLayer *layer, layers )
302  {
303  lst.append( layer );
304  }
305 
306  if ( mLayers == lst )
307  return;
308 
309  mLayers = lst;
310  emit layersChanged();
311 }
312 
313 QList<QgsMapLayer *> Qgs3DMapSettings::layers() const
314 {
315  QList<QgsMapLayer *> lst;
316  lst.reserve( mLayers.count() );
317  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
318  {
319  if ( layerRef.layer )
320  lst.append( layerRef.layer );
321  }
322  return lst;
323 }
324 
326 {
327  if ( mMapTileResolution == res )
328  return;
329 
330  mMapTileResolution = res;
332 }
333 
335 {
336  return mMapTileResolution;
337 }
338 
340 {
341  if ( mMaxTerrainScreenError == error )
342  return;
343 
344  mMaxTerrainScreenError = error;
346 }
347 
349 {
350  return mMaxTerrainScreenError;
351 }
352 
354 {
355  if ( mMaxTerrainGroundError == error )
356  return;
357 
358  mMaxTerrainGroundError = error;
360 }
361 
363 {
364  return mMaxTerrainGroundError;
365 }
366 
368 {
369  mTerrainGenerator.reset( gen );
371 }
372 
373 void Qgs3DMapSettings::setRenderers( const QList<QgsAbstract3DRenderer *> &renderers )
374 {
375  mRenderers = renderers;
376 }
377 
379 {
380  if ( mShowTerrainBoundingBoxes == enabled )
381  return;
382 
383  mShowTerrainBoundingBoxes = enabled;
385 }
386 
388 {
389  if ( mShowTerrainTileInfo == enabled )
390  return;
391 
392  mShowTerrainTileInfo = enabled;
394 }
395 
397 {
398  if ( mShowCameraViewCenter == enabled )
399  return;
400 
401  mShowCameraViewCenter = enabled;
403 }
404 
406 {
407  if ( mShowLabels == enabled )
408  return;
409 
410  mShowLabels = enabled;
411  emit showLabelsChanged();
412 }
QList< QgsMapLayer * > layers() const
Returns the list of map layers to be rendered as a texture of the terrain.
The class is used as a container of context for various read/write operations on other objects...
3 Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double preci...
Definition: qgsvector3d.h:31
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets coordinate reference system used in the 3D scene.
3 Terrain generator that creates a simple square flat area.
Base class for all map layer types.
Definition: qgsmaplayer.h:63
void maxTerrainGroundErrorChanged()
Emitted when the maximum terrain ground error has changed.
void setShowCameraViewCenter(bool enabled)
Sets whether to show camera&#39;s view center as a sphere (for debugging)
QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords) const
Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x...
virtual void resolveReferences(const QgsProject &project)
Resolves references to other objects - second phase of loading - after readXml()
void setTerrainGenerator(QgsTerrainGenerator *gen)
Sets terrain generator.
_LayerRef< QgsMapLayer > QgsMapLayerRef
Base class for all renderers that may to participate in 3D view.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml()
void layersChanged()
Emitted when the list of map layers for terrain texture has changed.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
void setShowTerrainTilesInfo(bool enabled)
Sets whether to display extra tile info on top of terrain tiles (for debugging)
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
void terrainVerticalScaleChanged()
Emitted when the vertical scale of the terrain has changed.
3 Definition of the world
QColor selectionColor() const
Returns color used for selected features.
3 Terrain generator using downloaded terrain tiles using quantized mesh specification ...
static QString encodeColor(const QColor &color)
virtual void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const =0
Writes renderer&#39;s properties to given XML element.
static QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords, const QgsVector3D &origin)
Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x...
Definition: qgs3dutils.cpp:349
QColor backgroundColor() const
Returns background color of the 3D map view.
QString layerId
Original layer ID.
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of map layers to be rendered as a texture of the terrain.
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
void setCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets CRS of the terrain.
QPointer< TYPE > layer
Weak pointer to map layer.
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
void showCameraViewCenterChanged()
Emitted when the flag whether camera&#39;s view center is shown has changed.
QgsVector3D mapToWorldCoordinates(const QgsVector3D &mapCoords) const
Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x...
float maxTerrainGroundError() const
Returns maximum ground error of terrain tiles in world units.
void selectionColorChanged()
Emitted when the selection color has changed.
static QgsVector3D mapToWorldCoordinates(const QgsVector3D &mapCoords, const QgsVector3D &origin)
Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x...
Definition: qgs3dutils.cpp:341
void terrainGeneratorChanged()
Emitted when the terrain generator has changed.
Reads and writes project states.
Definition: qgsproject.h:89
int mapTileResolution() const
Returns resolution (in pixels) of the texture of a terrain tile.
void showTerrainBoundingBoxesChanged()
Emitted when the flag whether terrain&#39;s bounding boxes are shown has changed.
Contains information about the context in which a coordinate transform is executed.
static QString typeToString(Type type)
Converts terrain generator type enumeration into a string.
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
void setMaxTerrainGroundError(float error)
Returns maximum ground error of terrain tiles in world units.
void mapTileResolutionChanged()
Emitted when the map tile resoulution has changed.
void setTerrainVerticalScale(double zScale)
Sets vertical scale (exaggeration) of terrain (1 = true scale, > 1 = hills get more pronounced) ...
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
3D renderer that renders all features of a vector layer with the same 3D symbol.
void showTerrainTilesInfoChanged()
Emitted when the flag whether terrain&#39;s tile info is shown has changed.
void setMapTileResolution(int res)
Sets resolution (in pixels) of the texture of a terrain tile.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads renderer&#39;s properties from given XML element.
Qgs3DMapSettings()=default
Constructor for Qgs3DMapSettings.
void showLabelsChanged()
Emitted when the flag whether labels are displayed on terrain tiles has changed.
void maxTerrainScreenErrorChanged()
Emitted when the maximum terrain screen error has changed.
3 Base class for generators of terrain.
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
void setBackgroundColor(const QColor &color)
Sets background color of the 3D map view.
QList< QgsAbstract3DRenderer * > renderers() const
Returns list of extra 3D renderers.
3 Implementation of terrain generator that uses a raster layer with DEM to build terrain.
This class represents a coordinate reference system (CRS).
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets CRS of the terrain.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
~Qgs3DMapSettings() override
void setShowLabels(bool enabled)
Sets whether to display labels on terrain tiles.
virtual QgsAbstract3DRenderer * clone() const =0
Returns a cloned instance.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from a DOM element previously written by writeXml()
void backgroundColorChanged()
Emitted when the background color has changed.
void setMaxTerrainScreenError(float error)
Sets maximum allowed screen error of terrain tiles in pixels.
void setRenderers(const QList< QgsAbstract3DRenderer * > &renderers)
Sets list of extra 3D renderers to use in the scene. Takes ownership of the objects.
void resolveReferences(const QgsProject &project)
Resolves references to other objects (map layers) after the call to readXml()
void setShowTerrainBoundingBoxes(bool enabled)
Sets whether to display bounding boxes of terrain tiles (for debugging)
void setSelectionColor(const QColor &color)
Sets color used for selected features.
double terrainVerticalScale() const
Returns vertical scale (exaggeration) of terrain.
float maxTerrainScreenError() const
Returns maximum allowed screen error of terrain tiles in pixels.
QgsTerrainGenerator * terrainGenerator() const
Returns terrain generator. It takes care of producing terrain tiles from the input data...
static QColor decodeColor(const QString &str)