QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsmeshlayerinterpolator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerinterpolator.cpp
3  ----------------------------
4  begin : April 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv 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 
19 
20 #include <memory>
21 #include <limits>
22 
24 
25 #include "qgis.h"
26 #include "qgsrasterinterface.h"
27 #include "qgsmaptopixel.h"
28 #include "qgsvector.h"
29 #include "qgspoint.h"
30 #include "qgspointxy.h"
31 #include "qgsmeshlayerutils.h"
32 #include "qgsmeshlayer.h"
34 #include "qgscoordinatetransform.h"
35 #include "qgsmeshdataprovider.h"
36 
37 QgsMeshLayerInterpolator::QgsMeshLayerInterpolator(
38  const QgsTriangularMesh &m,
39  const QVector<double> &datasetValues,
40  const QgsMeshDataBlock &activeFaceFlagValues,
42  const QgsRenderContext &context,
43  const QSize &size )
44  : mTriangularMesh( m ),
45  mDatasetValues( datasetValues ),
46  mActiveFaceFlagValues( activeFaceFlagValues ),
47  mContext( context ),
48  mDataType( dataType ),
49  mOutputSize( size )
50 {
51 }
52 
53 QgsMeshLayerInterpolator::~QgsMeshLayerInterpolator() = default;
54 
55 QgsRasterInterface *QgsMeshLayerInterpolator::clone() const
56 {
57  assert( false ); // we should not need this (hopefully)
58  return nullptr;
59 }
60 
61 Qgis::DataType QgsMeshLayerInterpolator::dataType( int ) const
62 {
63  return Qgis::Float64;
64 }
65 
66 int QgsMeshLayerInterpolator::bandCount() const
67 {
68  return 1;
69 }
70 
71 QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
72 {
73  std::unique_ptr<QgsRasterBlock> outputBlock( new QgsRasterBlock( Qgis::Float64, width, height ) );
74  const double noDataValue = std::numeric_limits<double>::quiet_NaN();
75  outputBlock->setNoDataValue( noDataValue );
76  outputBlock->setIsNoData(); // assume initially that all values are unset
77  double *data = reinterpret_cast<double *>( outputBlock->bits() );
78 
79  QList<int> spatialIndexTriangles;
80  int indexCount;
81  if ( mSpatialIndexActive )
82  {
83  spatialIndexTriangles = mTriangularMesh.faceIndexesForRectangle( extent );
84  indexCount = spatialIndexTriangles.count();
85  }
86  else
87  {
88  indexCount = mTriangularMesh.triangles().count();
89  }
90 
91  if ( mTriangularMesh.contains( QgsMesh::ElementType::Edge ) )
92  {
93  return outputBlock.release();
94  }
95 
96  const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
97 
98  // currently expecting that triangulation does not add any new extra vertices on the way
99  if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
100  Q_ASSERT( mDatasetValues.count() == mTriangularMesh.vertices().count() );
101 
102  for ( int i = 0; i < indexCount; ++i )
103  {
104  if ( feedback && feedback->isCanceled() )
105  break;
106 
107  if ( mContext.renderingStopped() )
108  break;
109 
110  int triangleIndex;
111  if ( mSpatialIndexActive )
112  triangleIndex = spatialIndexTriangles[i];
113  else
114  triangleIndex = i;
115 
116  const QgsMeshFace &face = mTriangularMesh.triangles()[triangleIndex];
117 
118  const int v1 = face[0], v2 = face[1], v3 = face[2];
119  const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
120 
121  const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[triangleIndex];
122  const bool isActive = mActiveFaceFlagValues.active( nativeFaceIndex );
123  if ( !isActive )
124  continue;
125 
126  QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( p1, p2, p3 );
127  if ( !extent.intersects( bbox ) )
128  continue;
129 
130  // Get the BBox of the element in pixels
131  int topLim, bottomLim, leftLim, rightLim;
132  QgsMeshLayerUtils::boundingBoxToScreenRectangle( mContext.mapToPixel(), mOutputSize, bbox, leftLim, rightLim, topLim, bottomLim );
133 
134  // interpolate in the bounding box of the face
135  for ( int j = topLim; j <= bottomLim; j++ )
136  {
137  double *line = data + ( j * width );
138  for ( int k = leftLim; k <= rightLim; k++ )
139  {
140  double val;
141  const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( k, j );
142  if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
143  val = QgsMeshLayerUtils::interpolateFromVerticesData(
144  p1,
145  p2,
146  p3,
147  mDatasetValues[v1],
148  mDatasetValues[v2],
149  mDatasetValues[v3],
150  p );
151  else
152  {
153  const int faceIdx = mTriangularMesh.trianglesToNativeFaces()[triangleIndex];
154  val = QgsMeshLayerUtils::interpolateFromFacesData(
155  p1,
156  p2,
157  p3,
158  mDatasetValues[faceIdx],
159  p
160  );
161  }
162  if ( !std::isnan( val ) )
163  {
164  line[k] = val;
165  outputBlock->setIsData( j, k );
166  }
167  }
168  }
169 
170  }
171 
172  return outputBlock.release();
173 }
174 
175 void QgsMeshLayerInterpolator::setSpatialIndexActive( bool active ) {mSpatialIndexActive = active;}
176 
178 
180  const QgsMeshLayer &layer,
181  const QgsMeshDatasetIndex &datasetIndex,
182  const QgsCoordinateReferenceSystem &destinationCrs,
183  const QgsCoordinateTransformContext &transformContext,
184  double mapUnitsPerPixel,
185  const QgsRectangle &extent,
186  QgsRasterBlockFeedback *feedback )
187 {
188  if ( !layer.dataProvider() )
189  return nullptr;
190 
191  if ( !datasetIndex.isValid() )
192  return nullptr;
193 
194  int widthPixel = static_cast<int>( extent.width() / mapUnitsPerPixel );
195  int heightPixel = static_cast<int>( extent.height() / mapUnitsPerPixel );
196 
197  const QgsPointXY center = extent.center();
198  QgsMapToPixel mapToPixel( mapUnitsPerPixel,
199  center.x(),
200  center.y(),
201  widthPixel,
202  heightPixel,
203  0 );
204  QgsCoordinateTransform transform( layer.crs(), destinationCrs, transformContext );
205 
206  QgsRenderContext renderContext;
207  renderContext.setCoordinateTransform( transform );
208  renderContext.setMapToPixel( mapToPixel );
209  renderContext.setExtent( extent );
210 
211  std::unique_ptr<QgsMesh> nativeMesh = qgis::make_unique<QgsMesh>();
212  layer.dataProvider()->populateMesh( nativeMesh.get() );
213  std::unique_ptr<QgsTriangularMesh> triangularMesh = qgis::make_unique<QgsTriangularMesh>();
214  triangularMesh->update( nativeMesh.get(), transform );
215 
216  const QgsMeshDatasetGroupMetadata metadata = layer.dataProvider()->datasetGroupMetadata( datasetIndex );
217  QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
218  const int count = QgsMeshLayerUtils::datasetValuesCount( nativeMesh.get(), scalarDataType );
219  QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
220  &layer,
221  datasetIndex,
222  0,
223  count );
224  if ( !vals.isValid() )
225  return nullptr;
226 
227  QVector<double> datasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
228  QgsMeshDataBlock activeFaceFlagValues = layer.dataProvider()->areFacesActive(
229  datasetIndex,
230  0,
231  nativeMesh->faces.count() );
232 
233  QgsMeshLayerInterpolator interpolator(
234  *( triangularMesh.get() ),
235  datasetValues,
236  activeFaceFlagValues,
237  scalarDataType,
238  renderContext,
239  QSize( widthPixel, heightPixel )
240  );
241 
242  return interpolator.block( 0, extent, widthPixel, heightPixel, feedback );
243 }
qgsmeshlayerutils.h
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsPointXY::y
double y
Definition: qgspointxy.h:48
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:102
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:58
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
qgsmaptopixel.h
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
qgscoordinatetransformcontext.h
QgsMeshDataSourceInterface::populateMesh
virtual void populateMesh(QgsMesh *mesh) const =0
Populates the mesh vertices, edges and faces.
qgis.h
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
qgsvector.h
qgspoint.h
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsMeshLayer::dataProvider
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Definition: qgsmeshlayer.cpp:156
qgsrasterinterface.h
qgsmeshlayerinterpolator.h
QgsMeshUtils::exportRasterBlock
CORE_EXPORT QgsRasterBlock * exportRasterBlock(const QgsMeshLayer &layer, const QgsMeshDatasetIndex &datasetIndex, const QgsCoordinateReferenceSystem &destinationCrs, const QgsCoordinateTransformContext &transformContext, double mapUnitsPerPixel, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Exports mesh layer's dataset values as raster block.
Definition: qgsmeshlayerinterpolator.cpp:179
QgsMeshDatasetIndex
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
Definition: qgsmeshdataset.h:47
QgsRenderContext::setExtent
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
Definition: qgsrendercontext.h:434
QgsRenderContext::setCoordinateTransform
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
Definition: qgsrendercontext.cpp:271
QgsMeshLayer
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:95
QgsMeshDatasetIndex::isValid
bool isValid() const
Returns whether index is valid, ie at least groups is set.
Definition: qgsmeshdataset.cpp:36
QgsRenderContext::setMapToPixel
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
Definition: qgsrendercontext.h:420
qgscoordinatetransform.h
QgsMeshFace
QVector< int > QgsMeshFace
List of vertex indexes.
Definition: qgsmeshdataprovider.h:41
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
qgsmeshlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsMeshDatasetGroupMetadata::dataType
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
Definition: qgsmeshdataset.cpp:171
QgsFeedback::isCanceled
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
QgsRectangle::intersects
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:328
QgsMeshDatasetGroupMetadata
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
Definition: qgsmeshdataset.h:350
QgsRasterInterface
Base class for processing filters like renderers, reprojector, resampler etc.
Definition: qgsrasterinterface.h:117
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsMeshDatasetGroupMetadata::DataType
DataType
Location of where data is specified for datasets in the dataset group.
Definition: qgsmeshdataset.h:355
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsRasterBlockFeedback
Feedback object tailored for raster block reading.
Definition: qgsrasterinterface.h:41
QgsMeshDataBlock
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
Definition: qgsmeshdataset.h:136
QgsTriangularMesh
Triangular/Derived Mesh is mesh with vertices in map coordinates.
Definition: qgstriangularmesh.h:50
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
qgsmeshdataprovider.h
QgsMeshDatasetSourceInterface::areFacesActive
virtual QgsMeshDataBlock areFacesActive(QgsMeshDatasetIndex index, int faceIndex, int count) const =0
Returns whether the faces are active for particular dataset.
QgsMeshDatasetSourceInterface::datasetGroupMetadata
virtual QgsMeshDatasetGroupMetadata datasetGroupMetadata(int groupIndex) const =0
Returns dataset group metadata.
QgsRasterBlock
Raster data container.
Definition: qgsrasterblock.h:37
qgspointxy.h
QgsMeshDataBlock::isValid
bool isValid() const
Whether the block is valid.
Definition: qgsmeshdataset.cpp:261
Qgis::Float64
@ Float64
Sixty four bit floating point (double)
Definition: qgis.h:110