Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesh Render Extent Settings #59305

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions python/PyQt6/core/auto_additions/qgsmeshrenderersettings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# The following has been generated automatically from src/core/mesh/qgsmeshrenderersettings.h
QgsMeshRendererScalarSettings.NoResampling = QgsMeshRendererScalarSettings.DataResamplingMethod.NoResampling
QgsMeshRendererScalarSettings.NeighbourAverage = QgsMeshRendererScalarSettings.DataResamplingMethod.NeighbourAverage
# monkey patching scoped based enum
QgsMeshRendererScalarSettings.MinMaxValueType.UserDefined.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.WholeMesh.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.FixedCanvas.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.InteractiveFromCanvas.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.__doc__ = """This enumerator describes the extent used to compute min/max values

* ``UserDefined``:
* ``WholeMesh``:
* ``FixedCanvas``:
* ``InteractiveFromCanvas``:

"""
# --
QgsMeshRendererVectorArrowSettings.MinMax = QgsMeshRendererVectorArrowSettings.ArrowScalingMethod.MinMax
QgsMeshRendererVectorArrowSettings.Scaled = QgsMeshRendererVectorArrowSettings.ArrowScalingMethod.Scaled
QgsMeshRendererVectorArrowSettings.Fixed = QgsMeshRendererVectorArrowSettings.ArrowScalingMethod.Fixed
Expand Down
13 changes: 13 additions & 0 deletions python/PyQt6/core/auto_generated/mesh/qgsmeshlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,19 @@ Sets labeling configuration. Takes ownership of the object.
.. versionadded:: 3.36
%End

bool minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min /Out/, double &max /Out/ );
%Docstring
Extracts minimum and maximum value for active scalar dataset on mesh faces.

:param extent: extent in which intersecting faces are searched for
:param datasetIndex: index for which dataset the values should be extracted

:return: - ``True`` if values were extracted
- min: minimal value
- max: maximal value

.. versionadded:: 3.42
%End

public slots:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ Represents a mesh renderer settings for scalar datasets
NeighbourAverage,
};

enum class MinMaxValueType
{
UserDefined,
WholeMesh,
FixedCanvas,
InteractiveFromCanvas,
};

QgsColorRampShader colorRampShader() const;
%Docstring
Returns color ramp shader function
Expand Down Expand Up @@ -178,6 +186,20 @@ Returns the stroke width unit used to render edges scalar dataset
Sets the stroke width unit used to render edges scalar dataset

.. versionadded:: 3.14
%End

QgsMeshRendererScalarSettings::MinMaxValueType minMaxValueType() const;
%Docstring
Gets the extent type for minimum maximum calculation

.. versionadded:: 3.42
%End

void setMinMaxValueType( QgsMeshRendererScalarSettings::MinMaxValueType minMaxValueType );
%Docstring
Sets the extent type for minimum maximum calculation

.. versionadded:: 3.42
%End

QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
Expand Down
14 changes: 14 additions & 0 deletions python/core/auto_additions/qgsmeshrenderersettings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# The following has been generated automatically from src/core/mesh/qgsmeshrenderersettings.h
# monkey patching scoped based enum
QgsMeshRendererScalarSettings.MinMaxValueType.UserDefined.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.WholeMesh.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.FixedCanvas.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.InteractiveFromCanvas.__doc__ = ""
QgsMeshRendererScalarSettings.MinMaxValueType.__doc__ = """This enumerator describes the extent used to compute min/max values

* ``UserDefined``:
* ``WholeMesh``:
* ``FixedCanvas``:
* ``InteractiveFromCanvas``:

"""
# --
# 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)"
Expand Down
13 changes: 13 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,19 @@ Sets labeling configuration. Takes ownership of the object.
.. versionadded:: 3.36
%End

bool minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min /Out/, double &max /Out/ );
%Docstring
Extracts minimum and maximum value for active scalar dataset on mesh faces.

:param extent: extent in which intersecting faces are searched for
:param datasetIndex: index for which dataset the values should be extracted

:return: - ``True`` if values were extracted
- min: minimal value
- max: maximal value

.. versionadded:: 3.42
%End

public slots:

Expand Down
22 changes: 22 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ Represents a mesh renderer settings for scalar datasets
NeighbourAverage,
};

enum class MinMaxValueType
{
UserDefined,
WholeMesh,
FixedCanvas,
InteractiveFromCanvas,
};

QgsColorRampShader colorRampShader() const;
%Docstring
Returns color ramp shader function
Expand Down Expand Up @@ -178,6 +186,20 @@ Returns the stroke width unit used to render edges scalar dataset
Sets the stroke width unit used to render edges scalar dataset

.. versionadded:: 3.14
%End

QgsMeshRendererScalarSettings::MinMaxValueType minMaxValueType() const;
%Docstring
Gets the extent type for minimum maximum calculation

.. versionadded:: 3.42
%End

void setMinMaxValueType( QgsMeshRendererScalarSettings::MinMaxValueType minMaxValueType );
%Docstring
Sets the extent type for minimum maximum calculation

.. versionadded:: 3.42
%End

QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
Expand Down
112 changes: 112 additions & 0 deletions src/core/mesh/qgsmeshlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1660,9 +1660,121 @@ QgsMapLayerRenderer *QgsMeshLayer::createMapRenderer( QgsRenderContext &renderer
if ( !mRendererCache )
mRendererCache.reset( new QgsMeshLayerRendererCache() );

if ( !rendererContext.testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) )
{
QgsMeshDatasetIndex activeDatasetIndex = activeScalarDatasetIndex( rendererContext );
QgsMeshRendererScalarSettings scalarRendererSettings = mRendererSettings.scalarSettings( activeDatasetIndex.group() );

if ( scalarRendererSettings.minMaxValueType() == QgsMeshRendererScalarSettings::MinMaxValueType::InteractiveFromCanvas )
{
double previousMin = scalarRendererSettings.classificationMinimum();
double previousMax = scalarRendererSettings.classificationMaximum();
double min, max;

bool found = minimumMaximumActiveScalarDataset( rendererContext.extent(), activeDatasetIndex, min, max );

if ( found )
{
if ( previousMin != min || previousMax != max )
{
scalarRendererSettings.setClassificationMinimumMaximum( min, max );
mRendererSettings.setScalarSettings( activeDatasetIndex.group(), scalarRendererSettings );
emit legendChanged();
}
}
}
}

return new QgsMeshLayerRenderer( this, rendererContext );
}

QgsMeshDatasetIndex QgsMeshLayer::activeScalarDatasetIndex( QgsRenderContext &rendererContext )
{
if ( rendererContext.isTemporal() )
return activeScalarDatasetAtTime( rendererContext.temporalRange(), mRendererSettings.activeScalarDatasetGroup() );
else
return staticScalarDatasetIndex( mRendererSettings.activeScalarDatasetGroup() );
}

bool QgsMeshLayer::minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max )
{

if ( extent.isNull() || !this->extent().intersects( extent ) )
return false;

QgsTriangularMesh *tMesh = triangularMesh();

QVector<double> scalarDatasetValues;
const QgsMeshDatasetGroupMetadata metadata = datasetGroupMetadata( datasetIndex.group() );

if ( !metadata.isScalar() )
{
return false;
}

QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );

if ( !datasetIndex.isValid() )
{
return false;
}

// populate scalar values
const int count = QgsMeshLayerUtils::datasetValuesCount( mNativeMesh.get(), scalarDataType );
const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
this,
datasetIndex,
0,
count );

if ( vals.isValid() )
{
// vals could be scalar or vectors, for contour rendering we want always magnitude
scalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
}
else
{
scalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
}

QList<int> intersectedFacesIndices = tMesh->faceIndexesForRectangle( extent );

if ( intersectedFacesIndices.isEmpty() )
{
return false;
}

min = std::numeric_limits<double>::max();
max = -std::numeric_limits<double>::max();

double value;

for ( int intersectedFaceIndex : intersectedFacesIndices )
{
QgsMeshFace face = tMesh->triangles().at( intersectedFaceIndex );

if ( metadata.dataType() == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces || metadata.dataType() == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
{
value = scalarDatasetValues.at( tMesh->trianglesToNativeFaces().at( intersectedFaceIndex ) );
min = std::min( min, value );
max = std::max( max, value );
}
else if ( metadata.dataType() == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
{
QgsMeshVertex vertex;

for ( int vertexIndex : face )
{
value = scalarDatasetValues.at( vertexIndex );
min = std::min( min, value );
max = std::max( max, value );
}
}
}

return true;
}

QgsAbstractProfileGenerator *QgsMeshLayer::createProfileGenerator( const QgsProfileRequest &request )
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Expand Down
12 changes: 12 additions & 0 deletions src/core/mesh/qgsmeshlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,16 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer, public QgsAbstractProfileSo
*/
void setLabeling( QgsAbstractMeshLayerLabeling *labeling SIP_TRANSFER );

/**
* Extracts minimum and maximum value for active scalar dataset on mesh faces.
* \param extent extent in which intersecting faces are searched for
* \param datasetIndex index for which dataset the values should be extracted
* \param min minimal value
* \param max maximal value
* \return TRUE if values were extracted
* \since QGIS 3.42
*/
bool minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min SIP_OUT, double &max SIP_OUT );

public slots:

Expand Down Expand Up @@ -974,6 +984,8 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer, public QgsAbstractProfileSo

private: // Private methods

QgsMeshDatasetIndex activeScalarDatasetIndex( QgsRenderContext &rendererContext );

/**
* Returns TRUE if the provider is in read-only mode
*/
Expand Down
60 changes: 60 additions & 0 deletions src/core/mesh/qgsmeshrenderersettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "qgsmeshrenderersettings.h"
#include "qgscolorutils.h"
#include "qgsunittypes.h"
#include "qgscolorramp.h"

bool QgsMeshRendererMeshSettings::isEnabled() const
{
Expand Down Expand Up @@ -96,6 +97,7 @@ void QgsMeshRendererScalarSettings::setClassificationMinimumMaximum( double mini
{
mClassificationMinimum = minimum;
mClassificationMaximum = maximum;
updateShader();
}

double QgsMeshRendererScalarSettings::opacity() const { return mOpacity; }
Expand Down Expand Up @@ -130,6 +132,25 @@ QDomElement QgsMeshRendererScalarSettings::writeXml( QDomDocument &doc, const Qg
break;
}
elem.setAttribute( QStringLiteral( "interpolation-method" ), methodTxt );

QString minMaxTypeText;
switch ( mMinMaxValueType )
{
case QgsMeshRendererScalarSettings::MinMaxValueType::UserDefined:
minMaxTypeText = QStringLiteral( "user-defined" );
break;
case QgsMeshRendererScalarSettings::MinMaxValueType::FixedCanvas:
minMaxTypeText = QStringLiteral( "fixed-canvas" );
break;
case QgsMeshRendererScalarSettings::MinMaxValueType::InteractiveFromCanvas:
minMaxTypeText = QStringLiteral( "interactive-canvas" );
break;
case QgsMeshRendererScalarSettings::MinMaxValueType::WholeMesh:
minMaxTypeText = QStringLiteral( "whole-mesh" );
break;
}
elem.setAttribute( QStringLiteral( "min-max-value-type" ), minMaxTypeText );

const QDomElement elemShader = mColorRampShader.writeXml( doc, context );
elem.appendChild( elemShader );

Expand All @@ -156,6 +177,29 @@ void QgsMeshRendererScalarSettings::readXml( const QDomElement &elem, const QgsR
{
mDataResamplingMethod = DataResamplingMethod::NoResampling;
}

const QString minMaxTypeText = elem.attribute( QStringLiteral( "min-max-value-type" ) );
if ( QStringLiteral( "interactive-canvas" ) == minMaxTypeText )
{
mMinMaxValueType = QgsMeshRendererScalarSettings::MinMaxValueType::InteractiveFromCanvas;
}
else if ( QStringLiteral( "fixed-canvas" ) == minMaxTypeText )
{
mMinMaxValueType = QgsMeshRendererScalarSettings::MinMaxValueType::FixedCanvas;
}
else if ( QStringLiteral( "user-defined" ) == minMaxTypeText )
{
mMinMaxValueType = QgsMeshRendererScalarSettings::MinMaxValueType::UserDefined;
}
else if ( QStringLiteral( "whole-mesh" ) == minMaxTypeText )
{
mMinMaxValueType = QgsMeshRendererScalarSettings::MinMaxValueType::WholeMesh;
}
else
{
mMinMaxValueType = MinMaxValueType::WholeMesh;
}

const QDomElement elemShader = elem.firstChildElement( QStringLiteral( "colorrampshader" ) );
mColorRampShader.readXml( elemShader, context );

Expand Down Expand Up @@ -186,6 +230,22 @@ void QgsMeshRendererScalarSettings::setEdgeStrokeWidthUnit( Qgis::RenderUnit edg
mEdgeStrokeWidthUnit = edgeStrokeWidthUnit;
}

void QgsMeshRendererScalarSettings::updateShader()
{

mColorRampShader.setMinimumValue( mClassificationMinimum );
mColorRampShader.setMaximumValue( mClassificationMaximum );

if ( !mColorRampShader.isEmpty() )
mColorRampShader.classifyColorRamp( mColorRampShader.sourceColorRamp()->count(), 1, QgsRectangle(), nullptr );
}

void QgsMeshRendererScalarSettings::setMinMaxValueType( QgsMeshRendererScalarSettings::MinMaxValueType minMaxValueType )
{
mMinMaxValueType = minMaxValueType;
updateShader();
}

// ---------------------------------------------------------------------

double QgsMeshRendererVectorSettings::lineWidth() const
Expand Down
Loading
Loading