Skip to content

Commit

Permalink
Mesh Render Extent Settings
Browse files Browse the repository at this point in the history
This brings to renderer for Mesh Contours option to set renderer Min Max based on extent (specific canvas, changing canvas) in the same way as renderers for Raster Layer.
  • Loading branch information
JanCaha authored Dec 17, 2024
1 parent c831a10 commit 2adaec6
Show file tree
Hide file tree
Showing 32 changed files with 924 additions and 4 deletions.
28 changes: 28 additions & 0 deletions python/PyQt6/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -11041,6 +11041,34 @@
"""
# --
Qgis.MouseHandlesAction.baseClass = Qgis
# monkey patching scoped based enum
Qgis.MeshRangeLimit.NotSet.__doc__ = "User defined"
Qgis.MeshRangeLimit.MinimumMaximum.__doc__ = "Real min-max values"
Qgis.MeshRangeLimit.__doc__ = """Describes the limits used to compute mesh ranges (min/max values).

.. versionadded:: 3.42

* ``NotSet``: User defined
* ``MinimumMaximum``: Real min-max values

"""
# --
Qgis.MeshRangeLimit.baseClass = Qgis
# monkey patching scoped based enum
Qgis.MeshRangeExtent.WholeMesh.__doc__ = "Whole mesh is used to compute statistics"
Qgis.MeshRangeExtent.FixedCanvas.__doc__ = "Current extent of the canvas (at the time of computation) is used to compute statistics"
Qgis.MeshRangeExtent.UpdatedCanvas.__doc__ = "Constantly updated extent of the canvas is used to compute statistics"
Qgis.MeshRangeExtent.__doc__ = """Describes the extent used to compute mesh ranges (min/max values).

.. versionadded:: 3.42

* ``WholeMesh``: Whole mesh is used to compute statistics
* ``FixedCanvas``: Current extent of the canvas (at the time of computation) is used to compute statistics
* ``UpdatedCanvas``: Constantly updated extent of the canvas is used to compute statistics

"""
# --
Qgis.MeshRangeExtent.baseClass = Qgis
try:
Qgis.__attribute_docs__ = {'QGIS_DEV_VERSION': 'The development version', 'DEFAULT_SEARCH_RADIUS_MM': 'Identify search radius in mm', 'DEFAULT_MAPTOPIXEL_THRESHOLD': 'Default threshold between map coordinates and device coordinates for map2pixel simplification', 'DEFAULT_HIGHLIGHT_COLOR': 'Default highlight color. The transparency is expected to only be applied to polygon\nfill. Lines and outlines are rendered opaque.', 'DEFAULT_HIGHLIGHT_BUFFER_MM': 'Default highlight buffer in mm.', 'DEFAULT_HIGHLIGHT_MIN_WIDTH_MM': 'Default highlight line/stroke minimum width in mm.', 'SCALE_PRECISION': 'Fudge factor used to compare two scales. The code is often going from scale to scale\ndenominator. So it looses precision and, when a limit is inclusive, can lead to errors.\nTo avoid that, use this factor instead of using <= or >=.\n\n.. deprecated:: 3.40\n\n No longer used by QGIS and will be removed in QGIS 4.0.', 'DEFAULT_Z_COORDINATE': 'Default Z coordinate value.\nThis value have to be assigned to the Z coordinate for the vertex.', 'DEFAULT_M_COORDINATE': 'Default M coordinate value.\nThis value have to be assigned to the M coordinate for the vertex.\n\n.. versionadded:: 3.20', 'UI_SCALE_FACTOR': 'UI scaling factor. This should be applied to all widget sizes obtained from font metrics,\nto account for differences in the default font sizes across different platforms.', 'DEFAULT_SNAP_TOLERANCE': 'Default snapping distance tolerance.', 'DEFAULT_SNAP_UNITS': 'Default snapping distance units.'}
Qgis.version = staticmethod(Qgis.version)
Expand Down
21 changes: 21 additions & 0 deletions python/PyQt6/core/auto_generated/mesh/qgsmeshlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,27 @@ Access to labeling configuration. May be ``None`` if labeling is not used.
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

QgsMeshDatasetIndex activeScalarDatasetIndex( QgsRenderContext &rendererContext );
%Docstring
Returns current active scalar dataset index for current renderer context.

.. versionadded:: 3.42
%End

bool datasetsPathUnique( const QString &path );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,34 @@ 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

void setLimits( Qgis::MeshRangeLimit limits );
%Docstring
Sets the range limits type for minimum maximum calculation

.. versionadded:: 3.42
%End

Qgis::MeshRangeLimit limits() const;
%Docstring
Returns the range limits type for minimum maximum calculation

.. versionadded:: 3.42
%End

void setExtent( Qgis::MeshRangeExtent extent );
%Docstring
Sets the mesh extent for minimum maximum calculation

.. versionadded:: 3.42
%End

Qgis::MeshRangeExtent extent() const;
%Docstring
Returns the mesh extent for minimum maximum calculation

.. versionadded:: 3.42
%End

QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
Expand Down
13 changes: 13 additions & 0 deletions python/PyQt6/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -3226,6 +3226,19 @@ The development version
NoAction
};

enum class MeshRangeLimit /BaseType=IntEnum/
{
NotSet,
MinimumMaximum,
};

enum class MeshRangeExtent /BaseType=IntEnum/
{
WholeMesh,
FixedCanvas,
UpdatedCanvas,
};

static const double DEFAULT_SEARCH_RADIUS_MM;

static const float DEFAULT_MAPTOPIXEL_THRESHOLD;
Expand Down
28 changes: 28 additions & 0 deletions python/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10951,6 +10951,34 @@
"""
# --
Qgis.MouseHandlesAction.baseClass = Qgis
# monkey patching scoped based enum
Qgis.MeshRangeLimit.NotSet.__doc__ = "User defined"
Qgis.MeshRangeLimit.MinimumMaximum.__doc__ = "Real min-max values"
Qgis.MeshRangeLimit.__doc__ = """Describes the limits used to compute mesh ranges (min/max values).

.. versionadded:: 3.42

* ``NotSet``: User defined
* ``MinimumMaximum``: Real min-max values

"""
# --
Qgis.MeshRangeLimit.baseClass = Qgis
# monkey patching scoped based enum
Qgis.MeshRangeExtent.WholeMesh.__doc__ = "Whole mesh is used to compute statistics"
Qgis.MeshRangeExtent.FixedCanvas.__doc__ = "Current extent of the canvas (at the time of computation) is used to compute statistics"
Qgis.MeshRangeExtent.UpdatedCanvas.__doc__ = "Constantly updated extent of the canvas is used to compute statistics"
Qgis.MeshRangeExtent.__doc__ = """Describes the extent used to compute mesh ranges (min/max values).

.. versionadded:: 3.42

* ``WholeMesh``: Whole mesh is used to compute statistics
* ``FixedCanvas``: Current extent of the canvas (at the time of computation) is used to compute statistics
* ``UpdatedCanvas``: Constantly updated extent of the canvas is used to compute statistics

"""
# --
Qgis.MeshRangeExtent.baseClass = Qgis
from enum import Enum


Expand Down
21 changes: 21 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,27 @@ Access to labeling configuration. May be ``None`` if labeling is not used.
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

QgsMeshDatasetIndex activeScalarDatasetIndex( QgsRenderContext &rendererContext );
%Docstring
Returns current active scalar dataset index for current renderer context.

.. versionadded:: 3.42
%End

bool datasetsPathUnique( const QString &path );
Expand Down
28 changes: 28 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,34 @@ 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

void setLimits( Qgis::MeshRangeLimit limits );
%Docstring
Sets the range limits type for minimum maximum calculation

.. versionadded:: 3.42
%End

Qgis::MeshRangeLimit limits() const;
%Docstring
Returns the range limits type for minimum maximum calculation

.. versionadded:: 3.42
%End

void setExtent( Qgis::MeshRangeExtent extent );
%Docstring
Sets the mesh extent for minimum maximum calculation

.. versionadded:: 3.42
%End

Qgis::MeshRangeExtent extent() const;
%Docstring
Returns the mesh extent for minimum maximum calculation

.. versionadded:: 3.42
%End

QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
Expand Down
13 changes: 13 additions & 0 deletions python/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -3226,6 +3226,19 @@ The development version
NoAction
};

enum class MeshRangeLimit
{
NotSet,
MinimumMaximum,
};

enum class MeshRangeExtent
{
WholeMesh,
FixedCanvas,
UpdatedCanvas,
};

static const double DEFAULT_SEARCH_RADIUS_MM;

static const float DEFAULT_MAPTOPIXEL_THRESHOLD;
Expand Down
14 changes: 14 additions & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17180,6 +17180,20 @@ void QgisApp::handleRenderedLayerStatistics() const
rasterLayer->emitStyleChanged();
emit rasterLayer->rendererChanged();
}

QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( QgsProject::instance()->mapLayer( layerStatistics->layerId() ) );
if ( meshLayer )
{
QgsMeshRendererSettings rendererSettings = meshLayer->rendererSettings();
QgsMeshRendererScalarSettings scalarRendererSettings = rendererSettings.scalarSettings( rendererSettings.activeScalarDatasetGroup() );
scalarRendererSettings.setClassificationMinimumMaximum( layerStatistics->minimum( 0 ), layerStatistics->maximum( 0 ) );
rendererSettings.setScalarSettings( rendererSettings.activeScalarDatasetGroup(), scalarRendererSettings );
meshLayer->setRendererSettings( rendererSettings );

meshLayer->emitStyleChanged();
emit meshLayer->rendererChanged();
emit meshLayer->legendChanged();
}
}
}
}
89 changes: 89 additions & 0 deletions src/core/mesh/qgsmeshlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,95 @@ QgsMapLayerRenderer *QgsMeshLayer::createMapRenderer( QgsRenderContext &renderer
return new QgsMeshLayerRenderer( this, rendererContext );
}

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

return QgsMeshDatasetIndex();
}

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
18 changes: 18 additions & 0 deletions src/core/mesh/qgsmeshlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,24 @@ 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 );

/**
* Returns current active scalar dataset index for current renderer context.
*
* \since QGIS 3.42
*/
QgsMeshDatasetIndex activeScalarDatasetIndex( QgsRenderContext &rendererContext );

/**
* Checks whether that datasets path is already added to this mesh layer. Return TRUE if the
* dataset path is not already added.
Expand Down
Loading

0 comments on commit 2adaec6

Please sign in to comment.