Add support for Wind Barb rendering for mesh vector datasets

This commit is contained in:
uclaros 2024-03-27 17:16:58 +02:00 committed by Martin Dobias
parent 818986092a
commit 3d4c19d3b3
14 changed files with 1007 additions and 265 deletions

View File

@ -6,6 +6,16 @@ QgsMeshRendererVectorArrowSettings.Scaled = QgsMeshRendererVectorArrowSettings.A
QgsMeshRendererVectorArrowSettings.Fixed = QgsMeshRendererVectorArrowSettings.ArrowScalingMethod.Fixed
QgsMeshRendererVectorStreamlineSettings.MeshGridded = QgsMeshRendererVectorStreamlineSettings.SeedingStartPointsMethod.MeshGridded
QgsMeshRendererVectorStreamlineSettings.Random = QgsMeshRendererVectorStreamlineSettings.SeedingStartPointsMethod.Random
# monkey patching scoped based enum
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MetersPerSecond.__doc__ = "Meters per second"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.KilometersPerHour.__doc__ = "Kilometers per hour"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.Knots.__doc__ = "Knots (Nautical miles per hour)"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MilesPerHour.__doc__ = "Miles per hour"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.FeetPerSecond.__doc__ = "Feet per second"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.OtherUnit.__doc__ = "Other unit"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.__doc__ = "Wind speed units. Wind barbs use knots so we use this enum for preset conversion values\n\n" + '* ``MetersPerSecond``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MetersPerSecond.__doc__ + '\n' + '* ``KilometersPerHour``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.KilometersPerHour.__doc__ + '\n' + '* ``Knots``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.Knots.__doc__ + '\n' + '* ``MilesPerHour``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MilesPerHour.__doc__ + '\n' + '* ``FeetPerSecond``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.FeetPerSecond.__doc__ + '\n' + '* ``OtherUnit``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.OtherUnit.__doc__
# --
QgsMeshRendererVectorSettings.Arrows = QgsMeshRendererVectorSettings.Symbology.Arrows
QgsMeshRendererVectorSettings.Streamlines = QgsMeshRendererVectorSettings.Symbology.Streamlines
QgsMeshRendererVectorSettings.Traces = QgsMeshRendererVectorSettings.Symbology.Traces
QgsMeshRendererVectorSettings.WindBarbs = QgsMeshRendererVectorSettings.Symbology.WindBarbs

View File

@ -419,6 +419,84 @@ Writes configuration to a new DOM element
};
class QgsMeshRendererVectorWindBarbSettings
{
%Docstring(signature="appended")
Represents a mesh renderer settings for vector datasets displayed with wind barbs
.. note::
The API is considered EXPERIMENTAL and can be changed without a notice
.. versionadded:: 3.38
%End
%TypeHeaderCode
#include "qgsmeshrenderersettings.h"
%End
public:
enum class WindSpeedUnit
{
MetersPerSecond,
KilometersPerHour,
Knots,
MilesPerHour,
FeetPerSecond,
OtherUnit
};
double magnitudeMultiplier() const;
%Docstring
Returns the multiplier for the magnitude to convert it to knots
%End
void setMagnitudeMultiplier( double magnitudeMultiplier );
%Docstring
Sets a multiplier for the magnitude to convert it to knots
%End
double shaftLength() const;
%Docstring
Returns the shaft length (in millimeters)
%End
void setShaftLength( double shaftLength );
%Docstring
Sets the shaft length (in millimeters)
%End
Qgis::RenderUnit shaftLengthUnits();
%Docstring
Sets the units for the shaft length
%End
void setShaftLengthUnits( Qgis::RenderUnit shaftLengthUnit );
%Docstring
Returns the units for the shaft length
%End
WindSpeedUnit magnitudeUnits() const;
%Docstring
Returns the units that the data are in
%End
void setMagnitudeUnits( WindSpeedUnit units );
%Docstring
Sets the units that the data are in
%End
QDomElement writeXml( QDomDocument &doc ) const;
%Docstring
Writes configuration to a new DOM element
%End
void readXml( const QDomElement &elem );
%Docstring
Reads configuration from the given DOM element
%End
};
class QgsMeshRendererVectorSettings
{
%Docstring(signature="appended")
@ -444,7 +522,9 @@ Represents a renderer settings for vector datasets
//! Displaying vector dataset with streamlines
Streamlines,
//! Displaying vector dataset with particle traces
Traces
Traces,
//! Displaying vector dataset with wind barbs
WindBarbs
};
double lineWidth() const;
@ -609,6 +689,20 @@ Returns settings for vector rendered with traces
Sets settings for vector rendered with traces
.. versionadded:: 3.12
%End
QgsMeshRendererVectorWindBarbSettings windBarbSettings() const;
%Docstring
Returns settings for vector rendered with wind barbs
.. versionadded:: 3.38
%End
void setWindBarbSettings( const QgsMeshRendererVectorWindBarbSettings &windBarbSettings );
%Docstring
Sets settings for vector rendered with wind barbs
.. versionadded:: 3.38
%End
QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;

View File

@ -0,0 +1,10 @@
# The following has been generated automatically from src/core/mesh/qgsmeshrenderersettings.h
# monkey patching scoped based enum
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MetersPerSecond.__doc__ = "Meters per second"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.KilometersPerHour.__doc__ = "Kilometers per hour"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.Knots.__doc__ = "Knots (Nautical miles per hour)"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MilesPerHour.__doc__ = "Miles per hour"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.FeetPerSecond.__doc__ = "Feet per second"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.OtherUnit.__doc__ = "Other unit"
QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.__doc__ = "Wind speed units. Wind barbs use knots so we use this enum for preset conversion values\n\n" + '* ``MetersPerSecond``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MetersPerSecond.__doc__ + '\n' + '* ``KilometersPerHour``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.KilometersPerHour.__doc__ + '\n' + '* ``Knots``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.Knots.__doc__ + '\n' + '* ``MilesPerHour``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.MilesPerHour.__doc__ + '\n' + '* ``FeetPerSecond``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.FeetPerSecond.__doc__ + '\n' + '* ``OtherUnit``: ' + QgsMeshRendererVectorWindBarbSettings.WindSpeedUnit.OtherUnit.__doc__
# --

View File

@ -419,6 +419,84 @@ Writes configuration to a new DOM element
};
class QgsMeshRendererVectorWindBarbSettings
{
%Docstring(signature="appended")
Represents a mesh renderer settings for vector datasets displayed with wind barbs
.. note::
The API is considered EXPERIMENTAL and can be changed without a notice
.. versionadded:: 3.38
%End
%TypeHeaderCode
#include "qgsmeshrenderersettings.h"
%End
public:
enum class WindSpeedUnit
{
MetersPerSecond,
KilometersPerHour,
Knots,
MilesPerHour,
FeetPerSecond,
OtherUnit
};
double magnitudeMultiplier() const;
%Docstring
Returns the multiplier for the magnitude to convert it to knots
%End
void setMagnitudeMultiplier( double magnitudeMultiplier );
%Docstring
Sets a multiplier for the magnitude to convert it to knots
%End
double shaftLength() const;
%Docstring
Returns the shaft length (in millimeters)
%End
void setShaftLength( double shaftLength );
%Docstring
Sets the shaft length (in millimeters)
%End
Qgis::RenderUnit shaftLengthUnits();
%Docstring
Sets the units for the shaft length
%End
void setShaftLengthUnits( Qgis::RenderUnit shaftLengthUnit );
%Docstring
Returns the units for the shaft length
%End
WindSpeedUnit magnitudeUnits() const;
%Docstring
Returns the units that the data are in
%End
void setMagnitudeUnits( WindSpeedUnit units );
%Docstring
Sets the units that the data are in
%End
QDomElement writeXml( QDomDocument &doc ) const;
%Docstring
Writes configuration to a new DOM element
%End
void readXml( const QDomElement &elem );
%Docstring
Reads configuration from the given DOM element
%End
};
class QgsMeshRendererVectorSettings
{
%Docstring(signature="appended")
@ -444,7 +522,9 @@ Represents a renderer settings for vector datasets
//! Displaying vector dataset with streamlines
Streamlines,
//! Displaying vector dataset with particle traces
Traces
Traces,
//! Displaying vector dataset with wind barbs
WindBarbs
};
double lineWidth() const;
@ -609,6 +689,20 @@ Returns settings for vector rendered with traces
Sets settings for vector rendered with traces
.. versionadded:: 3.12
%End
QgsMeshRendererVectorWindBarbSettings windBarbSettings() const;
%Docstring
Returns settings for vector rendered with wind barbs
.. versionadded:: 3.38
%End
void setWindBarbSettings( const QgsMeshRendererVectorWindBarbSettings &windBarbSettings );
%Docstring
Sets settings for vector rendered with wind barbs
.. versionadded:: 3.38
%End
QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;

View File

@ -612,6 +612,7 @@ QDomElement QgsMeshRendererVectorSettings::writeXml( QDomDocument &doc, const Qg
elem.appendChild( mArrowsSettings.writeXml( doc ) );
elem.appendChild( mStreamLinesSettings.writeXml( doc ) );
elem.appendChild( mTracesSettings.writeXml( doc ) );
elem.appendChild( mWindBarbSettings.writeXml( doc ) );
return elem;
}
@ -644,6 +645,10 @@ void QgsMeshRendererVectorSettings::readXml( const QDomElement &elem, const QgsR
const QDomElement elemTraces = elem.firstChildElement( QStringLiteral( "vector-traces-settings" ) );
if ( ! elemTraces.isNull() )
mTracesSettings.readXml( elemTraces );
const QDomElement elemWindBarb = elem.firstChildElement( QStringLiteral( "vector-windbarb-settings" ) );
if ( ! elemWindBarb.isNull() )
mWindBarbSettings.readXml( elemWindBarb );
}
QgsInterpolatedLineColor::ColoringMethod QgsMeshRendererVectorSettings::coloringMethod() const
@ -744,3 +749,73 @@ bool QgsMeshRendererSettings::hasSettings( int datasetGroupIndex ) const
{
return mRendererScalarSettings.contains( datasetGroupIndex ) || mRendererVectorSettings.contains( datasetGroupIndex );
}
QgsMeshRendererVectorWindBarbSettings QgsMeshRendererVectorSettings::windBarbSettings() const
{
return mWindBarbSettings;
}
void QgsMeshRendererVectorSettings::setWindBarbSettings( const QgsMeshRendererVectorWindBarbSettings &windBarbSettings )
{
mWindBarbSettings = windBarbSettings;
}
void QgsMeshRendererVectorWindBarbSettings::readXml( const QDomElement &elem )
{
mShaftLength = elem.attribute( QStringLiteral( "shaft-length" ), QStringLiteral( "10" ) ).toDouble();
mShaftLengthUnits = static_cast<Qgis::RenderUnit>(
elem.attribute( QStringLiteral( "shaft-length-units" ) ).toInt() );
mMagnitudeMultiplier = elem.attribute( QStringLiteral( "magnitude-multiplier" ), QStringLiteral( "1" ) ).toDouble();
mMagnitudeUnits = static_cast<WindSpeedUnit>(
elem.attribute( QStringLiteral( "magnitude-units" ), QStringLiteral( "0" ) ).toInt() );
}
QDomElement QgsMeshRendererVectorWindBarbSettings::writeXml( QDomDocument &doc ) const
{
QDomElement elem = doc.createElement( QStringLiteral( "vector-windbarb-settings" ) );
elem.setAttribute( QStringLiteral( "shaft-length" ), mShaftLength );
elem.setAttribute( QStringLiteral( "shaft-length-units" ), static_cast< int >( mShaftLengthUnits ) );
elem.setAttribute( QStringLiteral( "magnitude-multiplier" ), mMagnitudeMultiplier );
elem.setAttribute( QStringLiteral( "magnitude-units" ), static_cast< int >( mMagnitudeUnits ) );
return elem;
}
double QgsMeshRendererVectorWindBarbSettings::magnitudeMultiplier() const
{
return mMagnitudeMultiplier;
}
void QgsMeshRendererVectorWindBarbSettings::setMagnitudeMultiplier( double magnitudeMultiplier )
{
mMagnitudeMultiplier = magnitudeMultiplier;
}
double QgsMeshRendererVectorWindBarbSettings::shaftLength() const
{
return mShaftLength;
}
void QgsMeshRendererVectorWindBarbSettings::setShaftLength( double shaftLength )
{
mShaftLength = shaftLength;
}
Qgis::RenderUnit QgsMeshRendererVectorWindBarbSettings::shaftLengthUnits()
{
return mShaftLengthUnits;
}
void QgsMeshRendererVectorWindBarbSettings::setShaftLengthUnits( Qgis::RenderUnit shaftLengthUnit )
{
mShaftLengthUnits = shaftLengthUnit;
}
QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit QgsMeshRendererVectorWindBarbSettings::magnitudeUnits() const
{
return mMagnitudeUnits;
}
void QgsMeshRendererVectorWindBarbSettings::setMagnitudeUnits( WindSpeedUnit units )
{
mMagnitudeUnits = units;
}

View File

@ -395,6 +395,81 @@ class CORE_EXPORT QgsMeshRendererVectorTracesSettings
};
/**
* \ingroup core
*
* \brief Represents a mesh renderer settings for vector datasets displayed with wind barbs
*
* \note The API is considered EXPERIMENTAL and can be changed without a notice
*
* \since QGIS 3.38
*/
class CORE_EXPORT QgsMeshRendererVectorWindBarbSettings
{
public:
//! Wind speed units. Wind barbs use knots so we use this enum for preset conversion values
enum class WindSpeedUnit
{
MetersPerSecond = 0, //!< Meters per second
KilometersPerHour, //!< Kilometers per hour
Knots, //!< Knots (Nautical miles per hour)
MilesPerHour, //!< Miles per hour
FeetPerSecond, //!< Feet per second
OtherUnit //!< Other unit
};
/**
* Returns the multiplier for the magnitude to convert it to knots
*/
double magnitudeMultiplier() const;
/**
* Sets a multiplier for the magnitude to convert it to knots
*/
void setMagnitudeMultiplier( double magnitudeMultiplier );
/**
* Returns the shaft length (in millimeters)
*/
double shaftLength() const;
/**
* Sets the shaft length (in millimeters)
*/
void setShaftLength( double shaftLength );
/**
* Sets the units for the shaft length
*/
Qgis::RenderUnit shaftLengthUnits();
/**
* Returns the units for the shaft length
*/
void setShaftLengthUnits( Qgis::RenderUnit shaftLengthUnit );
/**
* Returns the units that the data are in
*/
WindSpeedUnit magnitudeUnits() const;
/**
* Sets the units that the data are in
*/
void setMagnitudeUnits( WindSpeedUnit units );
//! Writes configuration to a new DOM element
QDomElement writeXml( QDomDocument &doc ) const;
//! Reads configuration from the given DOM element
void readXml( const QDomElement &elem );
private:
double mShaftLength = 10;
Qgis::RenderUnit mShaftLengthUnits = Qgis::RenderUnit::Millimeters;
WindSpeedUnit mMagnitudeUnits = WindSpeedUnit::MetersPerSecond;
double mMagnitudeMultiplier = 1;
};
/**
* \ingroup core
*
@ -419,7 +494,9 @@ class CORE_EXPORT QgsMeshRendererVectorSettings
//! Displaying vector dataset with streamlines
Streamlines,
//! Displaying vector dataset with particle traces
Traces
Traces,
//! Displaying vector dataset with wind barbs
WindBarbs
};
//! Returns line width of the arrow (in millimeters)
@ -551,6 +628,18 @@ class CORE_EXPORT QgsMeshRendererVectorSettings
*/
void setTracesSettings( const QgsMeshRendererVectorTracesSettings &tracesSettings );
/**
* Returns settings for vector rendered with wind barbs
* \since QGIS 3.38
*/
QgsMeshRendererVectorWindBarbSettings windBarbSettings() const;
/**
* Sets settings for vector rendered with wind barbs
* \since QGIS 3.38
*/
void setWindBarbSettings( const QgsMeshRendererVectorWindBarbSettings &windBarbSettings );
//! Writes configuration to a new DOM element
QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
//! Reads configuration from the given DOM element
@ -573,6 +662,7 @@ class CORE_EXPORT QgsMeshRendererVectorSettings
QgsMeshRendererVectorArrowSettings mArrowsSettings;
QgsMeshRendererVectorStreamlineSettings mStreamLinesSettings;
QgsMeshRendererVectorTracesSettings mTracesSettings;
QgsMeshRendererVectorWindBarbSettings mWindBarbSettings;
};
/**

View File

@ -62,11 +62,11 @@ QgsMeshVectorArrowRenderer::QgsMeshVectorArrowRenderer(
, mDatasetValuesMag( datasetValuesMag )
, mMinMag( datasetMagMinimumValue )
, mMaxMag( datasetMagMaximumValue )
, mDataType( dataType )
, mBufferedExtent( context.mapExtent() )
, mContext( context )
, mCfg( settings )
, mDataType( dataType )
, mOutputSize( size )
, mBufferedExtent( context.mapExtent() )
{
// should be checked in caller
Q_ASSERT( !mDatasetValuesMag.empty() );
@ -292,7 +292,7 @@ void QgsMeshVectorArrowRenderer::drawVectorDataOnPoints( const QSet<int> indexes
const double V = mDatasetValuesMag[i]; // pre-calculated magnitude
const QgsPointXY lineStart = mContext.mapToPixel().transform( center.x(), center.y() );
drawVectorArrow( lineStart, xVal, yVal, V );
drawVector( lineStart, xVal, yVal, V );
}
}
@ -405,13 +405,13 @@ void QgsMeshVectorArrowRenderer::drawVectorDataOnGrid( )
continue;
const QgsPointXY lineStart( x, y );
drawVectorArrow( lineStart, val.x(), val.y(), val.scalar() );
drawVector( lineStart, val.x(), val.y(), val.scalar() );
}
}
}
}
void QgsMeshVectorArrowRenderer::drawVectorArrow( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude )
void QgsMeshVectorArrowRenderer::drawVector( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude )
{
QgsPointXY lineEnd;
double vectorLength;
@ -518,10 +518,163 @@ QgsMeshVectorRenderer *QgsMeshVectorRenderer::makeVectorRenderer(
layerExtent,
datasetMagMaximumValue );
break;
case QgsMeshRendererVectorSettings::WindBarbs:
renderer = new QgsMeshVectorWindBarbRenderer(
m,
datasetVectorValues,
datasetValuesMag,
datasetMagMaximumValue,
datasetMagMinimumValue,
dataType,
settings,
context,
size );
break;
}
return renderer;
}
QgsMeshVectorWindBarbRenderer::QgsMeshVectorWindBarbRenderer(
const QgsTriangularMesh &m,
const QgsMeshDataBlock &datasetValues,
const QVector<double> &datasetValuesMag,
double datasetMagMaximumValue, double datasetMagMinimumValue,
QgsMeshDatasetGroupMetadata::DataType dataType,
const QgsMeshRendererVectorSettings &settings,
QgsRenderContext &context,
QSize size ) : QgsMeshVectorArrowRenderer( m,
datasetValues,
datasetValuesMag,
datasetMagMinimumValue,
datasetMagMaximumValue,
dataType,
settings,
context,
size )
{
}
QgsMeshVectorWindBarbRenderer::~QgsMeshVectorWindBarbRenderer() = default;
void QgsMeshVectorWindBarbRenderer::drawVector( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude )
{
// do not render if magnitude is outside of the filtered range (if filtering is enabled)
if ( mCfg.filterMin() >= 0 && magnitude < mCfg.filterMin() )
return;
if ( mCfg.filterMax() >= 0 && magnitude > mCfg.filterMax() )
return;
QPen pen( mContext.painter()->pen() );
pen.setColor( mVectorColoring.color( magnitude ) );
mContext.painter()->setPen( pen );
// we need a brush to fill center circle and pennants
QBrush brush( pen.color() );
mContext.painter()->setBrush( brush );
const double shaftLength = mContext.convertToPainterUnits( mCfg.windBarbSettings().shaftLength(),
mCfg.windBarbSettings().shaftLengthUnits() );
const double d = shaftLength / 25; // this is a magic number ratio between shaft length and other barb dimensions
const double centerRadius = d;
const double zeroCircleRadius = 2 * d;
const double barbLength = 8 * d + pen.widthF();
const double barbAngle = 135;
const double barbOffset = 2 * d + pen.widthF();
// Determine the angle of the vector, counter-clockwise, from east
// (and associated trigs)
const double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal ) - mContext.mapToPixel().mapRotation() * M_DEG2RAD;
const double cosAlpha = cos( vectorAngle ) * mag( xVal );
const double sinAlpha = sin( vectorAngle ) * mag( xVal );
// Now determine the X and Y distances of the end of the line from the start
// Flip the Y axis (pixel vs real-world axis)
const double xDist = cosAlpha * shaftLength;
const double yDist = - sinAlpha * shaftLength;
if ( std::abs( xDist ) < 1 && std::abs( yDist ) < 1 )
return;
// Determine the line coords
const QgsPointXY lineEnd = QgsPointXY( lineStart.x() - xDist,
lineStart.y() - yDist );
// Check to see if both of the coords are outside the QImage area, if so, skip the whole vector
if ( ( lineStart.x() < 0 || lineStart.x() > mOutputSize.width() ||
lineStart.y() < 0 || lineStart.y() > mOutputSize.height() ) &&
( lineEnd.x() < 0 || lineEnd.x() > mOutputSize.width() ||
lineEnd.y() < 0 || lineEnd.y() > mOutputSize.height() ) )
return;
// scale the magnitude to convert it to knots
double knots = magnitude * mCfg.windBarbSettings().magnitudeMultiplier() ;
QgsPointXY nextLineOrigin = lineEnd;
// special case for no wind, just an empty circle
if ( knots < 2.5 )
{
mContext.painter()->setBrush( Qt::NoBrush );
mContext.painter()->drawEllipse( lineStart.toQPointF(), zeroCircleRadius, zeroCircleRadius );
mContext.painter()->setBrush( brush );
return;
}
const double azimuth = lineEnd.azimuth( lineStart );
// conditionally draw the shaft
if ( knots < 47.5 && knots > 7.5 )
{
// When first barb is a '10', we want to draw the shaft and barb as a single polyline for a proper join
const QVector< QPointF > pts{ lineStart.toQPointF(),
lineEnd.toQPointF(),
nextLineOrigin.project( barbLength, azimuth + barbAngle ).toQPointF() };
mContext.painter()->drawPolyline( pts );
nextLineOrigin = nextLineOrigin.project( barbOffset, azimuth );
knots -= 10;
}
else
{
// draw just the shaft
mContext.painter()->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
}
// draw the center circle
mContext.painter()->drawEllipse( lineStart.toQPointF(), centerRadius, centerRadius );
// draw pennants (50)
while ( knots > 47.5 )
{
const QVector< QPointF > pts{ nextLineOrigin.toQPointF(),
nextLineOrigin.project( barbLength / 1.414, azimuth + 90 ).toQPointF(),
nextLineOrigin.project( barbLength / 1.414, azimuth ).toQPointF() };
mContext.painter()->drawPolygon( pts );
knots -= 50;
// don't use an offset for the next pennant
if ( knots > 47.5 )
nextLineOrigin = nextLineOrigin.project( barbLength / 1.414, azimuth );
else
nextLineOrigin = nextLineOrigin.project( barbLength / 1.414 + barbOffset, azimuth );
}
// draw large barbs (10)
while ( knots > 7.5 )
{
mContext.painter()->drawLine( nextLineOrigin.toQPointF(), nextLineOrigin.project( barbLength, azimuth + barbAngle ).toQPointF() );
nextLineOrigin = nextLineOrigin.project( barbOffset, azimuth );
knots -= 10;
}
// draw small barb (5)
if ( knots > 2.5 )
{
// a single '5' barb should not start at the line end
if ( nextLineOrigin == lineEnd )
nextLineOrigin = nextLineOrigin.project( barbLength / 2, azimuth );
mContext.painter()->drawLine( nextLineOrigin.toQPointF(), nextLineOrigin.project( barbLength / 2, azimuth + barbAngle ).toQPointF() );
}
}
///@endcond

View File

@ -105,7 +105,7 @@ class QgsMeshVectorArrowRenderer : public QgsMeshVectorRenderer
//! Draws data on user-defined grid
void drawVectorDataOnGrid( );
//! Draws arrow from start point and vector data
void drawVectorArrow( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude );
virtual void drawVector( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude );
//! Calculates the end point of the arrow based on start point and vector data
bool calcVectorLineEnd( QgsPointXY &lineEnd,
double &vectorLength,
@ -130,18 +130,46 @@ class QgsMeshVectorArrowRenderer : public QgsMeshVectorRenderer
const QVector<double> &mDatasetValuesMag; //magnitudes
double mMinMag = 0.0;
double mMaxMag = 0.0;
QgsRenderContext &mContext;
const QgsMeshRendererVectorSettings mCfg;
QgsMeshDatasetGroupMetadata::DataType mDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnVertices;
QSize mOutputSize;
QgsRectangle mBufferedExtent;
QPen mPen;
protected:
QgsRenderContext &mContext;
const QgsMeshRendererVectorSettings mCfg;
QSize mOutputSize;
QgsInterpolatedLineColor mVectorColoring;
};
/**
* \ingroup core
*
* \brief Helper private class for rendering vector datasets using Wind Barbs
*
* \note not available in Python bindings
* \since QGIS 3.38
*/
class QgsMeshVectorWindBarbRenderer : public QgsMeshVectorArrowRenderer
{
public:
//! Ctor
QgsMeshVectorWindBarbRenderer( const QgsTriangularMesh &m,
const QgsMeshDataBlock &datasetValues,
const QVector<double> &datasetValuesMag,
double datasetMagMaximumValue,
double datasetMagMinimumValue,
QgsMeshDatasetGroupMetadata::DataType dataType,
const QgsMeshRendererVectorSettings &settings,
QgsRenderContext &context,
QSize size );
//! Dtor
~QgsMeshVectorWindBarbRenderer() override;
private:
void drawVector( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude ) override;
};
///@endcond

View File

@ -27,7 +27,8 @@ QgsMeshRendererVectorSettingsWidget::QgsMeshRendererVectorSettingsWidget( QWidge
widgets << mMinMagSpinBox << mMaxMagSpinBox
<< mHeadWidthSpinBox << mHeadLengthSpinBox
<< mMinimumShaftSpinBox << mMaximumShaftSpinBox
<< mScaleShaftByFactorOfSpinBox << mShaftLengthSpinBox;
<< mScaleShaftByFactorOfSpinBox << mShaftLengthSpinBox
<< mWindBarbLengthSpinBox << mWindBarbMagnitudeMultiplierSpinBox;
// Setup defaults and clear values for spin boxes
for ( const auto &widget : std::as_const( widgets ) )
@ -48,6 +49,9 @@ QgsMeshRendererVectorSettingsWidget::QgsMeshRendererVectorSettingsWidget( QWidge
mTracesParticlesCountSpinBox->setClearValue( 1000 );
mTracesMaxLengthSpinBox->setClearValue( 100.0 );
mWindBarbLengthSpinBox->setClearValue( 10.0 );
mWindBarbMagnitudeMultiplierSpinBox->setClearValue( 1.0 );
connect( mColorWidget, &QgsColorButton::colorChanged, this, &QgsMeshRendererVectorSettingsWidget::widgetChanged );
connect( mColoringMethodComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsMeshRendererVectorSettingsWidget::onColoringMethodChanged );
@ -114,6 +118,19 @@ QgsMeshRendererVectorSettingsWidget::QgsMeshRendererVectorSettingsWidget( QWidge
connect( mTracesTailLengthMapUnitWidget, &QgsUnitSelectionWidget::changed,
this, &QgsMeshRendererVectorSettingsWidget::widgetChanged );
mWindBarbLengthMapUnitWidget->setUnits(
{
Qgis::RenderUnit::Millimeters,
Qgis::RenderUnit::Pixels,
Qgis::RenderUnit::Points
} );
connect( mWindBarbLengthMapUnitWidget, &QgsUnitSelectionWidget::changed,
this, &QgsMeshRendererVectorSettingsWidget::widgetChanged );
connect( mWindBarbUnitsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsMeshRendererVectorSettingsWidget::onWindBarbUnitsChanged );
onWindBarbUnitsChanged( 0 );
}
void QgsMeshRendererVectorSettingsWidget::setLayer( QgsMeshLayer *layer )
@ -191,6 +208,15 @@ QgsMeshRendererVectorSettings QgsMeshRendererVectorSettingsWidget::settings() co
tracesSettings.setParticlesCount( mTracesParticlesCountSpinBox->value() );
settings.setTracesSettings( tracesSettings );
// Wind Barb settings
QgsMeshRendererVectorWindBarbSettings windBarbSettings;
windBarbSettings.setShaftLength( mWindBarbLengthSpinBox->value() );
windBarbSettings.setShaftLengthUnits( mWindBarbLengthMapUnitWidget->unit() );
windBarbSettings.setMagnitudeUnits(
static_cast<QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit>( mWindBarbUnitsComboBox->currentIndex() ) );
windBarbSettings.setMagnitudeMultiplier( mWindBarbMagnitudeMultiplierSpinBox->value() );
settings.setWindBarbSettings( windBarbSettings );
return settings;
}
@ -264,6 +290,12 @@ void QgsMeshRendererVectorSettingsWidget::syncToLayer( )
mTracesTailLengthMapUnitWidget->setUnit( tracesSettings.maximumTailLengthUnit() );
mTracesParticlesCountSpinBox->setValue( tracesSettings.particlesCount() );
// Wind Barb settings
const QgsMeshRendererVectorWindBarbSettings windBarbSettings = settings.windBarbSettings();
mWindBarbLengthSpinBox->setValue( windBarbSettings.shaftLength() );
mWindBarbMagnitudeMultiplierSpinBox->setValue( windBarbSettings.magnitudeMultiplier() );
mWindBarbUnitsComboBox->setCurrentIndex( static_cast<int>( windBarbSettings.magnitudeUnits() ) );
onWindBarbUnitsChanged( static_cast<int>( windBarbSettings.magnitudeUnits() ) );
}
void QgsMeshRendererVectorSettingsWidget::onSymbologyChanged( int currentIndex )
@ -272,6 +304,7 @@ void QgsMeshRendererVectorSettingsWidget::onSymbologyChanged( int currentIndex )
mArrowLengthGroupBox->setVisible( currentIndex == QgsMeshRendererVectorSettings::Arrows );
mHeadOptionsGroupBox->setVisible( currentIndex == QgsMeshRendererVectorSettings::Arrows );
mTracesGroupBox->setVisible( currentIndex == QgsMeshRendererVectorSettings::Traces );
mWindBarbGroupBox->setVisible( currentIndex == QgsMeshRendererVectorSettings::WindBarbs );
mDisplayVectorsOnGridGroupBox->setVisible( currentIndex != QgsMeshRendererVectorSettings::Traces );
filterByMagnitudeLabel->setVisible( currentIndex != QgsMeshRendererVectorSettings::Traces );
@ -282,6 +315,7 @@ void QgsMeshRendererVectorSettingsWidget::onSymbologyChanged( int currentIndex )
mDisplayVectorsOnGridGroupBox->setEnabled(
currentIndex == QgsMeshRendererVectorSettings::Arrows ||
currentIndex == QgsMeshRendererVectorSettings::WindBarbs ||
( currentIndex == QgsMeshRendererVectorSettings::Streamlines &&
mStreamlinesSeedingMethodComboBox->currentIndex() == QgsMeshRendererVectorStreamlineSettings::MeshGridded ) ) ;
}
@ -295,6 +329,36 @@ void QgsMeshRendererVectorSettingsWidget::onStreamLineSeedingMethodChanged( int
mDisplayVectorsOnGridGroupBox->setEnabled( !enabled );
}
void QgsMeshRendererVectorSettingsWidget::onWindBarbUnitsChanged( int currentIndex )
{
const QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit units =
static_cast<QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit>( currentIndex );
double multiplier;
switch ( units )
{
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::Knots:
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::OtherUnit:
multiplier = 1.0;
break;
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::MetersPerSecond:
multiplier = 3600.0 / 1852.0;
break;
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::KilometersPerHour:
multiplier = 1.852;
break;
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::MilesPerHour:
multiplier = 1.609344 / 1.852;
break;
case QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::FeetPerSecond:
multiplier = 3600.0 / 1.852 / 5280.0 * 1.609344 ;
break;
}
mWindBarbMagnitudeMultiplierLabel->setVisible( units == QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::OtherUnit );
mWindBarbMagnitudeMultiplierSpinBox->setVisible( units == QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::OtherUnit );
mWindBarbMagnitudeMultiplierSpinBox->setValue( multiplier );
}
void QgsMeshRendererVectorSettingsWidget::onColoringMethodChanged()
{
mColorRampShaderGroupBox->setVisible( mColoringMethodComboBox->currentData() == QgsInterpolatedLineColor::ColorRamp );

View File

@ -68,6 +68,7 @@ class QgsMeshRendererVectorSettingsWidget : public QWidget, private Ui::QgsMeshR
private slots:
void onSymbologyChanged( int currentIndex );
void onStreamLineSeedingMethodChanged( int currentIndex );
void onWindBarbUnitsChanged( int currentIndex );
void onColoringMethodChanged();
void onColorRampMinMaxChanged();
void loadColorRampShader();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>399</width>
<height>861</height>
<width>426</width>
<height>1006</height>
</rect>
</property>
<property name="windowTitle">
@ -26,20 +26,7 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="5" column="1">
<widget class="QgsColorButton" name="mColorWidget">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="mColoringMethodComboBox"/>
</item>
<item row="15" column="0">
<item row="16" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -52,94 +39,65 @@
</property>
</spacer>
</item>
<item row="14" column="0" colspan="2">
<widget class="QGroupBox" name="mTracesGroupBox">
<property name="title">
<string>Traces</string>
<item row="7" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="filterByMagnitudeLabel">
<property name="text">
<string>Filter by magnitude</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="maximumMagLabel">
<property name="text">
<string>Max</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QgsDoubleSpinBox" name="mMaxMagSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<double>-1000000000000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000000000.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="minimumMagLabel">
<property name="text">
<string>Min</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QgsDoubleSpinBox" name="mMinMagSpinBox">
<property name="minimum">
<double>-1000000000000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000000000.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<widget class="QgsColorButton" name="mColorWidget">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Particles count</string>
</property>
</widget>
</item>
<item>
<widget class="QgsSpinBox" name="mTracesParticlesCountSpinBox">
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max tail length</string>
</property>
</widget>
</item>
<item>
<widget class="QgsDoubleSpinBox" name="mTracesMaxLengthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>99999999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QgsUnitSelectionWidget" name="mTracesTailLengthMapUnitWidget" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="6" column="0" colspan="2">
@ -231,13 +189,43 @@
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Coloring Method</string>
<item row="4" column="1">
<widget class="QComboBox" name="mColoringMethodComboBox"/>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="mLineWidthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mSymbologyVectorComboBox">
<item>
<property name="text">
<string>Arrows</string>
</property>
</item>
<item>
<property name="text">
<string>Streamlines</string>
</property>
</item>
<item>
<property name="text">
<string>Traces</string>
</property>
</item>
<item>
<property name="text">
<string>Wind Barbs</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -256,75 +244,69 @@
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mSymbologyVectorComboBox">
<item>
<property name="text">
<string>Arrows</string>
</property>
</item>
<item>
<property name="text">
<string>Streamlines</string>
</property>
</item>
<item>
<property name="text">
<string>Traces</string>
</property>
</item>
<item row="11" column="0" colspan="2">
<widget class="QGroupBox" name="mHeadOptionsGroupBox">
<property name="title">
<string>Head Options</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="2">
<widget class="QLabel" name="percShaftLenLabel_2">
<property name="text">
<string>% of shaft length</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsDoubleSpinBox" name="mHeadWidthSpinBox">
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="mHeadLengthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="percShaftLenLabel">
<property name="text">
<string>% of shaft length</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="headLengthLabel">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="headWidthLabel">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="7" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="filterByMagnitudeLabel">
<property name="text">
<string>Filter by magnitude</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="maximumMagLabel">
<property name="text">
<string>Max</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QgsDoubleSpinBox" name="mMaxMagSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<double>-1000000000000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000000000.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="minimumMagLabel">
<property name="text">
<string>Min</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QgsDoubleSpinBox" name="mMinMagSpinBox">
<property name="minimum">
<double>-1000000000000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000000000.000000000000000</double>
</property>
</widget>
</item>
</layout>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Coloring Method</string>
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="QGroupBox" name="mStreamlineWidget">
@ -376,20 +358,6 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="symbologyLabel">
<property name="text">
<string>Symbology</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Line width</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QGroupBox" name="mDisplayVectorsOnGridGroupBox">
<property name="title">
@ -457,61 +425,18 @@
</layout>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QGroupBox" name="mHeadOptionsGroupBox">
<property name="title">
<string>Head Options</string>
<item row="2" column="0">
<widget class="QLabel" name="symbologyLabel">
<property name="text">
<string>Symbology</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Line width</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="2">
<widget class="QLabel" name="percShaftLenLabel_2">
<property name="text">
<string>% of shaft length</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsDoubleSpinBox" name="mHeadWidthSpinBox">
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="mHeadLengthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="percShaftLenLabel">
<property name="text">
<string>% of shaft length</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="headLengthLabel">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="headWidthLabel">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
@ -521,16 +446,6 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="mLineWidthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="12" column="0" colspan="2">
<widget class="QGroupBox" name="mArrowLengthGroupBox">
<property name="title">
@ -670,6 +585,184 @@
</layout>
</widget>
</item>
<item row="14" column="0" colspan="2">
<widget class="QGroupBox" name="mTracesGroupBox">
<property name="title">
<string>Traces</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Particles count</string>
</property>
</widget>
</item>
<item>
<widget class="QgsSpinBox" name="mTracesParticlesCountSpinBox">
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max tail length</string>
</property>
</widget>
</item>
<item>
<widget class="QgsDoubleSpinBox" name="mTracesMaxLengthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>99999999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QgsUnitSelectionWidget" name="mTracesTailLengthMapUnitWidget" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="15" column="0" colspan="2">
<widget class="QGroupBox" name="mWindBarbGroupBox">
<property name="title">
<string>Wind Barbs</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="1" column="0">
<widget class="QLabel" name="windBarbLengthLabel">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="windBarbUnitsLabel">
<property name="text">
<string>Data units</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mWindBarbUnitsComboBox">
<property name="toolTip">
<string>Select the units the data are in.&lt;br&gt;Values are converted to knots for rendering the wind barbs.</string>
</property>
<item>
<property name="text">
<string>m/s</string>
</property>
</item>
<item>
<property name="text">
<string>km/h</string>
</property>
</item>
<item>
<property name="text">
<string>knots</string>
</property>
</item>
<item>
<property name="text">
<string>mi/h</string>
</property>
</item>
<item>
<property name="text">
<string>ft/s</string>
</property>
</item>
<item>
<property name="text">
<string>other units</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mWindBarbMagnitudeMultiplierLabel">
<property name="text">
<string>Multiplier</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="mWindBarbMagnitudeMultiplierSpinBox">
<property name="toolTip">
<string>Data will be multiplied by this value to be converted to knots (nautical miles per hour)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QgsDoubleSpinBox" name="mWindBarbLengthSpinBox">
<property name="toolTip">
<string>This defines the shaft length.&lt;br&gt;The pennants and barbs are scaled proportionally.</string>
</property>
</widget>
</item>
<item>
<widget class="QgsUnitSelectionWidget" name="mWindBarbLengthMapUnitWidget" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -85,6 +85,7 @@ class TestQgsMeshRenderer : public QgsTest
void test_face_vector_on_user_grid();
void test_face_vector_on_user_grid_streamlines();
void test_vertex_vector_on_user_grid();
void test_vertex_vector_on_user_grid_wind_barbs();
void test_vertex_vector_on_user_grid_streamlines();
void test_vertex_vector_on_user_grid_streamlines_colorRamp();
void test_vertex_vector_traces();
@ -161,6 +162,7 @@ void TestQgsMeshRenderer::initTestCase()
// Mdal layer
mMdalLayer = new QgsMeshLayer( mDataDir + "/quad_and_triangle.2dm", "Triangle and Quad Mdal", "mdal" );
mMdalLayer->dataProvider()->addDataset( mDataDir + "/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
mMdalLayer->dataProvider()->addDataset( mDataDir + "/quad_and_triangle_vertex_vector2.dat" );
QVERIFY( mMdalLayer->isValid() );
// Memory layer
@ -474,6 +476,34 @@ void TestQgsMeshRenderer::test_vertex_scalar_dataset_with_inactive_face_renderin
QVERIFY( imageCheck( "quad_and_triangle_vertex_scalar_dataset_with_inactive_face", mMdalLayer ) );
}
void TestQgsMeshRenderer::test_vertex_vector_on_user_grid_wind_barbs()
{
const QgsMeshDatasetIndex ds( 2, 0 );
const QgsMeshDatasetGroupMetadata metadata = mMdalLayer->dataProvider()->datasetGroupMetadata( ds );
QCOMPARE( metadata.name(), QStringLiteral( "VertexVectorDataset2" ) );
QgsMeshRendererSettings rendererSettings = mMdalLayer->rendererSettings();
QgsMeshRendererVectorSettings settings = rendererSettings.vectorSettings( ds.group() );
settings.setOnUserDefinedGrid( true );
settings.setUserGridCellWidth( 30 );
settings.setUserGridCellHeight( 30 );
settings.setLineWidth( 0.5 );
settings.setSymbology( QgsMeshRendererVectorSettings::WindBarbs );
settings.setColoringMethod( QgsInterpolatedLineColor::SingleColor );
QgsMeshRendererVectorWindBarbSettings windBarbSettings = settings.windBarbSettings();
windBarbSettings.setShaftLength( 20 );
windBarbSettings.setShaftLengthUnits( Qgis::RenderUnit::Pixels );
windBarbSettings.setMagnitudeUnits( QgsMeshRendererVectorWindBarbSettings::WindSpeedUnit::OtherUnit );
windBarbSettings.setMagnitudeMultiplier( 2 );
settings.setWindBarbSettings( windBarbSettings );
rendererSettings.setVectorSettings( ds.group(), settings );
mMdalLayer->setRendererSettings( rendererSettings );
mMdalLayer->setStaticVectorDatasetIndex( ds );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset_wind_barbs", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset_wind_barbs_rotated_45", mMemoryLayer, 45.0 ) );
}
void TestQgsMeshRenderer::test_face_vector_on_user_grid()
{
const QgsMeshDatasetIndex ds( 3, 0 );