Branch data Line data Source code
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"
33 : : #include "qgssinglebandpseudocolorrenderer.h"
34 : : #include "qgsrastershader.h"
35 : : #include "qgsmeshlayerinterpolator.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"
42 : : #include "qgsmeshdataprovidertemporalcapabilities.h"
43 : : #include "qgsmapclippingutils.h"
44 : : #include "qgscolorrampshader.h"
45 : :
46 : 0 : QgsMeshLayerRenderer::QgsMeshLayerRenderer(
47 : : QgsMeshLayer *layer,
48 : : QgsRenderContext &context )
49 : 0 : : QgsMapLayerRenderer( layer->id(), &context )
50 : 0 : , mFeedback( new QgsMeshLayerRendererFeedback )
51 : 0 : , mRendererSettings( layer->rendererSettings() )
52 : 0 : , mLayerOpacity( layer->opacity() )
53 : 0 : {
54 : : // make copies for mesh data
55 : : // cppcheck-suppress assertWithSideEffect
56 : : Q_ASSERT( layer->nativeMesh() );
57 : : // cppcheck-suppress assertWithSideEffect
58 : : Q_ASSERT( layer->triangularMesh() );
59 : : // cppcheck-suppress assertWithSideEffect
60 : : Q_ASSERT( layer->rendererCache() );
61 : : // cppcheck-suppress assertWithSideEffect
62 : : Q_ASSERT( layer->dataProvider() );
63 : :
64 : 0 : mReadyToCompose = false;
65 : :
66 : : // copy native mesh
67 : 0 : mNativeMesh = *( layer->nativeMesh() );
68 : 0 : mLayerExtent = layer->extent();
69 : :
70 : : // copy triangular mesh
71 : 0 : copyTriangularMeshes( layer, context );
72 : :
73 : : // copy datasets
74 : 0 : copyScalarDatasetValues( layer );
75 : 0 : copyVectorDatasetValues( layer );
76 : :
77 : 0 : calculateOutputSize();
78 : :
79 : 0 : mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
80 : 0 : }
81 : :
82 : 0 : void QgsMeshLayerRenderer::copyTriangularMeshes( QgsMeshLayer *layer, QgsRenderContext &context )
83 : : {
84 : : // handle level of details of mesh
85 : 0 : QgsMeshSimplificationSettings simplificationSettings = layer->meshSimplificationSettings();
86 : 0 : if ( simplificationSettings.isEnabled() )
87 : : {
88 : 0 : double triangleSize = simplificationSettings.meshResolution() * context.mapToPixel().mapUnitsPerPixel();
89 : 0 : mTriangularMesh = *( layer->triangularMesh( triangleSize ) );
90 : 0 : mIsMeshSimplificationActive = true;
91 : 0 : }
92 : : else
93 : : {
94 : 0 : mTriangularMesh = *( layer->triangularMesh() );
95 : : }
96 : 0 : }
97 : :
98 : 0 : QgsFeedback *QgsMeshLayerRenderer::feedback() const
99 : : {
100 : 0 : return mFeedback.get();
101 : : }
102 : :
103 : 0 : void QgsMeshLayerRenderer::calculateOutputSize()
104 : : {
105 : : // figure out image size
106 : 0 : QgsRenderContext &context = *renderContext();
107 : 0 : const QgsRectangle extent = context.mapExtent();
108 : 0 : const QgsMapToPixel mapToPixel = context.mapToPixel();
109 : 0 : const QgsRectangle screenBBox = QgsMeshLayerUtils::boundingBoxToScreenRectangle( mapToPixel, extent );
110 : 0 : int width = int( screenBBox.width() );
111 : 0 : int height = int( screenBBox.height() );
112 : 0 : mOutputSize = QSize( width, height );
113 : 0 : }
114 : :
115 : 0 : void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
116 : 0 : {
117 : 0 : QgsMeshDatasetIndex datasetIndex;
118 : 0 : if ( renderContext()->isTemporal() )
119 : 0 : datasetIndex = layer->activeScalarDatasetAtTime( renderContext()->temporalRange() );
120 : : else
121 : 0 : datasetIndex = layer->staticScalarDatasetIndex();
122 : :
123 : : // Find out if we can use cache up to date. If yes, use it and return
124 : 0 : const int datasetGroupCount = layer->datasetGroupCount();
125 : 0 : const QgsMeshRendererScalarSettings::DataResamplingMethod method = mRendererSettings.scalarSettings( datasetIndex.group() ).dataResamplingMethod();
126 : 0 : QgsMeshLayerRendererCache *cache = layer->rendererCache();
127 : 0 : if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
128 : 0 : ( cache->mActiveScalarDatasetIndex == datasetIndex ) &&
129 : 0 : ( cache->mDataInterpolationMethod == method ) &&
130 : 0 : ( QgsMesh3dAveragingMethod::equals( cache->mScalarAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
131 : : )
132 : : {
133 : 0 : mScalarDatasetValues = cache->mScalarDatasetValues;
134 : 0 : mScalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
135 : 0 : mScalarDataType = cache->mScalarDataType;
136 : 0 : mScalarDatasetMinimum = cache->mScalarDatasetMinimum;
137 : 0 : mScalarDatasetMaximum = cache->mScalarDatasetMaximum;
138 : 0 : return;
139 : : }
140 : :
141 : : // Cache is not up-to-date, gather data
142 : 0 : if ( datasetIndex.isValid() )
143 : 0 : {
144 : 0 : const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex.group() );
145 : 0 : mScalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
146 : 0 :
147 : : // populate scalar values
148 : 0 : const int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mScalarDataType );
149 : 0 : QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
150 : 0 : layer,
151 : 0 : datasetIndex,
152 : : 0,
153 : 0 : count );
154 : :
155 : 0 : if ( vals.isValid() )
156 : : {
157 : : // vals could be scalar or vectors, for contour rendering we want always magnitude
158 : 0 : mScalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
159 : 0 : }
160 : : else
161 : : {
162 : 0 : mScalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
163 : : }
164 : :
165 : : // populate face active flag, always defined on faces
166 : 0 : mScalarActiveFaceFlagValues = layer->areFacesActive(
167 : : datasetIndex,
168 : : 0,
169 : 0 : mNativeMesh.faces.count() );
170 : :
171 : : // for data on faces, there could be request to interpolate the data to vertices
172 : 0 : if ( method != QgsMeshRendererScalarSettings::None )
173 : : {
174 : 0 : if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
175 : : {
176 : 0 : mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnVertices;
177 : 0 : mScalarDatasetValues = QgsMeshLayerUtils::interpolateFromFacesData(
178 : 0 : mScalarDatasetValues,
179 : 0 : &mNativeMesh,
180 : 0 : &mTriangularMesh,
181 : 0 : &mScalarActiveFaceFlagValues,
182 : 0 : method
183 : : );
184 : 0 : }
185 : 0 : else if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
186 : : {
187 : 0 : mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
188 : 0 : mScalarDatasetValues = QgsMeshLayerUtils::resampleFromVerticesToFaces(
189 : 0 : mScalarDatasetValues,
190 : 0 : &mNativeMesh,
191 : 0 : &mTriangularMesh,
192 : 0 : &mScalarActiveFaceFlagValues,
193 : 0 : method
194 : : );
195 : 0 : }
196 : :
197 : 0 : }
198 : :
199 : 0 : const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
200 : 0 : mScalarDatasetMinimum = datasetMetadata.minimum();
201 : 0 : mScalarDatasetMaximum = datasetMetadata.maximum();
202 : 0 : }
203 : :
204 : : // update cache
205 : 0 : cache->mDatasetGroupsCount = datasetGroupCount;
206 : 0 : cache->mActiveScalarDatasetIndex = datasetIndex;
207 : 0 : cache->mDataInterpolationMethod = method;
208 : 0 : cache->mScalarDatasetValues = mScalarDatasetValues;
209 : 0 : cache->mScalarActiveFaceFlagValues = mScalarActiveFaceFlagValues;
210 : 0 : cache->mScalarDataType = mScalarDataType;
211 : 0 : cache->mScalarDatasetMinimum = mScalarDatasetMinimum;
212 : 0 : cache->mScalarDatasetMaximum = mScalarDatasetMaximum;
213 : 0 : cache->mScalarAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
214 : 0 : }
215 : :
216 : :
217 : 0 : void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
218 : : {
219 : 0 : QgsMeshDatasetIndex datasetIndex;
220 : 0 : if ( renderContext()->isTemporal() )
221 : 0 : datasetIndex = layer->activeVectorDatasetAtTime( renderContext()->temporalRange() );
222 : : else
223 : 0 : datasetIndex = layer->staticVectorDatasetIndex();
224 : :
225 : : // Find out if we can use cache up to date. If yes, use it and return
226 : 0 : const int datasetGroupCount = layer->datasetGroupCount();
227 : 0 : QgsMeshLayerRendererCache *cache = layer->rendererCache();
228 : 0 : if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
229 : 0 : ( cache->mActiveVectorDatasetIndex == datasetIndex ) &&
230 : 0 : ( QgsMesh3dAveragingMethod::equals( cache->mVectorAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
231 : : )
232 : : {
233 : 0 : mVectorDatasetValues = cache->mVectorDatasetValues;
234 : 0 : mVectorDatasetValuesMag = cache->mVectorDatasetValuesMag;
235 : 0 : mVectorDatasetMagMinimum = cache->mVectorDatasetMagMinimum;
236 : 0 : mVectorDatasetMagMaximum = cache->mVectorDatasetMagMaximum;
237 : 0 : mVectorDatasetGroupMagMinimum = cache->mVectorDatasetMagMinimum;
238 : 0 : mVectorDatasetGroupMagMaximum = cache->mVectorDatasetMagMaximum;
239 : 0 : mVectorDataType = cache->mVectorDataType;
240 : 0 : return;
241 : : }
242 : :
243 : : // Cache is not up-to-date, gather data
244 : 0 : if ( datasetIndex.isValid() )
245 : : {
246 : 0 : const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex );
247 : :
248 : 0 : bool isScalar = metadata.isScalar();
249 : 0 : if ( isScalar )
250 : : {
251 : 0 : QgsDebugMsg( QStringLiteral( "Dataset has no vector values" ) );
252 : 0 : }
253 : : else
254 : : {
255 : 0 : mVectorDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
256 : :
257 : 0 : mVectorDatasetGroupMagMinimum = metadata.minimum();
258 : 0 : mVectorDatasetGroupMagMaximum = metadata.maximum();
259 : :
260 : 0 : int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mVectorDataType );
261 : 0 : mVectorDatasetValues = QgsMeshLayerUtils::datasetValues(
262 : 0 : layer,
263 : 0 : datasetIndex,
264 : : 0,
265 : 0 : count );
266 : :
267 : 0 : if ( mVectorDatasetValues.isValid() )
268 : 0 : mVectorDatasetValuesMag = QgsMeshLayerUtils::calculateMagnitudes( mVectorDatasetValues );
269 : : else
270 : 0 : mVectorDatasetValuesMag = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
271 : :
272 : 0 : const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
273 : 0 : mVectorDatasetMagMinimum = datasetMetadata.minimum();
274 : 0 : mVectorDatasetMagMaximum = datasetMetadata.maximum();
275 : : }
276 : 0 : }
277 : :
278 : : // update cache
279 : 0 : cache->mDatasetGroupsCount = datasetGroupCount;
280 : 0 : cache->mActiveVectorDatasetIndex = datasetIndex;
281 : 0 : cache->mVectorDatasetValues = mVectorDatasetValues;
282 : 0 : cache->mVectorDatasetValuesMag = mVectorDatasetValuesMag;
283 : 0 : cache->mVectorDatasetMagMinimum = mVectorDatasetMagMinimum;
284 : 0 : cache->mVectorDatasetMagMaximum = mVectorDatasetMagMaximum;
285 : 0 : cache->mVectorDatasetGroupMagMinimum = mVectorDatasetMagMinimum;
286 : 0 : cache->mVectorDatasetGroupMagMaximum = mVectorDatasetMagMaximum;
287 : 0 : cache->mVectorDataType = mVectorDataType;
288 : 0 : cache->mVectorAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
289 : 0 : }
290 : :
291 : 0 : bool QgsMeshLayerRenderer::render()
292 : : {
293 : 0 : mReadyToCompose = false;
294 : 0 : QgsScopedQPainterState painterState( renderContext()->painter() );
295 : 0 : if ( !mClippingRegions.empty() )
296 : : {
297 : 0 : bool needsPainterClipPath = false;
298 : 0 : const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), QgsMapLayerType::MeshLayer, needsPainterClipPath );
299 : 0 : if ( needsPainterClipPath )
300 : 0 : renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
301 : 0 : }
302 : :
303 : 0 : renderScalarDataset();
304 : 0 : mReadyToCompose = true;
305 : 0 : renderMesh();
306 : 0 : renderVectorDataset();
307 : :
308 : 0 : return !renderContext()->renderingStopped();
309 : 0 : }
310 : :
311 : 0 : bool QgsMeshLayerRenderer::forceRasterRender() const
312 : : {
313 : 0 : return renderContext()->testFlag( QgsRenderContext::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) );
314 : : }
315 : :
316 : 0 : void QgsMeshLayerRenderer::renderMesh()
317 : : {
318 : 0 : if ( !mRendererSettings.nativeMeshSettings().isEnabled() &&
319 : 0 : !mRendererSettings.edgeMeshSettings().isEnabled() &&
320 : 0 : !mRendererSettings.triangularMeshSettings().isEnabled() )
321 : 0 : return;
322 : :
323 : : // triangular mesh
324 : 0 : const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( renderContext()->mapExtent() );
325 : 0 : if ( mRendererSettings.triangularMeshSettings().isEnabled() )
326 : : {
327 : 0 : renderFaceMesh(
328 : 0 : mRendererSettings.triangularMeshSettings(),
329 : 0 : mTriangularMesh.triangles(),
330 : : trianglesInExtent );
331 : 0 : }
332 : :
333 : : // native mesh
334 : 0 : if ( mRendererSettings.nativeMeshSettings().isEnabled() && mTriangularMesh.levelOfDetail() == 0 )
335 : : {
336 : 0 : const QSet<int> nativeFacesInExtent = QgsMeshUtils::nativeFacesFromTriangles( trianglesInExtent,
337 : 0 : mTriangularMesh.trianglesToNativeFaces() );
338 : :
339 : 0 : renderFaceMesh(
340 : 0 : mRendererSettings.nativeMeshSettings(),
341 : 0 : mNativeMesh.faces,
342 : 0 : nativeFacesInExtent.values() );
343 : 0 : }
344 : :
345 : : // edge mesh
346 : 0 : if ( mRendererSettings.edgeMeshSettings().isEnabled() )
347 : : {
348 : 0 : const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( renderContext()->mapExtent() );
349 : 0 : renderEdgeMesh( mRendererSettings.edgeMeshSettings(), edgesInExtent );
350 : 0 : }
351 : 0 : }
352 : :
353 : 0 : static QPainter *_painterForMeshFrame( QgsRenderContext &context, const QgsMeshRendererMeshSettings &settings )
354 : : {
355 : : // Set up the render configuration options
356 : 0 : QPainter *painter = context.painter();
357 : :
358 : 0 : painter->save();
359 : 0 : context.setPainterFlagsUsingContext( painter );
360 : :
361 : 0 : QPen pen = painter->pen();
362 : 0 : pen.setCapStyle( Qt::FlatCap );
363 : 0 : pen.setJoinStyle( Qt::MiterJoin );
364 : :
365 : 0 : double penWidth = context.convertToPainterUnits( settings.lineWidth(), settings.lineWidthUnit() );
366 : 0 : pen.setWidthF( penWidth );
367 : 0 : pen.setColor( settings.color() );
368 : 0 : painter->setPen( pen );
369 : 0 : return painter;
370 : 0 : }
371 : :
372 : 0 : void QgsMeshLayerRenderer::renderEdgeMesh( const QgsMeshRendererMeshSettings &settings, const QList<int> &edgesInExtent )
373 : : {
374 : : Q_ASSERT( settings.isEnabled() );
375 : :
376 : 0 : if ( !mTriangularMesh.contains( QgsMesh::ElementType::Edge ) )
377 : 0 : return;
378 : :
379 : 0 : QgsRenderContext &context = *renderContext();
380 : 0 : QPainter *painter = _painterForMeshFrame( context, settings );
381 : :
382 : 0 : const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
383 : 0 : const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
384 : :
385 : 0 : for ( const int i : edgesInExtent )
386 : : {
387 : 0 : if ( context.renderingStopped() )
388 : 0 : break;
389 : :
390 : 0 : if ( i >= edges.size() )
391 : 0 : continue;
392 : :
393 : 0 : const QgsMeshEdge &edge = edges[i];
394 : 0 : const int startVertexIndex = edge.first;
395 : 0 : const int endVertexIndex = edge.second;
396 : :
397 : 0 : if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
398 : 0 : continue;
399 : :
400 : 0 : const QgsMeshVertex &startVertex = vertices[startVertexIndex];
401 : 0 : const QgsMeshVertex &endVertex = vertices[endVertexIndex];
402 : 0 : const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
403 : 0 : const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
404 : 0 : painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
405 : : }
406 : 0 : painter->restore();
407 : 0 : };
408 : :
409 : 0 : void QgsMeshLayerRenderer::renderFaceMesh(
410 : : const QgsMeshRendererMeshSettings &settings,
411 : : const QVector<QgsMeshFace> &faces,
412 : : const QList<int> &facesInExtent )
413 : : {
414 : : Q_ASSERT( settings.isEnabled() );
415 : :
416 : 0 : if ( !mTriangularMesh.contains( QgsMesh::ElementType::Face ) )
417 : 0 : return;
418 : :
419 : 0 : QgsRenderContext &context = *renderContext();
420 : 0 : QPainter *painter = _painterForMeshFrame( context, settings );
421 : :
422 : 0 : const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices(); //Triangular mesh vertices contains also native mesh vertices
423 : 0 : QSet<QPair<int, int>> drawnEdges;
424 : :
425 : 0 : for ( const int i : facesInExtent )
426 : : {
427 : 0 : if ( context.renderingStopped() )
428 : 0 : break;
429 : :
430 : 0 : const QgsMeshFace &face = faces[i];
431 : 0 : if ( face.size() < 2 )
432 : 0 : continue;
433 : :
434 : 0 : for ( int j = 0; j < face.size(); ++j )
435 : : {
436 : 0 : const int startVertexId = face[j];
437 : 0 : const int endVertexId = face[( j + 1 ) % face.size()];
438 : 0 : const QPair<int, int> thisEdge( startVertexId, endVertexId );
439 : 0 : const QPair<int, int> thisEdgeReversed( endVertexId, startVertexId );
440 : 0 : if ( drawnEdges.contains( thisEdge ) || drawnEdges.contains( thisEdgeReversed ) )
441 : 0 : continue;
442 : 0 : drawnEdges.insert( thisEdge );
443 : 0 : drawnEdges.insert( thisEdgeReversed );
444 : :
445 : 0 : const QgsMeshVertex &startVertex = vertices[startVertexId];
446 : 0 : const QgsMeshVertex &endVertex = vertices[endVertexId];
447 : 0 : const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
448 : 0 : const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
449 : 0 : painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
450 : 0 : }
451 : : }
452 : :
453 : 0 : painter->restore();
454 : 0 : }
455 : :
456 : 0 : void QgsMeshLayerRenderer::renderScalarDataset()
457 : : {
458 : 0 : if ( mScalarDatasetValues.isEmpty() )
459 : 0 : return; // activeScalarDataset == NO_ACTIVE_MESH_DATASET
460 : :
461 : 0 : if ( std::isnan( mScalarDatasetMinimum ) || std::isnan( mScalarDatasetMaximum ) )
462 : 0 : return; // only NODATA values
463 : :
464 : 0 : int groupIndex = mRendererSettings.activeScalarDatasetGroup();
465 : 0 : if ( groupIndex < 0 )
466 : 0 : return; // no shader
467 : :
468 : 0 : const QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( groupIndex );
469 : :
470 : 0 : if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Face ) ) &&
471 : 0 : ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnEdges ) )
472 : : {
473 : 0 : renderScalarDatasetOnFaces( scalarSettings );
474 : 0 : }
475 : :
476 : 0 : if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Edge ) ) &&
477 : 0 : ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnFaces ) )
478 : : {
479 : 0 : renderScalarDatasetOnEdges( scalarSettings );
480 : 0 : }
481 : 0 : }
482 : :
483 : 0 : void QgsMeshLayerRenderer::renderScalarDatasetOnEdges( const QgsMeshRendererScalarSettings &scalarSettings )
484 : : {
485 : 0 : QgsRenderContext &context = *renderContext();
486 : 0 : const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
487 : 0 : const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
488 : 0 : const QList<int> egdesInExtent = mTriangularMesh.edgeIndexesForRectangle( context.mapExtent() );
489 : 0 : const QSet<int> nativeEdgesInExtent = QgsMeshUtils::nativeEdgesFromEdges( egdesInExtent,
490 : 0 : mTriangularMesh.edgesToNativeEdges() );
491 : :
492 : 0 : QgsInterpolatedLineRenderer edgePlotter;
493 : 0 : edgePlotter.setInterpolatedColor( QgsInterpolatedLineColor( scalarSettings.colorRampShader() ) );
494 : 0 : edgePlotter.setInterpolatedWidth( QgsInterpolatedLineWidth( scalarSettings.edgeStrokeWidth() ) );
495 : 0 : edgePlotter.setWidthUnit( scalarSettings.edgeStrokeWidthUnit() );
496 : :
497 : 0 : for ( const int i : egdesInExtent )
498 : : {
499 : 0 : if ( context.renderingStopped() )
500 : 0 : break;
501 : :
502 : 0 : if ( i >= edges.size() )
503 : 0 : continue;
504 : :
505 : 0 : const QgsMeshEdge &edge = edges[i];
506 : 0 : const int startVertexIndex = edge.first;
507 : 0 : const int endVertexIndex = edge.second;
508 : :
509 : 0 : if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
510 : 0 : continue;
511 : :
512 : 0 : const QgsMeshVertex &startVertex = vertices[startVertexIndex];
513 : 0 : const QgsMeshVertex &endVertex = vertices[endVertexIndex];
514 : :
515 : 0 : if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges )
516 : : {
517 : 0 : edgePlotter.render( mScalarDatasetValues[i], mScalarDatasetValues[i], startVertex, endVertex, context );
518 : 0 : }
519 : : else
520 : : {
521 : 0 : edgePlotter.render( mScalarDatasetValues[startVertexIndex], mScalarDatasetValues[endVertexIndex], startVertex, endVertex, context );
522 : : }
523 : : }
524 : 0 : }
525 : :
526 : 0 : QColor QgsMeshLayerRenderer::colorAt( QgsColorRampShader *shader, double val ) const
527 : : {
528 : : int r, g, b, a;
529 : 0 : if ( shader->shade( val, &r, &g, &b, &a ) )
530 : : {
531 : 0 : return QColor( r, g, b, a );
532 : : }
533 : 0 : return QColor();
534 : 0 : }
535 : :
536 : 0 : QgsPointXY QgsMeshLayerRenderer::fractionPoint( const QgsPointXY &p1, const QgsPointXY &p2, double fraction ) const
537 : : {
538 : 0 : const QgsPointXY pt( p1.x() + fraction * ( p2.x() - p1.x() ),
539 : 0 : p1.y() + fraction * ( p2.y() - p1.y() ) );
540 : 0 : return pt;
541 : : }
542 : :
543 : 0 : void QgsMeshLayerRenderer::renderScalarDatasetOnFaces( const QgsMeshRendererScalarSettings &scalarSettings )
544 : : {
545 : 0 : QgsRenderContext &context = *renderContext();
546 : :
547 : 0 : QgsColorRampShader *fcn = new QgsColorRampShader( scalarSettings.colorRampShader() );
548 : 0 : QgsRasterShader *sh = new QgsRasterShader();
549 : 0 : sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
550 : 0 : QgsMeshLayerInterpolator interpolator( mTriangularMesh,
551 : 0 : mScalarDatasetValues,
552 : 0 : mScalarActiveFaceFlagValues,
553 : 0 : mScalarDataType,
554 : 0 : context,
555 : 0 : mOutputSize );
556 : 0 : interpolator.setSpatialIndexActive( mIsMeshSimplificationActive );
557 : 0 : QgsSingleBandPseudoColorRenderer renderer( &interpolator, 0, sh ); // takes ownership of sh
558 : 0 : renderer.setClassificationMin( scalarSettings.classificationMinimum() );
559 : 0 : renderer.setClassificationMax( scalarSettings.classificationMaximum() );
560 : 0 : renderer.setOpacity( scalarSettings.opacity() );
561 : :
562 : 0 : std::unique_ptr<QgsRasterBlock> bl( renderer.block( 0, context.mapExtent(), mOutputSize.width(), mOutputSize.height(), mFeedback.get() ) );
563 : 0 : QImage img = bl->image();
564 : :
565 : 0 : context.painter()->drawImage( 0, 0, img );
566 : 0 : }
567 : :
568 : 0 : void QgsMeshLayerRenderer::renderVectorDataset()
569 : : {
570 : 0 : int groupIndex = mRendererSettings.activeVectorDatasetGroup();
571 : 0 : if ( groupIndex < 0 )
572 : 0 : return;
573 : :
574 : 0 : if ( !mVectorDatasetValues.isValid() )
575 : 0 : return; // no data at all
576 : :
577 : 0 : if ( std::isnan( mVectorDatasetMagMinimum ) || std::isnan( mVectorDatasetMagMaximum ) )
578 : 0 : return; // only NODATA values
579 : :
580 : 0 : if ( !( mVectorDatasetMagMaximum > 0 ) )
581 : 0 : return; //all vector are null vector
582 : :
583 : 0 : std::unique_ptr<QgsMeshVectorRenderer> renderer( QgsMeshVectorRenderer::makeVectorRenderer(
584 : 0 : mTriangularMesh,
585 : 0 : mVectorDatasetValues,
586 : 0 : mScalarActiveFaceFlagValues,
587 : 0 : mVectorDatasetValuesMag,
588 : 0 : mVectorDatasetMagMaximum,
589 : 0 : mVectorDatasetMagMinimum,
590 : 0 : mVectorDataType,
591 : 0 : mRendererSettings.vectorSettings( groupIndex ),
592 : 0 : *renderContext(),
593 : 0 : mLayerExtent,
594 : 0 : mOutputSize ) );
595 : :
596 : 0 : if ( renderer )
597 : 0 : renderer->draw();
598 : 0 : }
599 : :
|