34 inline double mag(
double input )
43 inline bool nodataValue(
double x,
double y )
45 return ( std::isnan( x ) || std::isnan( y ) );
50 const QVector<double> &datasetValuesMag,
51 double datasetMagMinimumValue,
52 double datasetMagMaximumValue,
53 bool dataIsOnVertices,
56 : mTriangularMesh( m )
57 , mDatasetValues( datasetValues )
58 , mDatasetValuesMag( datasetValuesMag )
59 , mMinMag( datasetMagMinimumValue )
60 , mMaxMag( datasetMagMaximumValue )
63 , mDataOnVertices( dataIsOnVertices )
65 , mBufferedExtent( context.extent() )
68 Q_ASSERT( !mDatasetValuesMag.empty() );
69 Q_ASSERT( !std::isnan( mMinMag ) );
70 Q_ASSERT( !std::isnan( mMaxMag ) );
71 Q_ASSERT( mDatasetValues.isValid() );
78 mBufferedExtent.setXMinimum( mBufferedExtent.xMinimum() - extension );
79 mBufferedExtent.setXMaximum( mBufferedExtent.xMaximum() + extension );
80 mBufferedExtent.setYMinimum( mBufferedExtent.yMinimum() - extension );
81 mBufferedExtent.setYMaximum( mBufferedExtent.yMaximum() + extension );
84 QgsMeshVectorRenderer::~QgsMeshVectorRenderer() =
default;
86 void QgsMeshVectorRenderer::draw()
89 QPainter *painter = mContext.painter();
92 painter->setRenderHint( QPainter::Antialiasing,
true );
94 QPen pen = painter->pen();
95 pen.setCapStyle( Qt::FlatCap );
96 pen.setJoinStyle( Qt::MiterJoin );
98 double penWidth = mContext.convertToPainterUnits( mCfg.lineWidth(),
99 QgsUnitTypes::RenderUnit::RenderMillimeters );
100 pen.setWidthF( penWidth );
101 pen.setColor( mCfg.color() );
102 painter->setPen( pen );
104 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
106 if ( mCfg.isOnUserDefinedGrid() )
107 drawVectorDataOnGrid( trianglesInExtent );
108 else if ( mDataOnVertices )
109 drawVectorDataOnVertices( trianglesInExtent );
111 drawVectorDataOnFaces( trianglesInExtent );
116 bool QgsMeshVectorRenderer::calcVectorLineEnd(
118 double &vectorLength,
129 if ( xVal == 0.0 && yVal == 0.0 )
133 if ( mCfg.filterMin() >= 0 && magnitude < mCfg.filterMin() )
135 if ( mCfg.filterMax() >= 0 && magnitude > mCfg.filterMax() )
140 double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal );
141 cosAlpha = cos( vectorAngle ) * mag( xVal );
142 sinAlpha = sin( vectorAngle ) * mag( xVal );
147 switch ( mCfg.shaftLengthMethod() )
149 case QgsMeshRendererVectorSettings::ArrowScalingMethod::MinMax:
151 double minShaftLength = mContext.convertToPainterUnits( mCfg.minShaftLength(),
152 QgsUnitTypes::RenderUnit::RenderMillimeters );
153 double maxShaftLength = mContext.convertToPainterUnits( mCfg.maxShaftLength(),
154 QgsUnitTypes::RenderUnit::RenderMillimeters );
155 double minVal = mMinMag;
156 double maxVal = mMaxMag;
157 double k = ( magnitude - minVal ) / ( maxVal - minVal );
158 double L = minShaftLength + k * ( maxShaftLength - minShaftLength );
159 xDist = cosAlpha * L;
160 yDist = sinAlpha * L;
163 case QgsMeshRendererVectorSettings::ArrowScalingMethod::Scaled:
165 double scaleFactor = mCfg.scaleFactor();
166 xDist = scaleFactor * xVal;
167 yDist = scaleFactor * yVal;
170 case QgsMeshRendererVectorSettings::ArrowScalingMethod::Fixed:
173 double fixedShaftLength = mContext.convertToPainterUnits( mCfg.fixedShaftLength(),
174 QgsUnitTypes::RenderUnit::RenderMillimeters );
175 xDist = cosAlpha * fixedShaftLength;
176 yDist = sinAlpha * fixedShaftLength;
184 if ( std::abs( xDist ) < 1 && std::abs( yDist ) < 1 )
189 lineStart.
y() + yDist );
191 vectorLength = sqrt( xDist * xDist + yDist * yDist );
194 if ( ( lineStart.
x() < 0 || lineStart.
x() > mOutputSize.width() ||
195 lineStart.
y() < 0 || lineStart.
y() > mOutputSize.height() ) &&
196 ( lineEnd.
x() < 0 || lineEnd.
x() > mOutputSize.width() ||
197 lineEnd.
y() < 0 || lineEnd.
y() > mOutputSize.height() ) )
203 double QgsMeshVectorRenderer::calcExtentBufferSize()
const 206 switch ( mCfg.shaftLengthMethod() )
208 case QgsMeshRendererVectorSettings::ArrowScalingMethod::MinMax:
210 buffer = mContext.convertToPainterUnits( mCfg.maxShaftLength(),
211 QgsUnitTypes::RenderUnit::RenderMillimeters );
214 case QgsMeshRendererVectorSettings::ArrowScalingMethod::Scaled:
216 buffer = mCfg.scaleFactor() * mMaxMag;
219 case QgsMeshRendererVectorSettings::ArrowScalingMethod::Fixed:
221 buffer = mContext.convertToPainterUnits( mCfg.fixedShaftLength(),
222 QgsUnitTypes::RenderUnit::RenderMillimeters );
227 if ( mCfg.filterMax() >= 0 && buffer > mCfg.filterMax() )
228 buffer = mCfg.filterMax();
237 void QgsMeshVectorRenderer::drawVectorDataOnVertices(
const QList<int> &trianglesInExtent )
239 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
240 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
241 QSet<int> drawnVertices;
244 Q_ASSERT( mDatasetValuesMag.count() == vertices.count() );
246 for (
int triangleIndex : trianglesInExtent )
248 if ( mContext.renderingStopped() )
251 const QgsMeshFace triangle = triangles[triangleIndex];
252 for (
int i : triangle )
254 if ( drawnVertices.contains( i ) )
256 drawnVertices.insert( i );
259 if ( !mBufferedExtent.contains( vertex ) )
263 double xVal = val.
x();
264 double yVal = val.
y();
265 if ( nodataValue( xVal, yVal ) )
268 double V = mDatasetValuesMag[i];
269 QgsPointXY lineStart = mContext.mapToPixel().transform( vertex.
x(), vertex.
y() );
271 drawVectorArrow( lineStart, xVal, yVal, V );
276 void QgsMeshVectorRenderer::drawVectorDataOnFaces(
const QList<int> &trianglesInExtent )
278 const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.centroids();
280 mTriangularMesh.trianglesToNativeFaces() );
281 for (
int i : nativeFacesInExtent )
283 if ( mContext.renderingStopped() )
287 if ( !mBufferedExtent.contains( center ) )
291 double xVal = val.
x();
292 double yVal = val.
y();
293 if ( nodataValue( xVal, yVal ) )
296 double V = mDatasetValuesMag[i];
297 QgsPointXY lineStart = mContext.mapToPixel().transform( center.
x(), center.
y() );
299 drawVectorArrow( lineStart, xVal, yVal, V );
303 void QgsMeshVectorRenderer::drawVectorDataOnGrid(
const QList<int> &trianglesInExtent )
305 int cellx = mCfg.userGridCellWidth();
306 int celly = mCfg.userGridCellHeight();
308 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
309 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
311 for (
const int i : trianglesInExtent )
313 if ( mContext.renderingStopped() )
318 const int v1 = face[0], v2 = face[1], v3 = face[2];
319 const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
321 const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
324 QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( p1, p2, p3 );
325 int left, right, top, bottom;
326 QgsMeshLayerUtils::boundingBoxToScreenRectangle( mContext.mapToPixel(), mOutputSize, bbox, left, right, top, bottom );
329 if ( left % cellx != 0 )
330 left += cellx - ( left % cellx );
331 if ( right % cellx != 0 )
332 right -= ( right % cellx );
333 if ( top % celly != 0 )
334 top += celly - ( top % celly );
335 if ( bottom % celly != 0 )
336 bottom -= ( bottom % celly );
338 for (
int y = top; y <= bottom; y += celly )
340 for (
int x = left; x <= right; x += cellx )
343 const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( x, y );
345 if ( mDataOnVertices )
347 const auto val1 = mDatasetValues.value( v1 );
348 const auto val2 = mDatasetValues.value( v2 );
349 const auto val3 = mDatasetValues.value( v3 );
351 QgsMeshLayerUtils::interpolateFromVerticesData(
359 QgsMeshLayerUtils::interpolateFromVerticesData(
369 const auto val1 = mDatasetValues.value( nativeFaceIndex );
371 QgsMeshLayerUtils::interpolateFromFacesData(
378 QgsMeshLayerUtils::interpolateFromFacesData(
386 if ( nodataValue( val.
x(), val.
y() ) )
390 drawVectorArrow( lineStart, val.
x(), val.
y(), val.
scalar() );
396 void QgsMeshVectorRenderer::drawVectorArrow(
const QgsPointXY &lineStart,
double xVal,
double yVal,
double magnitude )
400 double cosAlpha, sinAlpha;
401 if ( calcVectorLineEnd( lineEnd, vectorLength, cosAlpha, sinAlpha,
402 lineStart, xVal, yVal, magnitude ) )
408 QVector<QPointF> finalVectorHeadPoints( 3 );
410 double vectorHeadWidthRatio = mCfg.arrowHeadWidthRatio();
411 double vectorHeadLengthRatio = mCfg.arrowHeadLengthRatio();
414 vectorHeadPoints[0].
setX( -1.0 * vectorHeadLengthRatio );
415 vectorHeadPoints[0].
setY( vectorHeadWidthRatio * 0.5 );
418 vectorHeadPoints[1].
setX( 0.0 );
419 vectorHeadPoints[1].
setY( 0.0 );
422 vectorHeadPoints[2].
setX( -1.0 * vectorHeadLengthRatio );
423 vectorHeadPoints[2].
setY( -1.0 * vectorHeadWidthRatio * 0.5 );
426 for (
int j = 0; j < 3; j++ )
428 finalVectorHeadPoints[j].setX( lineEnd.
x()
429 + ( vectorHeadPoints[j].
x() * cosAlpha * vectorLength )
430 - ( vectorHeadPoints[j].y() * sinAlpha * vectorLength )
433 finalVectorHeadPoints[j].setY( lineEnd.
y()
434 - ( vectorHeadPoints[j].
x() * sinAlpha * vectorLength )
435 - ( vectorHeadPoints[j].y() * cosAlpha * vectorLength )
441 mContext.painter()->drawPolygon( finalVectorHeadPoints );
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
A rectangle specified with double values.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
Use antialiasing while drawing.
Vector double pairs (x1, y1, x2, y2, ... )
A class to represent a 2D point.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e...
void setY(double y)
Sets Y value.
double y() const
Returns y value.
QPointF toQPointF() const
Converts a point to a QPointF.
Represents a mesh renderer settings for vector datasets.
void setY(double y)
Sets the y value of the point.
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.
void setX(double x)
Sets the x value of the point.
CORE_EXPORT QList< int > nativeFacesFromTriangles(const QList< int > &triangleIndexes, const QVector< int > &trianglesToNativeFaces)
Returns unique native faces indexes from list of triangle indexes.
Contains information about the context of a rendering operation.
QVector< int > QgsMeshFace
List of vertex indexes.
QgsMeshDatasetValue represents single dataset value.
void setX(double x)
Sets X value.
double x() const
Returns x value.