QGIS API Documentation  3.23.0-Master (dd0cd13a00)
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 #include <QSet>
20 #include <QPair>
21 #include <QLinearGradient>
22 #include <QBrush>
23 #include <QPointer>
24 #include <algorithm>
25 
26 #include "qgsmeshlayerrenderer.h"
27 
28 #include "qgsfield.h"
29 #include "qgslogger.h"
30 #include "qgsmeshlayer.h"
31 #include "qgspointxy.h"
32 #include "qgsrenderer.h"
34 #include "qgsrastershader.h"
36 #include "qgsmeshlayerutils.h"
37 #include "qgsmeshvectorrenderer.h"
38 #include "qgsmeshtracerenderer.h"
39 #include "qgsfillsymbollayer.h"
40 #include "qgssettings.h"
41 #include "qgsstyle.h"
43 #include "qgsmapclippingutils.h"
44 #include "qgscolorrampshader.h"
45 
47  QgsMeshLayer *layer,
48  QgsRenderContext &context )
49  : QgsMapLayerRenderer( layer->id(), &context )
50  , mIsEditable( layer->isEditable() )
51  , mFeedback( new QgsMeshLayerRendererFeedback )
52  , mRendererSettings( layer->rendererSettings() )
53  , mLayerOpacity( layer->opacity() )
54 {
55  // make copies for mesh data
56  // cppcheck-suppress assertWithSideEffect
57  Q_ASSERT( layer->nativeMesh() );
58  // cppcheck-suppress assertWithSideEffect
59  Q_ASSERT( layer->triangularMesh() );
60  // cppcheck-suppress assertWithSideEffect
61  Q_ASSERT( layer->rendererCache() );
62  // cppcheck-suppress assertWithSideEffect
63  Q_ASSERT( layer->dataProvider() );
64 
65  mReadyToCompose = false;
66 
67  // copy native mesh
68  mNativeMesh = *( layer->nativeMesh() );
69  mLayerExtent = layer->extent();
70 
71  // copy triangular mesh
72  copyTriangularMeshes( layer, context );
73 
74  // copy datasets
75  copyScalarDatasetValues( layer );
76  copyVectorDatasetValues( layer );
77 
78  calculateOutputSize();
79 
81 }
82 
83 void QgsMeshLayerRenderer::copyTriangularMeshes( QgsMeshLayer *layer, QgsRenderContext &context )
84 {
85  // handle level of details of mesh
86  const QgsMeshSimplificationSettings simplificationSettings = layer->meshSimplificationSettings();
87  if ( simplificationSettings.isEnabled() )
88  {
89  const double triangleSize = simplificationSettings.meshResolution() * context.mapToPixel().mapUnitsPerPixel();
90  mTriangularMesh = *( layer->triangularMesh( triangleSize ) );
91  mIsMeshSimplificationActive = true;
92  }
93  else
94  {
95  mTriangularMesh = *( layer->triangularMesh() );
96  }
97 }
98 
100 {
101  return mFeedback.get();
102 }
103 
104 void QgsMeshLayerRenderer::calculateOutputSize()
105 {
106  // figure out image size
107  const QgsRenderContext &context = *renderContext();
108  const QgsRectangle extent = context.mapExtent();
109  const QgsMapToPixel mapToPixel = context.mapToPixel();
110  const QgsRectangle screenBBox = QgsMeshLayerUtils::boundingBoxToScreenRectangle( mapToPixel, extent );
111  const int width = int( screenBBox.width() );
112  const int height = int( screenBBox.height() );
113  mOutputSize = QSize( width, height );
114 }
115 
116 void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
117 {
118  QgsMeshDatasetIndex datasetIndex;
119  if ( renderContext()->isTemporal() )
120  datasetIndex = layer->activeScalarDatasetAtTime( renderContext()->temporalRange() );
121  else
122  datasetIndex = layer->staticScalarDatasetIndex();
123 
124  // Find out if we can use cache up to date. If yes, use it and return
125  const int datasetGroupCount = layer->datasetGroupCount();
127  QgsMeshLayerRendererCache *cache = layer->rendererCache();
128  if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
129  ( cache->mActiveScalarDatasetIndex == datasetIndex ) &&
130  ( cache->mDataInterpolationMethod == method ) &&
131  ( QgsMesh3dAveragingMethod::equals( cache->mScalarAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
132  )
133  {
134  mScalarDatasetValues = cache->mScalarDatasetValues;
135  mScalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
136  mScalarDataType = cache->mScalarDataType;
137  mScalarDatasetMinimum = cache->mScalarDatasetMinimum;
138  mScalarDatasetMaximum = cache->mScalarDatasetMaximum;
139  return;
140  }
141 
142  // Cache is not up-to-date, gather data
143  if ( datasetIndex.isValid() )
144  {
145  const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex.group() );
146  mScalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
147 
148  // populate scalar values
149  const int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mScalarDataType );
150  const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
151  layer,
152  datasetIndex,
153  0,
154  count );
155 
156  if ( vals.isValid() )
157  {
158  // vals could be scalar or vectors, for contour rendering we want always magnitude
159  mScalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
160  }
161  else
162  {
163  mScalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
164  }
165 
166  // populate face active flag, always defined on faces
168  datasetIndex,
169  0,
170  mNativeMesh.faces.count() );
171 
172  // for data on faces, there could be request to interpolate the data to vertices
173  if ( method != QgsMeshRendererScalarSettings::None )
174  {
175  if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
176  {
177  mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnVertices;
178  mScalarDatasetValues = QgsMeshLayerUtils::interpolateFromFacesData(
180  &mNativeMesh,
183  method
184  );
185  }
186  else if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
187  {
188  mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
189  mScalarDatasetValues = QgsMeshLayerUtils::resampleFromVerticesToFaces(
191  &mNativeMesh,
194  method
195  );
196  }
197  }
198 
199  const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
200  mScalarDatasetMinimum = datasetMetadata.minimum();
201  mScalarDatasetMaximum = datasetMetadata.maximum();
202  }
203 
204  // update cache
205  cache->mDatasetGroupsCount = datasetGroupCount;
206  cache->mActiveScalarDatasetIndex = datasetIndex;
207  cache->mDataInterpolationMethod = method;
208  cache->mScalarDatasetValues = mScalarDatasetValues;
209  cache->mScalarActiveFaceFlagValues = mScalarActiveFaceFlagValues;
210  cache->mScalarDataType = mScalarDataType;
211  cache->mScalarDatasetMinimum = mScalarDatasetMinimum;
212  cache->mScalarDatasetMaximum = mScalarDatasetMaximum;
213  cache->mScalarAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
214 }
215 
216 
217 void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
218 {
219  QgsMeshDatasetIndex datasetIndex;
220  if ( renderContext()->isTemporal() )
221  datasetIndex = layer->activeVectorDatasetAtTime( renderContext()->temporalRange() );
222  else
223  datasetIndex = layer->staticVectorDatasetIndex();
224 
225  // Find out if we can use cache up to date. If yes, use it and return
226  const int datasetGroupCount = layer->datasetGroupCount();
227  QgsMeshLayerRendererCache *cache = layer->rendererCache();
228  if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
229  ( cache->mActiveVectorDatasetIndex == datasetIndex ) &&
230  ( QgsMesh3dAveragingMethod::equals( cache->mVectorAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
231  )
232  {
233  mVectorDatasetValues = cache->mVectorDatasetValues;
234  mVectorDatasetValuesMag = cache->mVectorDatasetValuesMag;
235  mVectorDatasetMagMinimum = cache->mVectorDatasetMagMinimum;
236  mVectorDatasetMagMaximum = cache->mVectorDatasetMagMaximum;
237  mVectorDatasetGroupMagMinimum = cache->mVectorDatasetMagMinimum;
238  mVectorDatasetGroupMagMaximum = cache->mVectorDatasetMagMaximum;
239  mVectorDataType = cache->mVectorDataType;
240  return;
241  }
242 
243  // Cache is not up-to-date, gather data
244  if ( datasetIndex.isValid() )
245  {
246  const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex );
247 
248  const bool isScalar = metadata.isScalar();
249  if ( isScalar )
250  {
251  QgsDebugMsg( QStringLiteral( "Dataset has no vector values" ) );
252  }
253  else
254  {
255  mVectorDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
256 
259 
260  const int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mVectorDataType );
261  mVectorDatasetValues = QgsMeshLayerUtils::datasetValues(
262  layer,
263  datasetIndex,
264  0,
265  count );
266 
268  mVectorDatasetValuesMag = QgsMeshLayerUtils::calculateMagnitudes( mVectorDatasetValues );
269  else
270  mVectorDatasetValuesMag = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
271 
272  const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
273  mVectorDatasetMagMinimum = datasetMetadata.minimum();
274  mVectorDatasetMagMaximum = datasetMetadata.maximum();
275  }
276  }
277 
278  // update cache
279  cache->mDatasetGroupsCount = datasetGroupCount;
280  cache->mActiveVectorDatasetIndex = datasetIndex;
281  cache->mVectorDatasetValues = mVectorDatasetValues;
282  cache->mVectorDatasetValuesMag = mVectorDatasetValuesMag;
283  cache->mVectorDatasetMagMinimum = mVectorDatasetMagMinimum;
284  cache->mVectorDatasetMagMaximum = mVectorDatasetMagMaximum;
285  cache->mVectorDatasetGroupMagMinimum = mVectorDatasetMagMinimum;
286  cache->mVectorDatasetGroupMagMaximum = mVectorDatasetMagMaximum;
287  cache->mVectorDataType = mVectorDataType;
288  cache->mVectorAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
289 }
290 
292 {
293  mReadyToCompose = false;
294  const QgsScopedQPainterState painterState( renderContext()->painter() );
295  if ( !mClippingRegions.empty() )
296  {
297  bool needsPainterClipPath = false;
299  if ( needsPainterClipPath )
300  renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
301  }
302 
303  renderScalarDataset();
304  mReadyToCompose = true;
305  renderMesh();
306  renderVectorDataset();
307 
308  return !renderContext()->renderingStopped();
309 }
310 
312 {
313  return renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) );
314 }
315 
316 void QgsMeshLayerRenderer::renderMesh()
317 {
318  if ( !mRendererSettings.nativeMeshSettings().isEnabled() && !mIsEditable &&
321  return;
322 
323  // triangular mesh
324  const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( renderContext()->mapExtent() );
326  {
327  renderFaceMesh(
330  trianglesInExtent );
331  }
332 
333  // native mesh
334  if ( ( mRendererSettings.nativeMeshSettings().isEnabled() || mIsEditable ) &&
336  {
337  const QSet<int> nativeFacesInExtent = QgsMeshUtils::nativeFacesFromTriangles( trianglesInExtent,
339 
340  renderFaceMesh(
343  nativeFacesInExtent.values() );
344  }
345 
346  // edge mesh
348  {
349  const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( renderContext()->mapExtent() );
350  renderEdgeMesh( mRendererSettings.edgeMeshSettings(), edgesInExtent );
351  }
352 }
353 
354 static QPainter *_painterForMeshFrame( QgsRenderContext &context, const QgsMeshRendererMeshSettings &settings )
355 {
356  // Set up the render configuration options
357  QPainter *painter = context.painter();
358 
359  painter->save();
360  context.setPainterFlagsUsingContext( painter );
361 
362  QPen pen = painter->pen();
363  pen.setCapStyle( Qt::FlatCap );
364  pen.setJoinStyle( Qt::MiterJoin );
365 
366  const double penWidth = context.convertToPainterUnits( settings.lineWidth(), settings.lineWidthUnit() );
367  pen.setWidthF( penWidth );
368  pen.setColor( settings.color() );
369  painter->setPen( pen );
370  return painter;
371 }
372 
373 void QgsMeshLayerRenderer::renderEdgeMesh( const QgsMeshRendererMeshSettings &settings, const QList<int> &edgesInExtent )
374 {
375  Q_ASSERT( settings.isEnabled() );
376 
377  if ( !mTriangularMesh.contains( QgsMesh::ElementType::Edge ) )
378  return;
379 
380  QgsRenderContext &context = *renderContext();
381  QPainter *painter = _painterForMeshFrame( context, settings );
382 
383  const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
384  const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
385 
386  for ( const int i : edgesInExtent )
387  {
388  if ( context.renderingStopped() )
389  break;
390 
391  if ( i >= edges.size() )
392  continue;
393 
394  const QgsMeshEdge &edge = edges[i];
395  const int startVertexIndex = edge.first;
396  const int endVertexIndex = edge.second;
397 
398  if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
399  continue;
400 
401  const QgsMeshVertex &startVertex = vertices[startVertexIndex];
402  const QgsMeshVertex &endVertex = vertices[endVertexIndex];
403  const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
404  const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
405  painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
406  }
407  painter->restore();
408 };
409 
410 void QgsMeshLayerRenderer::renderFaceMesh(
411  const QgsMeshRendererMeshSettings &settings,
412  const QVector<QgsMeshFace> &faces,
413  const QList<int> &facesInExtent )
414 {
415  Q_ASSERT( settings.isEnabled() || mIsEditable );
416 
417  if ( !mTriangularMesh.contains( QgsMesh::ElementType::Face ) )
418  return;
419 
420  QgsRenderContext &context = *renderContext();
421  QPainter *painter = _painterForMeshFrame( context, settings );
422 
423  const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices(); //Triangular mesh vertices contains also native mesh vertices
424  QSet<QPair<int, int>> drawnEdges;
425 
426  for ( const int i : facesInExtent )
427  {
428  if ( context.renderingStopped() )
429  break;
430 
431  if ( i >= faces.count() )
432  continue;
433 
434  const QgsMeshFace &face = faces[i];
435  if ( face.size() < 2 )
436  continue;
437 
438  for ( int j = 0; j < face.size(); ++j )
439  {
440  const int startVertexId = face[j];
441  const int endVertexId = face[( j + 1 ) % face.size()];
442  const QPair<int, int> thisEdge( startVertexId, endVertexId );
443  const QPair<int, int> thisEdgeReversed( endVertexId, startVertexId );
444  if ( drawnEdges.contains( thisEdge ) || drawnEdges.contains( thisEdgeReversed ) )
445  continue;
446  drawnEdges.insert( thisEdge );
447  drawnEdges.insert( thisEdgeReversed );
448 
449  const QgsMeshVertex &startVertex = vertices[startVertexId];
450  const QgsMeshVertex &endVertex = vertices[endVertexId];
451  const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
452  const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
453  painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
454  }
455  }
456 
457  painter->restore();
458 }
459 
460 void QgsMeshLayerRenderer::renderScalarDataset()
461 {
462  if ( mScalarDatasetValues.isEmpty() )
463  return; // activeScalarDataset == NO_ACTIVE_MESH_DATASET
464 
465  if ( std::isnan( mScalarDatasetMinimum ) || std::isnan( mScalarDatasetMaximum ) )
466  return; // only NODATA values
467 
468  const int groupIndex = mRendererSettings.activeScalarDatasetGroup();
469  if ( groupIndex < 0 )
470  return; // no shader
471 
472  const QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( groupIndex );
473 
474  if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Face ) ) &&
475  ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnEdges ) )
476  {
477  renderScalarDatasetOnFaces( scalarSettings );
478  }
479 
480  if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Edge ) ) &&
481  ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnFaces ) )
482  {
483  renderScalarDatasetOnEdges( scalarSettings );
484  }
485 }
486 
487 void QgsMeshLayerRenderer::renderScalarDatasetOnEdges( const QgsMeshRendererScalarSettings &scalarSettings )
488 {
489  QgsRenderContext &context = *renderContext();
490  const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
491  const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
492  const QList<int> egdesInExtent = mTriangularMesh.edgeIndexesForRectangle( context.mapExtent() );
493 
494  QgsInterpolatedLineRenderer edgePlotter;
495  edgePlotter.setInterpolatedColor( QgsInterpolatedLineColor( scalarSettings.colorRampShader() ) );
496  edgePlotter.setInterpolatedWidth( QgsInterpolatedLineWidth( scalarSettings.edgeStrokeWidth() ) );
497  edgePlotter.setWidthUnit( scalarSettings.edgeStrokeWidthUnit() );
498 
499  for ( const int i : egdesInExtent )
500  {
501  if ( context.renderingStopped() )
502  break;
503 
504  if ( i >= edges.size() )
505  continue;
506 
507  const QgsMeshEdge &edge = edges[i];
508  const int startVertexIndex = edge.first;
509  const int endVertexIndex = edge.second;
510 
511  if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
512  continue;
513 
514  const QgsMeshVertex &startVertex = vertices[startVertexIndex];
515  const QgsMeshVertex &endVertex = vertices[endVertexIndex];
516 
517  if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges )
518  {
519  edgePlotter.render( mScalarDatasetValues[i], mScalarDatasetValues[i], startVertex, endVertex, context );
520  }
521  else
522  {
523  edgePlotter.render( mScalarDatasetValues[startVertexIndex], mScalarDatasetValues[endVertexIndex], startVertex, endVertex, context );
524  }
525  }
526 }
527 
528 QColor QgsMeshLayerRenderer::colorAt( QgsColorRampShader *shader, double val ) const
529 {
530  int r, g, b, a;
531  if ( shader->shade( val, &r, &g, &b, &a ) )
532  {
533  return QColor( r, g, b, a );
534  }
535  return QColor();
536 }
537 
538 QgsPointXY QgsMeshLayerRenderer::fractionPoint( const QgsPointXY &p1, const QgsPointXY &p2, double fraction ) const
539 {
540  const QgsPointXY pt( p1.x() + fraction * ( p2.x() - p1.x() ),
541  p1.y() + fraction * ( p2.y() - p1.y() ) );
542  return pt;
543 }
544 
545 void QgsMeshLayerRenderer::renderScalarDatasetOnFaces( const QgsMeshRendererScalarSettings &scalarSettings )
546 {
547  QgsRenderContext &context = *renderContext();
548 
549  QgsColorRampShader *fcn = new QgsColorRampShader( scalarSettings.colorRampShader() );
550  QgsRasterShader *sh = new QgsRasterShader();
551  sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
552  QgsMeshLayerInterpolator interpolator( mTriangularMesh,
556  context,
557  mOutputSize );
558  interpolator.setSpatialIndexActive( mIsMeshSimplificationActive );
559  QgsSingleBandPseudoColorRenderer renderer( &interpolator, 0, sh ); // takes ownership of sh
560  renderer.setClassificationMin( scalarSettings.classificationMinimum() );
561  renderer.setClassificationMax( scalarSettings.classificationMaximum() );
562  renderer.setOpacity( scalarSettings.opacity() );
563 
564  std::unique_ptr<QgsRasterBlock> bl( renderer.block( 0, context.mapExtent(), mOutputSize.width(), mOutputSize.height(), mFeedback.get() ) );
565  const QImage img = bl->image();
566 
567  context.painter()->drawImage( 0, 0, img );
568 }
569 
570 void QgsMeshLayerRenderer::renderVectorDataset()
571 {
572  const int groupIndex = mRendererSettings.activeVectorDatasetGroup();
573  if ( groupIndex < 0 )
574  return;
575 
576  if ( !mVectorDatasetValues.isValid() )
577  return; // no data at all
578 
579  if ( std::isnan( mVectorDatasetMagMinimum ) || std::isnan( mVectorDatasetMagMaximum ) )
580  return; // only NODATA values
581 
582  if ( !( mVectorDatasetMagMaximum > 0 ) )
583  return; //all vector are null vector
584 
585  std::unique_ptr<QgsMeshVectorRenderer> renderer( QgsMeshVectorRenderer::makeVectorRenderer(
593  mRendererSettings.vectorSettings( groupIndex ),
594  *renderContext(),
595  mLayerExtent,
596  mOutputSize ) );
597 
598  if ( renderer )
599  renderer->draw();
600 }
601 
@ UseAdvancedEffects
Enable layer opacity and blending effects.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Class defining color to render mesh datasets.
Represents a simple line renderer with width and color varying depending on values.
void setInterpolatedColor(const QgsInterpolatedLineColor &strokeColoring)
Sets the stroke color used to render.
void setInterpolatedWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render.
void render(double value1, double value2, const QgsPointXY &point1, const QgsPointXY &point2, QgsRenderContext &context) const
Renders a line in the context between point1 and point2 with color and width that vary depending on v...
void setWidthUnit(QgsUnitTypes::RenderUnit strokeWidthUnit)
Sets the unit of the stroke width.
Represents a width than can vary depending on values.
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, QgsMapLayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
Base class for utility classes that encapsulate information necessary for rendering of map layers.
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapUnitsPerPixel() const
Returns the current map units per pixel.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
virtual QgsMesh3dAveragingMethod * clone() const =0
Clone the instance.
static bool equals(const QgsMesh3dAveragingMethod *a, const QgsMesh3dAveragingMethod *b)
Returns whether two methods equal.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
bool isValid() const
Whether the block is valid.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
bool isScalar() const
Returns whether dataset group has scalar data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is valid or ...
double maximum() const
Returns maximum scalar value/vector magnitude present for the dataset.
double minimum() const
Returns minimum scalar value/vector magnitude present for the dataset.
QgsMeshDatasetGroupMetadata::DataType mScalarDataType
QgsTriangularMesh mTriangularMesh
QgsMeshLayerRenderer(QgsMeshLayer *layer, QgsRenderContext &context)
Ctor.
QVector< double > mScalarDatasetValues
std::unique_ptr< QgsMeshLayerRendererFeedback > mFeedback
feedback class for cancellation
QgsMeshDataBlock mScalarActiveFaceFlagValues
bool render() override
Do the rendering (based on data stored in the class).
QVector< double > mVectorDatasetValuesMag
QgsMeshRendererSettings mRendererSettings
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
QgsMeshDatasetGroupMetadata::DataType mVectorDataType
QList< QgsMapClippingRegion > mClippingRegions
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr)
QgsMeshDataBlock mVectorDatasetValues
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:97
QgsRectangle extent() const override
Returns the extent of the layer.
int datasetGroupCount() const
Returns the dataset groups count handle by the layer.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange) const
Returns dataset index from active scalar group depending on the time range.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QgsMeshDatasetIndex staticVectorDatasetIndex() const
Returns the static vector dataset index that is rendered if the temporal properties is not active.
QgsMeshSimplificationSettings meshSimplificationSettings() const
Returns mesh simplification settings.
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
QgsMeshDataBlock areFacesActive(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns whether the faces are active for particular dataset.
QgsMeshDatasetIndex staticScalarDatasetIndex() const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
QgsMeshDatasetMetadata datasetMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset metadata.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
QgsMeshLayerRendererCache * rendererCache()
Returns native mesh (nullptr before rendering)
Represents a mesh renderer settings for mesh object.
QColor color() const
Returns color used for rendering.
QgsUnitTypes::RenderUnit lineWidthUnit() const
Returns units of the width of the mesh frame.
double lineWidth() const
Returns line width used for rendering (in millimeters)
bool isEnabled() const
Returns whether mesh structure rendering is enabled.
Represents a mesh renderer settings for scalar datasets.
double opacity() const
Returns opacity.
QgsColorRampShader colorRampShader() const
Returns color ramp shader function.
double classificationMinimum() const
Returns min value used for creation of the color ramp shader.
DataResamplingMethod
Resampling of value from dataset.
DataResamplingMethod dataResamplingMethod() const
Returns the type of interpolation to use to convert face defined datasets to values on vertices.
double classificationMaximum() const
Returns max value used for creation of the color ramp shader.
QgsUnitTypes::RenderUnit edgeStrokeWidthUnit() const
Returns the stroke width unit used to render edges scalar dataset.
QgsInterpolatedLineWidth edgeStrokeWidth() const
Returns the stroke width used to render edges scalar dataset.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
int activeVectorDatasetGroup() const
Returns the active vector dataset group.
int activeScalarDatasetGroup() const
Returns the active scalar dataset group.
QgsMesh3dAveragingMethod * averagingMethod() const
Returns averaging method for conversion of 3d stacked mesh data to 2d data.
QgsMeshRendererVectorSettings vectorSettings(int groupIndex) const
Returns renderer settings.
QgsMeshRendererMeshSettings edgeMeshSettings() const
Returns edge mesh renderer settings.
QgsMeshRendererMeshSettings nativeMeshSettings() const
Returns native mesh renderer settings.
QgsMeshRendererMeshSettings triangularMeshSettings() const
Returns triangular mesh renderer settings.
Represents an overview renderer settings.
bool isEnabled() const
Returns if the overview is active.
int meshResolution() const
Returns the mesh resolution i.e., the minimum size (average) of triangles in pixels.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
Interface for all raster shaders.
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
bool testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Scoped object for saving and restoring a QPainter object's state.
Raster renderer pipe for single band pseudocolor.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
int levelOfDetail() const
Returns the corresponding index of level of detail on which this mesh is associated.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains mesh elements of given type.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
CORE_EXPORT QSet< int > nativeFacesFromTriangles(const QList< int > &triangleIndexes, const QVector< int > &trianglesToNativeFaces)
Returns unique native faces indexes from list of triangle indexes.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1504
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
QVector< QgsMeshFace > faces