QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsmeshlayerrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerrenderer.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 
18 #include <memory>
19 
20 #include "qgsmeshlayerrenderer.h"
21 
22 #include "qgsfield.h"
23 #include "qgslogger.h"
24 #include "qgsmeshlayer.h"
25 #include "qgspointxy.h"
26 #include "qgsrenderer.h"
28 #include "qgssymbol.h"
30 #include "qgsrastershader.h"
32 #include "qgsmeshvectorrenderer.h"
33 #include "qgsfillsymbollayer.h"
34 
35 
36 
38  : QgsMapLayerRenderer( layer->id() )
39  , mFeedback( new QgsMeshLayerRendererFeedback )
40  , mContext( context )
41  , mRendererNativeMeshSettings( layer->rendererNativeMeshSettings() )
42  , mRendererTriangularMeshSettings( layer->rendererTriangularMeshSettings() )
43  , mRendererScalarSettings( layer-> rendererScalarSettings() )
44  , mRendererVectorSettings( layer-> rendererVectorSettings() )
45 {
46  // make copies for mesh data
47  Q_ASSERT( layer->nativeMesh() );
48  Q_ASSERT( layer->triangularMesh() );
49  mNativeMesh = *( layer->nativeMesh() );
50  mTriangularMesh = *( layer->triangularMesh() );
51 
54 
55  copyScalarDatasetValues( layer );
56  copyVectorDatasetValues( layer );
57 
58  calculateOutputSize();
59 }
60 
62 {
63  return mFeedback.get();
64 }
65 
66 void QgsMeshLayerRenderer::calculateOutputSize()
67 {
68  // figure out image size
69  QgsRectangle extent = mContext.extent(); // this is extent in layer's coordinate system - but we need it in map coordinate system
70  QgsMapToPixel mapToPixel = mContext.mapToPixel();
71  QgsPointXY topleft = mapToPixel.transform( extent.xMinimum(), extent.yMaximum() );
72  QgsPointXY bottomright = mapToPixel.transform( extent.xMaximum(), extent.yMinimum() );
73  int width = int( bottomright.x() - topleft.x() );
74  int height = int( bottomright.y() - topleft.y() );
75  mOutputSize = QSize( width, height );
76 }
77 
78 void QgsMeshLayerRenderer::createMeshSymbol( std::unique_ptr<QgsSymbol> &symbol,
79  const QgsMeshRendererMeshSettings &settings )
80 {
81  if ( settings.isEnabled() )
82  {
84  l1 << new QgsSimpleFillSymbolLayer( Qt::white,
85  Qt::NoBrush,
86  settings.color(),
87  Qt::SolidLine,
88  settings.lineWidth() );
89  symbol.reset( new QgsFillSymbol( l1 ) );
90  }
91 }
92 
93 
94 void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
95 {
96  int datasetIndex = layer->activeScalarDataset();
97  if ( datasetIndex != NO_ACTIVE_MESH_DATASET )
98  {
99  const QgsMeshDatasetMetadata metadata = layer->dataProvider()->datasetMetadata( datasetIndex );
100  mScalarDataOnVertices = metadata.isOnVertices();
101  int count;
102  if ( mScalarDataOnVertices )
103  count = mNativeMesh.vertices.count();
104  else
105  count = mNativeMesh.faces.count();
106 
107  mScalarDatasetValues.resize( count );
108  for ( int i = 0; i < count; ++i )
109  {
110  double v = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
111  mScalarDatasetValues[i] = v;
112  }
113  }
114 }
115 
116 void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
117 {
118  int datasetIndex = layer->activeVectorDataset();
119  if ( datasetIndex != NO_ACTIVE_MESH_DATASET )
120  {
121  const QgsMeshDatasetMetadata metadata = layer->dataProvider()->datasetMetadata( datasetIndex );
122 
123  bool isScalar = metadata.isScalar();
124  if ( isScalar )
125  {
126  QgsDebugMsg( "Dataset has no vector values" );
127  }
128  else
129  {
130  mVectorDataOnVertices = metadata.isOnVertices();
131  int count;
132  if ( mVectorDataOnVertices )
133  count = mNativeMesh.vertices.count();
134  else
135  count = mNativeMesh.faces.count();
136 
137  mVectorDatasetValuesX.resize( count );
138  mVectorDatasetValuesY.resize( count );
139  mVectorDatasetValuesMag.resize( count );
140  for ( int i = 0; i < count; ++i )
141  {
142  double x = layer->dataProvider()->datasetValue( datasetIndex, i ).x();
143  mVectorDatasetValuesX[i] = x;
144 
145  double y = layer->dataProvider()->datasetValue( datasetIndex, i ).y();
146  mVectorDatasetValuesY[i] = y;
147 
148  double mag = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
149  mVectorDatasetValuesMag[i] = mag;
150  }
151  }
152  }
153 }
154 
156 {
157 
158  renderScalarDataset();
159 
160  renderMesh( mNativeMeshSymbol, mNativeMesh.faces ); // native mesh
161  renderMesh( mTriangularMeshSymbol, mTriangularMesh.triangles() ); // triangular mesh
162 
163  renderVectorDataset();
164 
165  return true;
166 }
167 
168 void QgsMeshLayerRenderer::renderMesh( const std::unique_ptr<QgsSymbol> &symbol, const QVector<QgsMeshFace> &faces )
169 {
170  if ( !symbol )
171  return;
172 
173  QgsFields fields;
174  QgsSingleSymbolRenderer renderer( symbol->clone() );
175  renderer.startRender( mContext, fields );
176 
177  for ( int i = 0; i < faces.size(); ++i )
178  {
179  if ( mContext.renderingStopped() )
180  break;
181 
182  const QgsMeshFace &face = faces[i];
183  QgsFeature feat;
184  feat.setFields( fields );
185  QVector<QgsPointXY> ring;
186  for ( int j = 0; j < face.size(); ++j )
187  {
188  int vertex_id = face[j];
189  Q_ASSERT( vertex_id < mTriangularMesh.vertices().size() ); //Triangular mesh vertices contains also native mesh vertices
190  const QgsPoint &vertex = mTriangularMesh.vertices()[vertex_id];
191  ring.append( vertex );
192  }
193  QgsPolygonXY polygon;
194  polygon.append( ring );
195  QgsGeometry geom = QgsGeometry::fromPolygonXY( polygon );
196  feat.setGeometry( geom );
197  renderer.renderFeature( feat, mContext );
198  }
199 
200  renderer.stopRender( mContext );
201 }
202 
203 void QgsMeshLayerRenderer::renderScalarDataset()
204 {
205  if ( mScalarDatasetValues.isEmpty() )
206  return;
207 
208  // do not render if magnitude is outside of the filtered range (if filtering is enabled)
209  double vMin = mRendererScalarSettings.minValue();
210  if ( std::isnan( vMin ) )
211  vMin = *std::min_element( mScalarDatasetValues.constBegin(), mScalarDatasetValues.constEnd() );
212 
213 
214  double vMax = mRendererScalarSettings.maxValue();
215  if ( std::isnan( vMax ) )
216  vMax = *std::max_element( mScalarDatasetValues.constBegin(), mScalarDatasetValues.constEnd() );
217 
218  QList<QgsColorRampShader::ColorRampItem> lst;
219  lst << QgsColorRampShader::ColorRampItem( vMin, mRendererScalarSettings.minColor(), QString::number( vMin ) );
220  lst << QgsColorRampShader::ColorRampItem( vMax, mRendererScalarSettings.maxColor(), QString::number( vMax ) );
221 
222  QgsColorRampShader *fcn = new QgsColorRampShader( vMin, vMax );
223  fcn->setColorRampItemList( lst );
224  QgsRasterShader *sh = new QgsRasterShader( vMin, vMax );
225  sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
226  QgsMeshLayerInterpolator interpolator( mTriangularMesh, mScalarDatasetValues, mScalarDataOnVertices, mContext, mOutputSize );
227  QgsSingleBandPseudoColorRenderer r( &interpolator, 0, sh ); // takes ownership of sh
228  std::unique_ptr<QgsRasterBlock> bl( r.block( 0, mContext.extent(), mOutputSize.width(), mOutputSize.height(), mFeedback.get() ) );
229  QImage img = bl->image();
230 
231  mContext.painter()->drawImage( 0, 0, img );
232 }
233 
234 void QgsMeshLayerRenderer::renderVectorDataset()
235 {
236  if ( mVectorDatasetValuesX.isEmpty() )
237  return;
238 
239  if ( mVectorDatasetValuesX.size() != mVectorDatasetValuesY.size() )
240  return;
241 
242  QgsMeshVectorRenderer renderer( mTriangularMesh,
245 
246  renderer.draw();
247 }
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Interface for all raster shaders.
QVector< double > mVectorDatasetValuesX
double maxValue() const
Returns max scalar value that represents maxColor()
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:155
int activeVectorDataset() const
Returns active vector dataset.
Definition: qgsmeshlayer.h:186
QColor minColor() const
Returns color representing minimum scalar value in the dataset.
bool isScalar() const
Returns whether dataset has scalar data.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
double y
Definition: qgspointxy.h:48
Represents a mesh renderer settings for mesh object.
A class to represent a 2D point.
Definition: qgspointxy.h:43
virtual QgsMeshDatasetMetadata datasetMetadata(int datasetIndex) const =0
Returns dataset metadata.
bool isEnabled() const
Returns whether mesh structure rendering is enabled.
virtual QgsMeshDatasetValue datasetValue(int datasetIndex, int valueIndex) const =0
Returns vector/scalar value associated with the index from the dataset.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:66
bool renderingStopped() const
bool isOnVertices() const
Returns whether dataset data is defined on vertices.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
QVector< double > mScalarDatasetValues
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering)
const int NO_ACTIVE_MESH_DATASET
Definition: qgsmeshlayer.h:29
QVector< double > mVectorDatasetValuesMag
double y() const
Returns y value.
QVector< QgsMeshVertex > vertices
vertices
QgsTriangularMesh mTriangularMesh
Base class for feedback objects to be used for cancelation of something running in a worker thread...
Definition: qgsfeedback.h:44
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
double lineWidth() const
Returns line width used for rendering (in millimeters)
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be null)
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QColor maxColor() const
Returns color representing maximum scalar value in the dataset.
bool render() override
Do the rendering (based on data stored in the class)
const QgsRectangle & extent() const
QgsMeshRendererScalarSettings mRendererScalarSettings
double minValue() const
Returns min scalar value that represents minColor()
Raster renderer pipe for single band pseudocolor.
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
std::unique_ptr< QgsSymbol > mTriangularMeshSymbol
QgsMeshDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
QVector< double > mVectorDatasetValuesY
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
std::unique_ptr< QgsMeshLayerRendererFeedback > mFeedback
feedback class for cancelation
double x
Definition: qgspointxy.h:47
QgsMeshRendererVectorSettings mRendererVectorSettings
QgsRenderContext & mContext
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
int activeScalarDataset() const
Returns active scalar dataset.
Definition: qgsmeshlayer.h:177
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
QgsMeshLayerRenderer(QgsMeshLayer *layer, QgsRenderContext &context)
Ctor.
QColor color() const
Returns color used for rendering.
QVector< int > QgsMeshFace
List of vertex indexes.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
QgsMeshRendererMeshSettings mRendererNativeMeshSettings
Base class for utility classes that encapsulate information necessary for rendering of map layers...
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:90
QVector< QgsMeshFace > faces
faces
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is vector or...
QgsMeshRendererMeshSettings mRendererTriangularMeshSettings
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map CRS.
QgsTriangularMesh * triangularMesh()
Returns triangular mesh (nullptr before rendering)
std::unique_ptr< QgsSymbol > mNativeMeshSymbol
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
double x() const
Returns x value.