35 inline double mag(
double input )
44 inline bool nodataValue(
double x,
double y )
46 return ( std::isnan( x ) || std::isnan( y ) );
49 QgsMeshVectorArrowRenderer::QgsMeshVectorArrowRenderer(
52 const QVector<double> &datasetValuesMag,
53 double datasetMagMaximumValue,
double datasetMagMinimumValue,
59 , mDatasetValues( datasetValues )
60 , mDatasetValuesMag( datasetValuesMag )
61 , mMinMag( datasetMagMinimumValue )
62 , mMaxMag( datasetMagMaximumValue )
65 , mDataType( dataType )
67 , mBufferedExtent( context.mapExtent() )
70 Q_ASSERT( !mDatasetValuesMag.empty() );
71 Q_ASSERT( !std::isnan( mMinMag ) );
72 Q_ASSERT( !std::isnan( mMaxMag ) );
73 Q_ASSERT( mDatasetValues.isValid() );
80 mBufferedExtent.setXMinimum( mBufferedExtent.xMinimum() - extension );
81 mBufferedExtent.setXMaximum( mBufferedExtent.xMaximum() + extension );
82 mBufferedExtent.setYMinimum( mBufferedExtent.yMinimum() - extension );
83 mBufferedExtent.setYMaximum( mBufferedExtent.yMaximum() + extension );
88 QgsMeshVectorArrowRenderer::~QgsMeshVectorArrowRenderer() =
default;
90 void QgsMeshVectorArrowRenderer::draw()
93 QPainter *painter = mContext.painter();
96 painter->setRenderHint( QPainter::Antialiasing,
true );
98 QPen pen = painter->pen();
99 pen.setCapStyle( Qt::FlatCap );
100 pen.setJoinStyle( Qt::MiterJoin );
102 double penWidth = mContext.convertToPainterUnits( mCfg.lineWidth(),
103 QgsUnitTypes::RenderUnit::RenderMillimeters );
104 pen.setWidthF( penWidth );
105 painter->setPen( pen );
107 if ( mCfg.isOnUserDefinedGrid() )
109 drawVectorDataOnGrid( );
111 else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
113 drawVectorDataOnVertices( );
115 else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
117 drawVectorDataOnFaces( );
119 else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges )
121 drawVectorDataOnEdges( );
127 bool QgsMeshVectorArrowRenderer::calcVectorLineEnd(
129 double &vectorLength,
140 if ( xVal == 0.0 && yVal == 0.0 )
144 if ( mCfg.filterMin() >= 0 && magnitude < mCfg.filterMin() )
146 if ( mCfg.filterMax() >= 0 && magnitude > mCfg.filterMax() )
151 double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal );
152 cosAlpha = cos( vectorAngle ) * mag( xVal );
153 sinAlpha = sin( vectorAngle ) * mag( xVal );
158 switch ( mCfg.arrowSettings().shaftLengthMethod() )
160 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::MinMax:
162 double minShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().minShaftLength(),
163 QgsUnitTypes::RenderUnit::RenderMillimeters );
164 double maxShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().maxShaftLength(),
165 QgsUnitTypes::RenderUnit::RenderMillimeters );
166 double minVal = mMinMag;
167 double maxVal = mMaxMag;
168 double k = ( magnitude - minVal ) / ( maxVal - minVal );
169 double L = minShaftLength + k * ( maxShaftLength - minShaftLength );
170 xDist = cosAlpha * L;
171 yDist = sinAlpha * L;
174 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Scaled:
176 double scaleFactor = mCfg.arrowSettings().scaleFactor();
177 xDist = scaleFactor * xVal;
178 yDist = scaleFactor * yVal;
181 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Fixed:
184 double fixedShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().fixedShaftLength(),
185 QgsUnitTypes::RenderUnit::RenderMillimeters );
186 xDist = cosAlpha * fixedShaftLength;
187 yDist = sinAlpha * fixedShaftLength;
195 if ( std::abs( xDist ) < 1 && std::abs( yDist ) < 1 )
200 lineStart.
y() + yDist );
202 vectorLength = sqrt( xDist * xDist + yDist * yDist );
205 if ( ( lineStart.
x() < 0 || lineStart.
x() > mOutputSize.width() ||
206 lineStart.
y() < 0 || lineStart.
y() > mOutputSize.height() ) &&
207 ( lineEnd.
x() < 0 || lineEnd.
x() > mOutputSize.width() ||
208 lineEnd.
y() < 0 || lineEnd.
y() > mOutputSize.height() ) )
214 double QgsMeshVectorArrowRenderer::calcExtentBufferSize()
const
217 switch ( mCfg.arrowSettings().shaftLengthMethod() )
219 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::MinMax:
221 buffer = mContext.convertToPainterUnits( mCfg.arrowSettings().maxShaftLength(),
222 QgsUnitTypes::RenderUnit::RenderMillimeters );
225 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Scaled:
227 buffer = mCfg.arrowSettings().scaleFactor() * mMaxMag;
230 case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Fixed:
232 buffer = mContext.convertToPainterUnits( mCfg.arrowSettings().fixedShaftLength(),
233 QgsUnitTypes::RenderUnit::RenderMillimeters );
238 if ( mCfg.filterMax() >= 0 && buffer > mCfg.filterMax() )
239 buffer = mCfg.filterMax();
248 void QgsMeshVectorArrowRenderer::drawVectorDataOnVertices()
250 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
251 QSet<int> verticesToDraw;
254 Q_ASSERT( mDatasetValuesMag.count() == vertices.count() );
258 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
259 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
265 const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
266 const QVector<QgsMeshEdge> &edges = mTriangularMesh.edges();
271 drawVectorDataOnPoints( verticesToDraw, vertices );
274 void QgsMeshVectorArrowRenderer::drawVectorDataOnPoints(
const QSet<int> indexesToRender,
const QVector<QgsMeshVertex> &points )
276 for (
int i : indexesToRender )
278 if ( mContext.renderingStopped() )
282 if ( !mBufferedExtent.contains( center ) )
286 double xVal = val.
x();
287 double yVal = val.
y();
288 if ( nodataValue( xVal, yVal ) )
291 double V = mDatasetValuesMag[i];
292 QgsPointXY lineStart = mContext.mapToPixel().transform( center.
x(), center.
y() );
294 drawVectorArrow( lineStart, xVal, yVal, V );
298 void QgsMeshVectorArrowRenderer::drawVectorDataOnFaces( )
300 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
301 const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.faceCentroids();
303 mTriangularMesh.trianglesToNativeFaces() );
304 drawVectorDataOnPoints( nativeFacesInExtent, centroids );
307 void QgsMeshVectorArrowRenderer::drawVectorDataOnEdges()
309 const QList<int> egdesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
310 const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.edgeCentroids();
312 mTriangularMesh.edgesToNativeEdges() );
313 drawVectorDataOnPoints( nativeEdgesInExtent, centroids );
316 void QgsMeshVectorArrowRenderer::drawVectorDataOnGrid( )
318 if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges ||
319 mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
322 const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
323 int cellx = mCfg.userGridCellWidth();
324 int celly = mCfg.userGridCellHeight();
326 const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
327 const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
329 for (
const int i : trianglesInExtent )
331 if ( mContext.renderingStopped() )
336 const int v1 = face[0], v2 = face[1], v3 = face[2];
337 const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
339 const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
342 QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( p1, p2, p3 );
343 int left, right, top, bottom;
344 QgsMeshLayerUtils::boundingBoxToScreenRectangle( mContext.mapToPixel(), mOutputSize, bbox, left, right, top, bottom );
347 if ( left % cellx != 0 )
348 left += cellx - ( left % cellx );
349 if ( right % cellx != 0 )
350 right -= ( right % cellx );
351 if ( top % celly != 0 )
352 top += celly - ( top % celly );
353 if ( bottom % celly != 0 )
354 bottom -= ( bottom % celly );
356 for (
int y = top; y <= bottom; y += celly )
358 for (
int x = left; x <= right; x += cellx )
361 const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( x, y );
363 if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
365 const auto val1 = mDatasetValues.value( v1 );
366 const auto val2 = mDatasetValues.value( v2 );
367 const auto val3 = mDatasetValues.value( v3 );
369 QgsMeshLayerUtils::interpolateFromVerticesData(
377 QgsMeshLayerUtils::interpolateFromVerticesData(
385 else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
387 const auto val1 = mDatasetValues.value( nativeFaceIndex );
389 QgsMeshLayerUtils::interpolateFromFacesData(
396 QgsMeshLayerUtils::interpolateFromFacesData(
403 if ( nodataValue( val.
x(), val.
y() ) )
407 drawVectorArrow( lineStart, val.
x(), val.
y(), val.
scalar() );
413 void QgsMeshVectorArrowRenderer::drawVectorArrow(
const QgsPointXY &lineStart,
double xVal,
double yVal,
double magnitude )
417 double cosAlpha, sinAlpha;
418 if ( calcVectorLineEnd( lineEnd, vectorLength, cosAlpha, sinAlpha,
419 lineStart, xVal, yVal, magnitude ) )
425 QVector<QPointF> finalVectorHeadPoints( 3 );
427 double vectorHeadWidthRatio = mCfg.arrowSettings().arrowHeadWidthRatio();
428 double vectorHeadLengthRatio = mCfg.arrowSettings().arrowHeadLengthRatio();
431 vectorHeadPoints[0].
setX( -1.0 * vectorHeadLengthRatio );
432 vectorHeadPoints[0].
setY( vectorHeadWidthRatio * 0.5 );
435 vectorHeadPoints[1].
setX( 0.0 );
436 vectorHeadPoints[1].
setY( 0.0 );
439 vectorHeadPoints[2].
setX( -1.0 * vectorHeadLengthRatio );
440 vectorHeadPoints[2].
setY( -1.0 * vectorHeadWidthRatio * 0.5 );
443 for (
int j = 0; j < 3; j++ )
445 finalVectorHeadPoints[j].setX( lineEnd.
x()
446 + ( vectorHeadPoints[j].x() * cosAlpha * vectorLength )
447 - ( vectorHeadPoints[j].y() * sinAlpha * vectorLength )
450 finalVectorHeadPoints[j].setY( lineEnd.
y()
451 - ( vectorHeadPoints[j].x() * sinAlpha * vectorLength )
452 - ( vectorHeadPoints[j].y() * cosAlpha * vectorLength )
457 QPen pen( mContext.painter()->pen() );
458 pen.setColor( mVectorColoring.color( magnitude ) );
459 mContext.painter()->setPen( pen );
461 mContext.painter()->drawPolygon( finalVectorHeadPoints );
464 QgsMeshVectorRenderer::~QgsMeshVectorRenderer() =
default;
466 QgsMeshVectorRenderer *QgsMeshVectorRenderer::makeVectorRenderer(
470 const QVector<double> &datasetValuesMag,
471 double datasetMagMaximumValue,
472 double datasetMagMinimumValue,
479 QgsMeshVectorRenderer *renderer =
nullptr;
484 renderer =
new QgsMeshVectorArrowRenderer(
488 datasetMagMaximumValue,
489 datasetMagMinimumValue,
495 renderer =
new QgsMeshVectorStreamlineRenderer(
498 scalarActiveFaceFlagValues,
499 dataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices,
503 datasetMagMaximumValue );
506 renderer =
new QgsMeshVectorTraceRenderer(
509 scalarActiveFaceFlagValues,
510 dataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices,
514 datasetMagMaximumValue );