QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsterrainprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsterrainprovider.cpp
3  ---------------
4  begin : February 2022
5  copyright : (C) 2022 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include "qgsterrainprovider.h"
18 #include "qgsmeshlayerutils.h"
19 #include <QThread>
20 
22 
24 {
25 
26 }
27 
29  : mScale( other.mScale )
30  , mOffset( other.mOffset )
31 {
32 
33 }
34 
36 {
37  element.setAttribute( QStringLiteral( "offset" ), qgsDoubleToString( mOffset ) );
38  element.setAttribute( QStringLiteral( "scale" ), qgsDoubleToString( mScale ) );
39 }
40 
41 void QgsAbstractTerrainProvider::readCommonProperties( const QDomElement &element, const QgsReadWriteContext & )
42 {
43  mOffset = element.attribute( QStringLiteral( "offset" ) ).toDouble();
44  mScale = element.attribute( QStringLiteral( "scale" ) ).toDouble();
45 }
46 
47 //
48 // QgsFlatTerrainProvider
49 //
50 
52 {
53  return QStringLiteral( "flat" );
54 }
55 
56 bool QgsFlatTerrainProvider::readXml( const QDomElement &element, const QgsReadWriteContext &context )
57 {
58  const QDomElement terrainElement = element.firstChildElement( QStringLiteral( "TerrainProvider" ) );
59  if ( terrainElement.isNull() )
60  return false;
61 
62  readCommonProperties( terrainElement, context );
63  return true;
64 }
65 
66 QDomElement QgsFlatTerrainProvider::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
67 {
68  QDomElement element = document.createElement( QStringLiteral( "TerrainProvider" ) );
69  writeCommonProperties( element, context );
70  return element;
71 }
72 
74 {
76 }
77 
78 double QgsFlatTerrainProvider::heightAt( double, double ) const
79 {
80  return mOffset;
81 }
82 
84 {
85  return new QgsFlatTerrainProvider( *this );
86 }
87 
89 {
90  Q_ASSERT_X( QThread::currentThread() == QCoreApplication::instance()->thread(), "QgsFlatTerrainProvider::prepare", "prepare() must be called from the main thread" );
91 
92 }
93 
95 {
96  if ( other->type() != type() )
97  return false;
98 
99  const QgsFlatTerrainProvider *otherTerrain = qgis::down_cast< const QgsFlatTerrainProvider * >( other );
100 
101  return qgsDoubleNear( otherTerrain->offset(), mOffset );
102 }
103 
104 
105 //
106 // QgsRasterDemTerrainProvider
107 //
108 
110 {
111  return QStringLiteral( "raster" );
112 }
113 
115 {
116  if ( mRasterLayer )
117  return; // already assigned
118 
119  mRasterLayer.resolve( project );
120 }
121 
122 bool QgsRasterDemTerrainProvider::readXml( const QDomElement &element, const QgsReadWriteContext &context )
123 {
124  const QDomElement terrainElement = element.firstChildElement( QStringLiteral( "TerrainProvider" ) );
125  if ( terrainElement.isNull() )
126  return false;
127 
128  QString layerId = terrainElement.attribute( QStringLiteral( "layer" ) );
129  QString layerName = terrainElement.attribute( QStringLiteral( "layerName" ) );
130  QString layerSource = terrainElement.attribute( QStringLiteral( "layerSource" ) );
131  QString layerProvider = terrainElement.attribute( QStringLiteral( "layerProvider" ) );
132  mRasterLayer = _LayerRef<QgsRasterLayer>( layerId, layerName, layerSource, layerProvider );
133 
134  readCommonProperties( terrainElement, context );
135  return true;
136 }
137 
138 QDomElement QgsRasterDemTerrainProvider::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
139 {
140  QDomElement element = document.createElement( QStringLiteral( "TerrainProvider" ) );
141  if ( mRasterLayer )
142  {
143  element.setAttribute( QStringLiteral( "layer" ), mRasterLayer.layerId );
144  element.setAttribute( QStringLiteral( "layerName" ), mRasterLayer.name );
145  element.setAttribute( QStringLiteral( "layerSource" ), mRasterLayer.source );
146  element.setAttribute( QStringLiteral( "layerProvider" ), mRasterLayer.provider );
147  }
148 
149  writeCommonProperties( element, context );
150  return element;
151 }
152 
154 {
155  return mRasterProvider ? mRasterProvider->crs()
156  : ( mRasterLayer ? mRasterLayer->crs() : QgsCoordinateReferenceSystem() );
157 }
158 
159 double QgsRasterDemTerrainProvider::heightAt( double x, double y ) const
160 {
161  // TODO -- may want to use a more efficient approach here, i.e. requesting whole
162  // blocks upfront instead of multiple sample calls
163  bool ok = false;
164  double res = std::numeric_limits<double>::quiet_NaN();
165  if ( mRasterProvider )
166  {
167  res = mRasterProvider->sample( QgsPointXY( x, y ), 1, &ok );
168  }
169  else if ( QThread::currentThread() == QCoreApplication::instance()->thread() && mRasterLayer && mRasterLayer->isValid() )
170  {
171  res = mRasterLayer->dataProvider()->sample( QgsPointXY( x, y ), 1, &ok );
172  }
173 
174  if ( ok )
175  return res * mScale + mOffset;
176 
177  return std::numeric_limits<double>::quiet_NaN();
178 }
179 
181 {
182  return new QgsRasterDemTerrainProvider( *this );
183 }
184 
186 {
187  if ( other->type() != type() )
188  return false;
189 
190  const QgsRasterDemTerrainProvider *otherTerrain = qgis::down_cast< const QgsRasterDemTerrainProvider * >( other );
191  if ( !qgsDoubleNear( otherTerrain->offset(), mOffset )
192  || !qgsDoubleNear( otherTerrain->scale(), mScale )
193  || mRasterLayer.get() != otherTerrain->layer() )
194  return false;
195 
196  return true;
197 }
198 
200 {
201  Q_ASSERT_X( QThread::currentThread() == QCoreApplication::instance()->thread(), "QgsRasterDemTerrainProvider::prepare", "prepare() must be called from the main thread" );
202 
203  if ( mRasterLayer && mRasterLayer->isValid() )
204  mRasterProvider.reset( mRasterLayer->dataProvider()->clone() );
205 }
206 
208 {
209  mRasterLayer.setLayer( layer );
210 }
211 
213 {
214  return mRasterLayer.get();
215 }
216 
218  : QgsAbstractTerrainProvider( other )
219  , mRasterLayer( other.mRasterLayer )
220 {
221 
222 }
223 
224 
225 //
226 // QgsMeshTerrainProvider
227 //
228 
230 {
231  return QStringLiteral( "mesh" );
232 }
233 
235 {
236  if ( mMeshLayer )
237  return; // already assigned
238 
239  mMeshLayer.resolve( project );
240 }
241 
242 bool QgsMeshTerrainProvider::readXml( const QDomElement &element, const QgsReadWriteContext &context )
243 {
244  const QDomElement terrainElement = element.firstChildElement( QStringLiteral( "TerrainProvider" ) );
245  if ( terrainElement.isNull() )
246  return false;
247 
248  QString layerId = terrainElement.attribute( QStringLiteral( "layer" ) );
249  QString layerName = terrainElement.attribute( QStringLiteral( "layerName" ) );
250  QString layerSource = terrainElement.attribute( QStringLiteral( "layerSource" ) );
251  QString layerProvider = terrainElement.attribute( QStringLiteral( "layerProvider" ) );
252  mMeshLayer = _LayerRef<QgsMeshLayer>( layerId, layerName, layerSource, layerProvider );
253 
254  readCommonProperties( terrainElement, context );
255  return true;
256 }
257 
258 QDomElement QgsMeshTerrainProvider::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
259 {
260  QDomElement element = document.createElement( QStringLiteral( "TerrainProvider" ) );
261  if ( mMeshLayer )
262  {
263  element.setAttribute( QStringLiteral( "layer" ), mMeshLayer.layerId );
264  element.setAttribute( QStringLiteral( "layerName" ), mMeshLayer.name );
265  element.setAttribute( QStringLiteral( "layerSource" ), mMeshLayer.source );
266  element.setAttribute( QStringLiteral( "layerProvider" ), mMeshLayer.provider );
267  }
268 
269  writeCommonProperties( element, context );
270  return element;
271 }
272 
274 {
275  return mMeshLayer ? mMeshLayer->crs() : QgsCoordinateReferenceSystem();
276 }
277 
278 double QgsMeshTerrainProvider::heightAt( double x, double y ) const
279 {
280  if ( mTriangularMesh.vertices().empty() && mMeshLayer && QThread::currentThread() == QCoreApplication::instance()->thread() )
281  const_cast< QgsMeshTerrainProvider * >( this )->prepare(); // auto prepare if we are on main thread and haven't already!
282 
283  return QgsMeshLayerUtils::interpolateZForPoint( mTriangularMesh, x, y ) * mScale + mOffset;
284 }
285 
287 {
288  return new QgsMeshTerrainProvider( *this );
289 }
290 
292 {
293  if ( other->type() != type() )
294  return false;
295 
296  const QgsMeshTerrainProvider *otherTerrain = qgis::down_cast< const QgsMeshTerrainProvider * >( other );
297  if ( !qgsDoubleNear( otherTerrain->offset(), mOffset )
298  || !qgsDoubleNear( otherTerrain->scale(), mScale )
299  || mMeshLayer.get() != otherTerrain->layer() )
300  return false;
301 
302  return true;
303 }
304 
306 {
307  Q_ASSERT_X( QThread::currentThread() == QCoreApplication::instance()->thread(), "QgsMeshTerrainProvider::prepare", "prepare() must be called from the main thread" );
308  if ( mMeshLayer )
309  {
310  mMeshLayer->updateTriangularMesh();
311  mTriangularMesh = *mMeshLayer->triangularMesh();
312  }
313 }
314 
316 {
317  mMeshLayer.setLayer( layer );
318 }
319 
321 {
322  return mMeshLayer.get();
323 }
324 
326  : QgsAbstractTerrainProvider( other )
327  , mMeshLayer( other.mMeshLayer )
328 {
329 
330 }
qgsmeshlayerutils.h
QgsMeshTerrainProvider::crs
QgsCoordinateReferenceSystem crs() const override
Returns the native coordinate reference system of the terrain provider.
Definition: qgsterrainprovider.cpp:273
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsRasterDemTerrainProvider::crs
QgsCoordinateReferenceSystem crs() const override
Returns the native coordinate reference system of the terrain provider.
Definition: qgsterrainprovider.cpp:153
QgsTriangularMesh::vertices
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
Definition: qgstriangularmesh.cpp:352
QgsRasterDemTerrainProvider::equals
bool equals(const QgsAbstractTerrainProvider *other) const override
Returns true if the provider is equal to other.
Definition: qgsterrainprovider.cpp:185
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsFlatTerrainProvider::clone
QgsFlatTerrainProvider * clone() const override
Creates a clone of the provider and returns the new object.
Definition: qgsterrainprovider.cpp:83
QgsMeshTerrainProvider::layer
QgsMeshLayer * layer() const
Returns the mesh layer to be used as the terrain source.
Definition: qgsterrainprovider.cpp:320
QgsMeshTerrainProvider::QgsMeshTerrainProvider
QgsMeshTerrainProvider()=default
Constructor for QgsMeshTerrainProvider.
QgsRasterDemTerrainProvider::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the terrain provider state from a DOM element.
Definition: qgsterrainprovider.cpp:122
QgsFlatTerrainProvider::prepare
void prepare() override
Called on the main thread prior to accessing the provider from a background thread.
Definition: qgsterrainprovider.cpp:88
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:81
QgsFlatTerrainProvider::type
QString type() const override
Returns the unique type ID string for the provider.
Definition: qgsterrainprovider.cpp:51
QgsFlatTerrainProvider::heightAt
double heightAt(double x, double y) const override
Returns the height at the point (x,y) in the terrain provider's native crs().
Definition: qgsterrainprovider.cpp:78
QgsRasterDemTerrainProvider::clone
QgsRasterDemTerrainProvider * clone() const override
Creates a clone of the provider and returns the new object.
Definition: qgsterrainprovider.cpp:180
QgsMeshLayer::triangularMesh
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
Definition: qgsmeshlayer.cpp:285
QgsMeshTerrainProvider
A terrain provider that uses the Z values of a mesh layer to build a terrain surface.
Definition: qgsterrainprovider.h:284
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:2204
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:103
QgsRasterDataProvider::clone
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
QgsMeshLayer::updateTriangularMesh
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
Definition: qgsmeshlayer.cpp:317
_LayerRef::layerId
QString layerId
Original layer ID.
Definition: qgsmaplayerref.h:117
QgsAbstractTerrainProvider::type
virtual QString type() const =0
Returns the unique type ID string for the provider.
QgsMeshTerrainProvider::prepare
void prepare() override
Called on the main thread prior to accessing the provider from a background thread.
Definition: qgsterrainprovider.cpp:305
QgsFlatTerrainProvider::crs
QgsCoordinateReferenceSystem crs() const override
Returns the native coordinate reference system of the terrain provider.
Definition: qgsterrainprovider.cpp:73
_LayerRef::setLayer
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
Definition: qgsmaplayerref.h:78
_LayerRef::provider
QString provider
Weak reference to layer provider.
Definition: qgsmaplayerref.h:124
QgsMeshTerrainProvider::heightAt
double heightAt(double x, double y) const override
Returns the height at the point (x,y) in the terrain provider's native crs().
Definition: qgsterrainprovider.cpp:278
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsRasterDataProvider::sample
virtual double sample(const QgsPointXY &point, int band, bool *ok=nullptr, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Samples a raster value from the specified band found at the point position.
Definition: qgsrasterdataprovider.cpp:334
QgsMeshLayer
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:98
QgsMeshTerrainProvider::type
QString type() const override
Returns the unique type ID string for the provider.
Definition: qgsterrainprovider.cpp:229
_LayerRef::name
QString name
Weak reference to layer name.
Definition: qgsmaplayerref.h:122
QgsRasterDemTerrainProvider::setLayer
void setLayer(QgsRasterLayer *layer)
Sets the raster layer with elevation model to be used as the terrain source.
Definition: qgsterrainprovider.cpp:207
QgsRasterLayer
Represents a raster layer.
Definition: qgsrasterlayer.h:76
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsFlatTerrainProvider::writeXml
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const override
Returns a DOM element representing the state of the terrain provider.
Definition: qgsterrainprovider.cpp:66
QgsFlatTerrainProvider::equals
bool equals(const QgsAbstractTerrainProvider *other) const override
Returns true if the provider is equal to other.
Definition: qgsterrainprovider.cpp:94
QgsAbstractTerrainProvider::mScale
double mScale
Scale factor.
Definition: qgsterrainprovider.h:185
QgsMeshTerrainProvider::writeXml
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const override
Returns a DOM element representing the state of the terrain provider.
Definition: qgsterrainprovider.cpp:258
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsAbstractTerrainProvider::QgsAbstractTerrainProvider
QgsAbstractTerrainProvider()=default
Constructor for QgsAbstractTerrainProvider.
QgsMeshTerrainProvider::clone
QgsMeshTerrainProvider * clone() const override
Creates a clone of the provider and returns the new object.
Definition: qgsterrainprovider.cpp:286
QgsRasterDemTerrainProvider::resolveReferences
void resolveReferences(const QgsProject *project) override
Resolves reference to layers from stored layer ID (if it has not been resolved already)
Definition: qgsterrainprovider.cpp:114
QgsAbstractTerrainProvider::writeCommonProperties
void writeCommonProperties(QDomElement &element, const QgsReadWriteContext &context) const
Writes common properties to a DOM element.
Definition: qgsterrainprovider.cpp:35
_LayerRef::source
QString source
Weak reference to layer public source.
Definition: qgsmaplayerref.h:120
QgsRasterDemTerrainProvider::type
QString type() const override
Returns the unique type ID string for the provider.
Definition: qgsterrainprovider.cpp:109
QgsRasterDemTerrainProvider::QgsRasterDemTerrainProvider
QgsRasterDemTerrainProvider()=default
Constructor for QgsRasterDemTerrainProvider.
QgsRasterDemTerrainProvider::heightAt
double heightAt(double x, double y) const override
Returns the height at the point (x,y) in the terrain provider's native crs().
Definition: qgsterrainprovider.cpp:159
QgsRasterDemTerrainProvider
A terrain provider where the terrain source is a raster DEM layer.
Definition: qgsterrainprovider.h:230
QgsAbstractTerrainProvider::~QgsAbstractTerrainProvider
virtual ~QgsAbstractTerrainProvider()
qgsterrainprovider.h
QgsAbstractTerrainProvider::readCommonProperties
void readCommonProperties(const QDomElement &element, const QgsReadWriteContext &context)
Reads common properties from a DOM element.
Definition: qgsterrainprovider.cpp:41
QgsRasterDemTerrainProvider::prepare
void prepare() override
Called on the main thread prior to accessing the provider from a background thread.
Definition: qgsterrainprovider.cpp:199
_LayerRef< QgsRasterLayer >
QgsMeshTerrainProvider::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the terrain provider state from a DOM element.
Definition: qgsterrainprovider.cpp:242
QgsFlatTerrainProvider::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the terrain provider state from a DOM element.
Definition: qgsterrainprovider.cpp:56
QgsRasterDemTerrainProvider::writeXml
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const override
Returns a DOM element representing the state of the terrain provider.
Definition: qgsterrainprovider.cpp:138
QgsRasterDemTerrainProvider::layer
QgsRasterLayer * layer() const
Returns the raster layer with elevation model to be used as the terrain source.
Definition: qgsterrainprovider.cpp:212
QgsAbstractTerrainProvider
Abstract base class for terrain providers.
Definition: qgsterrainprovider.h:40
QgsAbstractTerrainProvider::resolveReferences
virtual void resolveReferences(const QgsProject *project)
Resolves reference to layers from stored layer ID (if it has not been resolved already)
Definition: qgsterrainprovider.cpp:23
QgsMeshTerrainProvider::equals
bool equals(const QgsAbstractTerrainProvider *other) const override
Returns true if the provider is equal to other.
Definition: qgsterrainprovider.cpp:291
QgsMeshTerrainProvider::setLayer
void setLayer(QgsMeshLayer *layer)
Sets the mesh layer to be used as the terrain source.
Definition: qgsterrainprovider.cpp:315
_LayerRef::resolve
TYPE * resolve(const QgsProject *project)
Resolves the map layer by attempting to find a layer with matching ID within a project.
Definition: qgsmaplayerref.h:150
QgsRasterLayer::dataProvider
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Definition: qgsrasterlayer.cpp:257
QgsFlatTerrainProvider::QgsFlatTerrainProvider
QgsFlatTerrainProvider()=default
Constructor for QgsFlatTerrainProvider.
QgsAbstractTerrainProvider::scale
double scale() const
Returns the vertical scale factor, which can be used to exaggerate vertical heights.
Definition: qgsterrainprovider.h:133
_LayerRef::get
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer.
Definition: qgsmaplayerref.h:108
QgsAbstractTerrainProvider::offset
double offset() const
Returns the vertical offset value, used for adjusting the heights from the terrain provider.
Definition: qgsterrainprovider.h:149
QgsAbstractTerrainProvider::mOffset
double mOffset
Offset amount.
Definition: qgsterrainprovider.h:188
QgsMeshTerrainProvider::resolveReferences
void resolveReferences(const QgsProject *project) override
Resolves reference to layers from stored layer ID (if it has not been resolved already)
Definition: qgsterrainprovider.cpp:234
QgsFlatTerrainProvider
A terrain provider where the terrain is a simple flat surface.
Definition: qgsterrainprovider.h:205