Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Merge pull request #9549 from wonder-sk/online-3d-terrain
[3d] Add option to use terrain data from online service
- Loading branch information
Showing
with
872 additions
and 83 deletions.
- +4 −0 src/3d/CMakeLists.txt
- +5 −6 src/3d/qgs3dmapsettings.cpp
- +36 −7 src/3d/terrain/qgsdemterraintileloader_p.cpp
- +3 −0 src/3d/terrain/qgsdemterraintileloader_p.h
- +117 −0 src/3d/terrain/qgsonlineterraingenerator.cpp
- +86 −0 src/3d/terrain/qgsonlineterraingenerator.h
- +199 −0 src/3d/terrain/qgsterraindownloader.cpp
- +97 −0 src/3d/terrain/qgsterraindownloader.h
- +2 −2 src/3d/terrain/qgsterraingenerator.cpp
- +1 −1 src/3d/terrain/qgsterraingenerator.h
- +71 −22 src/app/3d/qgs3dmapconfigwidget.cpp
- +1 −0 src/app/3d/qgs3dmapconfigwidget.h
- +86 −0 src/core/qgsgdalutils.cpp
- +21 −0 src/core/qgsgdalutils.h
- +55 −45 src/ui/3d/map3dconfigwidget.ui
- +88 −0 tests/src/core/testqgsgdalutils.cpp
@@ -0,0 +1,117 @@ | ||
/*************************************************************************** | ||
qgsonlineterraingenerator.cpp | ||
-------------------------------------- | ||
Date : March 2019 | ||
Copyright : (C) 2019 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsonlineterraingenerator.h" | ||
|
||
#include "qgsdemterraintileloader_p.h" | ||
|
||
|
||
QgsOnlineTerrainGenerator::QgsOnlineTerrainGenerator() = default; | ||
|
||
QgsOnlineTerrainGenerator::~QgsOnlineTerrainGenerator() = default; | ||
|
||
QgsChunkLoader *QgsOnlineTerrainGenerator::createChunkLoader( QgsChunkNode *node ) const | ||
{ | ||
return new QgsDemTerrainTileLoader( mTerrain, node ); | ||
} | ||
|
||
QgsTerrainGenerator *QgsOnlineTerrainGenerator::clone() const | ||
{ | ||
QgsOnlineTerrainGenerator *cloned = new QgsOnlineTerrainGenerator; | ||
cloned->mCrs = mCrs; | ||
cloned->mExtent = mExtent; | ||
cloned->mResolution = mResolution; | ||
cloned->mSkirtHeight = mSkirtHeight; | ||
cloned->updateGenerator(); | ||
return cloned; | ||
} | ||
|
||
QgsTerrainGenerator::Type QgsOnlineTerrainGenerator::type() const | ||
{ | ||
return QgsTerrainGenerator::Online; | ||
} | ||
|
||
QgsRectangle QgsOnlineTerrainGenerator::extent() const | ||
{ | ||
return mTerrainTilingScheme.tileToExtent( 0, 0, 0 ); | ||
} | ||
|
||
float QgsOnlineTerrainGenerator::heightAt( double x, double y, const Qgs3DMapSettings &map ) const | ||
{ | ||
Q_UNUSED( map ); | ||
if ( mHeightMapGenerator ) | ||
return mHeightMapGenerator->heightAt( x, y ); | ||
else | ||
return 0; | ||
} | ||
|
||
void QgsOnlineTerrainGenerator::writeXml( QDomElement &elem ) const | ||
{ | ||
QgsRectangle r = mExtent; | ||
QDomElement elemExtent = elem.ownerDocument().createElement( QStringLiteral( "extent" ) ); | ||
elemExtent.setAttribute( QStringLiteral( "xmin" ), QString::number( r.xMinimum() ) ); | ||
elemExtent.setAttribute( QStringLiteral( "xmax" ), QString::number( r.xMaximum() ) ); | ||
elemExtent.setAttribute( QStringLiteral( "ymin" ), QString::number( r.yMinimum() ) ); | ||
elemExtent.setAttribute( QStringLiteral( "ymax" ), QString::number( r.yMaximum() ) ); | ||
|
||
elem.setAttribute( QStringLiteral( "resolution" ), mResolution ); | ||
elem.setAttribute( QStringLiteral( "skirt-height" ), mSkirtHeight ); | ||
|
||
// crs is not read/written - it should be the same as destination crs of the map | ||
} | ||
|
||
void QgsOnlineTerrainGenerator::readXml( const QDomElement &elem ) | ||
{ | ||
QDomElement elemExtent = elem.firstChildElement( QStringLiteral( "extent" ) ); | ||
double xmin = elemExtent.attribute( QStringLiteral( "xmin" ) ).toDouble(); | ||
double xmax = elemExtent.attribute( QStringLiteral( "xmax" ) ).toDouble(); | ||
double ymin = elemExtent.attribute( QStringLiteral( "ymin" ) ).toDouble(); | ||
double ymax = elemExtent.attribute( QStringLiteral( "ymax" ) ).toDouble(); | ||
|
||
setExtent( QgsRectangle( xmin, ymin, xmax, ymax ) ); | ||
|
||
mResolution = elem.attribute( QStringLiteral( "resolution" ) ).toInt(); | ||
mSkirtHeight = elem.attribute( QStringLiteral( "skirt-height" ) ).toFloat(); | ||
|
||
// crs is not read/written - it should be the same as destination crs of the map | ||
} | ||
|
||
void QgsOnlineTerrainGenerator::setCrs( const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context ) | ||
{ | ||
mCrs = crs; | ||
mTransformContext = context; | ||
updateGenerator(); | ||
} | ||
|
||
void QgsOnlineTerrainGenerator::setExtent( const QgsRectangle &extent ) | ||
{ | ||
mExtent = extent; | ||
updateGenerator(); | ||
} | ||
|
||
void QgsOnlineTerrainGenerator::updateGenerator() | ||
{ | ||
if ( mExtent.isNull() ) | ||
{ | ||
mTerrainTilingScheme = QgsTilingScheme(); | ||
} | ||
else | ||
{ | ||
// the real extent will be a square where the given extent fully fits | ||
mTerrainTilingScheme = QgsTilingScheme( mExtent, mCrs ); | ||
} | ||
|
||
mHeightMapGenerator.reset( new QgsDemHeightMapGenerator( nullptr, mTerrainTilingScheme, mResolution ) ); | ||
} |
@@ -0,0 +1,86 @@ | ||
/*************************************************************************** | ||
qgsonlineterraingenerator.h | ||
-------------------------------------- | ||
Date : March 2019 | ||
Copyright : (C) 2019 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSONLINETERRAINGENERATOR_H | ||
#define QGSONLINETERRAINGENERATOR_H | ||
|
||
#include "qgis_3d.h" | ||
|
||
#include "qgsterraingenerator.h" | ||
|
||
#include "qgscoordinatetransformcontext.h" | ||
|
||
class QgsDemHeightMapGenerator; | ||
|
||
/** | ||
* \ingroup 3d | ||
* Implementation of terrain generator that uses online resources to download heightmaps. | ||
* \since QGIS 3.8 | ||
*/ | ||
class _3D_EXPORT QgsOnlineTerrainGenerator : public QgsTerrainGenerator | ||
{ | ||
public: | ||
//! Constructor for QgsOnlineTerrainGenerator | ||
QgsOnlineTerrainGenerator(); | ||
~QgsOnlineTerrainGenerator() override; | ||
|
||
//! Sets extent of the terrain | ||
void setExtent( const QgsRectangle &extent ); | ||
|
||
//! Sets CRS of the terrain | ||
void setCrs( const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context ); | ||
//! Returns CRS of the terrain | ||
QgsCoordinateReferenceSystem crs() const { return mCrs; } | ||
|
||
//! Sets resolution of the generator (how many elevation samples on one side of a terrain tile) | ||
void setResolution( int resolution ) { mResolution = resolution; updateGenerator(); } | ||
//! Returns resolution of the generator (how many elevation samples on one side of a terrain tile) | ||
int resolution() const { return mResolution; } | ||
|
||
//! Sets skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between adjacent tiles. | ||
void setSkirtHeight( float skirtHeight ) { mSkirtHeight = skirtHeight; } | ||
//! Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between adjacent tiles. | ||
float skirtHeight() const { return mSkirtHeight; } | ||
|
||
//! Returns height map generator object - takes care of extraction of elevations from the layer) | ||
QgsDemHeightMapGenerator *heightMapGenerator() { return mHeightMapGenerator.get(); } | ||
|
||
QgsTerrainGenerator *clone() const override SIP_FACTORY; | ||
Type type() const override; | ||
QgsRectangle extent() const override; | ||
float heightAt( double x, double y, const Qgs3DMapSettings &map ) const override; | ||
void writeXml( QDomElement &elem ) const override; | ||
void readXml( const QDomElement &elem ) override; | ||
//void resolveReferences( const QgsProject &project ) override; | ||
|
||
QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override SIP_FACTORY; | ||
|
||
private: | ||
|
||
void updateGenerator(); | ||
|
||
QgsRectangle mExtent; | ||
QgsCoordinateReferenceSystem mCrs; | ||
QgsCoordinateTransformContext mTransformContext; | ||
|
||
//! how many vertices to place on one side of the tile | ||
int mResolution = 16; | ||
//! height of the "skirts" at the edges of tiles to hide cracks between adjacent cracks | ||
float mSkirtHeight = 10.f; | ||
|
||
std::unique_ptr<QgsDemHeightMapGenerator> mHeightMapGenerator; | ||
}; | ||
|
||
#endif // QGSONLINETERRAINGENERATOR_H |
Oops, something went wrong.