33inline bool nodataValue(
double x,
double y )
35 return ( std::isnan( x ) || std::isnan( y ) );
38QgsMeshVectorRenderer::~QgsMeshVectorRenderer() =
default;
40QgsMeshVectorRenderer *QgsMeshVectorRenderer::makeVectorRenderer(
44 const QVector<double> &datasetValuesMag,
45 double datasetMagMaximumValue,
46 double datasetMagMinimumValue,
55 QgsMeshVectorRenderer *renderer =
nullptr;
61 renderer =
new QgsMeshVectorGlyphRenderer( m, datasetVectorValues, datasetValuesMag, datasetMagMaximumValue, datasetMagMinimumValue, dataType, settings, context, size );
66 =
new QgsMeshVectorStreamlineRenderer( m, datasetVectorValues, scalarActiveFaceFlagValues, datasetValuesMag, datasetMagMaximumValue, datasetMagMinimumValue, dataType, settings, context, layerExtent, feedBack, size );
73QgsMeshVectorGlyphRenderer::QgsMeshVectorGlyphRenderer(
76 const QVector<double> &datasetValuesMag,
77 double datasetMagMaximumValue,
78 double datasetMagMinimumValue,
84 : mTriangularMesh( m )
85 , mDatasetValues( datasetValues )
86 , mDatasetValuesMag( datasetValuesMag )
87 , mMinMag( datasetMagMinimumValue )
88 , mMaxMag( datasetMagMaximumValue )
89 , mDataType( dataType )
90 , mBufferedExtent( context.mapExtent() )
94 , mEngine( datasetMagMaximumValue, datasetMagMinimumValue, settings, context, size )
97 Q_ASSERT( !mDatasetValuesMag.empty() );
98 Q_ASSERT( !std::isnan( mMinMag ) );
99 Q_ASSERT( !std::isnan( mMaxMag ) );
100 Q_ASSERT( mDatasetValues.isValid() );
107 mBufferedExtent.setXMinimum( mBufferedExtent.xMinimum() - extension );
108 mBufferedExtent.setXMaximum( mBufferedExtent.xMaximum() + extension );
109 mBufferedExtent.setYMinimum( mBufferedExtent.yMinimum() - extension );
110 mBufferedExtent.setYMaximum( mBufferedExtent.yMaximum() + extension );
113QgsMeshVectorGlyphRenderer::~QgsMeshVectorGlyphRenderer() =
default;
115void QgsMeshVectorGlyphRenderer::draw()
117 if ( mCfg.isOnUserDefinedGrid() )
119 drawVectorDataOnGrid();
123 drawVectorDataOnVertices();
127 drawVectorDataOnFaces();
131 drawVectorDataOnEdges();
135void QgsMeshVectorGlyphRenderer::drawVectorDataOnVertices()
137 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
138 QSet<int> verticesToDraw;
141 Q_ASSERT( mDatasetValuesMag.count() == vertices.count() );
145 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
146 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
152 const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
153 const QVector<QgsMeshEdge> &edges = mTriangularMesh.edges();
158 drawVectorDataOnPoints( verticesToDraw, vertices );
161void QgsMeshVectorGlyphRenderer::drawVectorDataOnPoints(
const QSet<int> indexesToRender,
const QVector<QgsMeshVertex> &points )
163 for (
const int i : indexesToRender )
165 if ( mContext.renderingStopped() )
169 if ( !mBufferedExtent.contains( center ) )
173 const double xVal = val.
x();
174 const double yVal = val.
y();
175 if ( nodataValue( xVal, yVal ) )
178 const double V = mDatasetValuesMag[i];
179 const QgsPointXY lineStart = mContext.mapToPixel().transform( center.
x(), center.
y() );
181 mEngine.drawGlyph( lineStart, xVal, yVal, V );
185void QgsMeshVectorGlyphRenderer::drawVectorDataOnFaces()
187 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
188 const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.faceCentroids();
190 drawVectorDataOnPoints( nativeFacesInExtent, centroids );
193void QgsMeshVectorGlyphRenderer::drawVectorDataOnEdges()
195 const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
196 const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.edgeCentroids();
198 drawVectorDataOnPoints( nativeEdgesInExtent, centroids );
201void QgsMeshVectorGlyphRenderer::drawVectorDataOnGrid()
206 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
207 const int cellx = mCfg.userGridCellWidth();
208 const int celly = mCfg.userGridCellHeight();
210 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
211 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
213 for (
const int i : trianglesInExtent )
215 if ( mContext.renderingStopped() )
220 const int v1 = face[0], v2 = face[1], v3 = face[2];
221 const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
223 const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
226 const QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( p1, p2, p3 );
227 int left, right, top, bottom;
228 QgsMeshLayerUtils::boundingBoxToScreenRectangle( mContext.mapToPixel(), mOutputSize, bbox, left, right, top, bottom );
231 if ( left % cellx != 0 )
232 left += cellx - ( left % cellx );
233 if ( right % cellx != 0 )
234 right -= ( right % cellx );
235 if ( top % celly != 0 )
236 top += celly - ( top % celly );
237 if ( bottom % celly != 0 )
238 bottom -= ( bottom % celly );
240 for (
int y = top; y <= bottom; y += celly )
242 for (
int x = left; x <= right; x += cellx )
245 const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( x, y );
249 const auto val1 = mDatasetValues.value( v1 );
250 const auto val2 = mDatasetValues.value( v2 );
251 const auto val3 = mDatasetValues.value( v3 );
252 val.
setX( QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), p ) );
253 val.
setY( QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), p ) );
257 const auto val1 = mDatasetValues.value( nativeFaceIndex );
258 val.
setX( QgsMeshLayerUtils::interpolateFromFacesData( p1, p2, p3, val1.x(), p ) );
259 val.
setY( QgsMeshLayerUtils::interpolateFromFacesData( p1, p2, p3, val1.y(), p ) );
261 if ( nodataValue( val.
x(), val.
y() ) )
265 mEngine.drawGlyph( lineStart, val.
x(), val.
y(), val.
scalar() );
271QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
275 const QVector<double> &datasetValuesMag,
276 double datasetMagMaximumValue,
277 double datasetMagMinimumValue,
286 , mFeedBack( feedBack )
287 , mSource( QgsMeshVectorFieldValueSource::create( m, datasetValues, scalarActiveFaceFlagValues, datasetValuesMag, dataType, layerExtent, datasetMagMaximumValue ) )
288 , mEngine( datasetMagMaximumValue, datasetMagMinimumValue, settings, context, size )
291QgsMeshVectorStreamlineRenderer::~QgsMeshVectorStreamlineRenderer() =
default;
293void QgsMeshVectorStreamlineRenderer::draw()
295 switch ( mCfg.symbology() )
298 mEngine.drawStreamlines( std::move( mSource ), mFeedBack );
301 mEngine.drawTraces( std::move( mSource ) );
@ WindBarbs
Displaying vector dataset with wind barbs.
@ Arrows
Displaying vector dataset with arrows.
@ Traces
Displaying vector dataset with particle traces.
@ Streamlines
Displaying vector dataset with streamlines.
A block of integers/doubles from a mesh dataset.
@ Vector2DDouble
Vector double pairs (x1, y1, x2, y2, ... ).
Represents a single mesh dataset value.
void setY(double y)
Sets Y value.
double y() const
Returns y value.
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
double x() const
Returns x value.
void setX(double x)
Sets X value.
static QSet< int > nativeEdgesFromEdges(const QList< int > &edgesIndexes, const QVector< int > &edgesToNativeEdges)
Returns unique native faces indexes from list of triangle indexes.
static QSet< int > nativeVerticesFromEdges(const QList< int > &edgesIndexes, const QVector< QgsMeshEdge > &edges)
Returns unique native faces indexes from list of vertices of triangles.
static QSet< int > nativeVerticesFromTriangles(const QList< int > &triangleIndexes, const QVector< QgsMeshFace > &triangles)
Returns unique native vertex indexes from list of vertices of triangles.
static QSet< int > nativeFacesFromTriangles(const QList< int > &triangleIndexes, const QVector< int > &trianglesToNativeFaces)
Returns unique native faces indexes from list of triangle indexes.
Point geometry type, with support for z-dimension and m-values.
Feedback object tailored for raster block reading.
A rectangle specified with double values.
Contains information about the context of a rendering operation.
double convertToMapUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
A triangular/derived mesh with vertices in map coordinates.
Represents a renderer settings for vector datasets.
Qgis::VectorFieldSymbology symbology() const
Returns the displaying method used to render vector datasets.
QVector< int > QgsMeshFace
List of vertex indexes.